1 /*
2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
3  */
4 /*
5  * Licensed to the Apache Software Foundation (ASF) under one or more
6  * contributor license agreements.  See the NOTICE file distributed with
7  * this work for additional information regarding copyright ownership.
8  * The ASF licenses this file to You under the Apache License, Version 2.0
9  * (the "License"); you may not use this file except in compliance with
10  * the License.  You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 package com.sun.org.apache.xerces.internal.util;
22 
23 import com.sun.org.apache.xerces.internal.xni.Augmentations;
24 import java.util.Collections;
25 import java.util.Enumeration;
26 import java.util.HashMap;
27 import java.util.Map;
28 
29 /**
30  * This class provides an implementation for Augmentations interface.
31  * Augmentations interface defines a map of additional data that could
32  * be passed along the document pipeline. The information can contain extra
33  * arguments or infoset augmentations, for example PSVI. This additional
34  * information is identified by a String key.
35  * <p>
36  *
37  * @author Elena Litani, IBM
38  * @LastModified: Oct 2017
39  */
40 public class AugmentationsImpl implements Augmentations{
41 
42     private AugmentationsItemsContainer fAugmentationsContainer =
43                                         new SmallContainer();
44 
45     /**
46      * Add additional information identified by a key to the Augmentations structure.
47      *
48      * @param key    Identifier, can't be <code>null</code>
49      * @param item   Additional information
50      *
51      * @return the previous value of the specified key in the Augmentations strucutre,
52      *         or <code>null</code> if it did not have one.
53      */
putItem(String key, Object item)54     public Object putItem (String key, Object item){
55         Object oldValue = fAugmentationsContainer.putItem(key, item);
56 
57         if (oldValue == null && fAugmentationsContainer.isFull()) {
58             fAugmentationsContainer = fAugmentationsContainer.expand();
59         }
60 
61         return oldValue;
62     }
63 
64 
65     /**
66      * Get information identified by a key from the Augmentations structure
67      *
68      * @param key    Identifier, can't be <code>null</code>
69      *
70      * @return the value to which the key is mapped in the Augmentations structure;
71      *         <code>null</code> if the key is not mapped to any value.
72      */
getItem(String key)73     public Object getItem(String key){
74         return fAugmentationsContainer.getItem(key);
75     }
76 
77 
78     /**
79      * Remove additional info from the Augmentations structure
80      *
81      * @param key    Identifier, can't be <code>null</code>
82      */
removeItem(String key)83     public Object removeItem (String key){
84         return fAugmentationsContainer.removeItem(key);
85     }
86 
87     /**
88      * Returns an enumeration of the keys in the Augmentations structure
89      *
90      */
keys()91     public Enumeration<Object> keys (){
92         return fAugmentationsContainer.keys();
93     }
94 
95     /**
96      * Remove all objects from the Augmentations structure.
97      */
removeAllItems()98     public void removeAllItems() {
99         fAugmentationsContainer.clear();
100     }
101 
toString()102     public String toString() {
103         return fAugmentationsContainer.toString();
104     }
105 
106     abstract class AugmentationsItemsContainer {
putItem(Object key, Object item)107         abstract public Object putItem(Object key, Object item);
getItem(Object key)108         abstract public Object getItem(Object key);
removeItem(Object key)109         abstract public Object removeItem(Object key);
keys()110         abstract public Enumeration<Object> keys();
clear()111         abstract public void clear();
isFull()112         abstract public boolean isFull();
expand()113         abstract public AugmentationsItemsContainer expand();
114     }
115 
116     class SmallContainer extends AugmentationsItemsContainer {
117         final static int SIZE_LIMIT = 10;
118         final Object[] fAugmentations = new Object[SIZE_LIMIT*2];
119         int fNumEntries = 0;
120 
keys()121         public Enumeration<Object> keys() {
122             return new SmallContainerKeyEnumeration();
123         }
124 
getItem(Object key)125         public Object getItem(Object key) {
126             for (int i = 0; i < fNumEntries*2; i = i + 2) {
127                 if (fAugmentations[i].equals(key)) {
128                     return fAugmentations[i+1];
129                 }
130             }
131 
132             return null;
133         }
134 
putItem(Object key, Object item)135         public Object putItem(Object key, Object item) {
136             for (int i = 0; i < fNumEntries*2; i = i + 2) {
137                 if (fAugmentations[i].equals(key)) {
138                     Object oldValue = fAugmentations[i+1];
139                     fAugmentations[i+1] = item;
140 
141                     return oldValue;
142                 }
143             }
144 
145             fAugmentations[fNumEntries*2] = key;
146             fAugmentations[fNumEntries*2+1] = item;
147             fNumEntries++;
148 
149             return null;
150         }
151 
152 
removeItem(Object key)153         public Object removeItem(Object key) {
154             for (int i = 0; i < fNumEntries*2; i = i + 2) {
155                 if (fAugmentations[i].equals(key)) {
156                     Object oldValue = fAugmentations[i+1];
157 
158                     for (int j = i; j < fNumEntries*2 - 2; j = j + 2) {
159                         fAugmentations[j] = fAugmentations[j+2];
160                         fAugmentations[j+1] = fAugmentations[j+3];
161                     }
162 
163                     fAugmentations[fNumEntries*2-2] = null;
164                     fAugmentations[fNumEntries*2-1] = null;
165                     fNumEntries--;
166 
167                     return oldValue;
168                 }
169             }
170 
171             return null;
172         }
173 
clear()174         public void clear() {
175             for (int i = 0; i < fNumEntries*2; i = i + 2) {
176                 fAugmentations[i] = null;
177                 fAugmentations[i+1] = null;
178             }
179 
180             fNumEntries = 0;
181         }
182 
isFull()183         public boolean isFull() {
184             return (fNumEntries == SIZE_LIMIT);
185         }
186 
expand()187         public AugmentationsItemsContainer expand() {
188             LargeContainer expandedContainer = new LargeContainer();
189 
190             for (int i = 0; i < fNumEntries*2; i = i + 2) {
191                 expandedContainer.putItem(fAugmentations[i],
192                                           fAugmentations[i+1]);
193             }
194 
195             return expandedContainer;
196         }
197 
toString()198         public String toString() {
199             StringBuilder buff = new StringBuilder();
200             buff.append("SmallContainer - fNumEntries == ").append(fNumEntries);
201 
202             for (int i = 0; i < SIZE_LIMIT*2; i=i+2) {
203                 buff.append("\nfAugmentations[")
204                     .append(i)
205                     .append("] == ")
206                     .append(fAugmentations[i])
207                     .append("; fAugmentations[")
208                     .append(i+1)
209                     .append("] == ")
210                     .append(fAugmentations[i+1]);
211             }
212 
213             return buff.toString();
214         }
215 
216         class SmallContainerKeyEnumeration implements Enumeration<Object> {
217             Object [] enumArray = new Object[fNumEntries];
218             int next = 0;
219 
SmallContainerKeyEnumeration()220             SmallContainerKeyEnumeration() {
221                 for (int i = 0; i < fNumEntries; i++) {
222                     enumArray[i] = fAugmentations[i*2];
223                 }
224             }
225 
hasMoreElements()226             public boolean hasMoreElements() {
227                 return next < enumArray.length;
228             }
229 
nextElement()230             public Object nextElement() {
231                 if (next >= enumArray.length) {
232                     throw new java.util.NoSuchElementException();
233                 }
234 
235                 Object nextVal = enumArray[next];
236                 enumArray[next] = null;
237                 next++;
238 
239                 return nextVal;
240             }
241         }
242     }
243 
244     class LargeContainer extends AugmentationsItemsContainer {
245         final Map<Object, Object> fAugmentations = new HashMap<>();
246 
getItem(Object key)247         public Object getItem(Object key) {
248             return fAugmentations.get(key);
249         }
250 
putItem(Object key, Object item)251         public Object putItem(Object key, Object item) {
252             return fAugmentations.put(key, item);
253         }
254 
removeItem(Object key)255         public Object removeItem(Object key) {
256             return fAugmentations.remove(key);
257         }
258 
keys()259         public Enumeration<Object> keys() {
260             return Collections.enumeration(fAugmentations.keySet());
261         }
262 
clear()263         public void clear() {
264             fAugmentations.clear();
265         }
266 
isFull()267         public boolean isFull() {
268             return false;
269         }
270 
expand()271         public AugmentationsItemsContainer expand() {
272             return this;
273         }
274 
toString()275         public String toString() {
276             StringBuilder buff = new StringBuilder();
277             buff.append("LargeContainer");
278             for(Object key : fAugmentations.keySet()) {
279                 buff.append("\nkey == ");
280                 buff.append(key);
281                 buff.append("; value == ");
282                 buff.append(fAugmentations.get(key));
283             }
284             return buff.toString();
285         }
286     }
287 }
288