1 /*
   2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * @LastModified: Oct 2017
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.xerces.internal.util;
  23 
  24 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  25 import java.util.Collections;
  26 import java.util.Enumeration;
  27 import java.util.HashMap;
  28 import java.util.Map;
  29 
  30 /**
  31  * This class provides an implementation for Augmentations interface.
  32  * Augmentations interface defines a map of additional data that could
  33  * be passed along the document pipeline. The information can contain extra
  34  * arguments or infoset augmentations, for example PSVI. This additional
  35  * information is identified by a String key.
  36  * <p>
  37  *
  38  * @author Elena Litani, IBM
  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      */
  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      */
  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      */
  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      */
  91     public Enumeration<Object> keys (){
  92         return fAugmentationsContainer.keys();
  93     }
  94 
  95     /**
  96      * Remove all objects from the Augmentations structure.
  97      */
  98     public void removeAllItems() {
  99         fAugmentationsContainer.clear();
 100     }
 101 
 102     public String toString() {
 103         return fAugmentationsContainer.toString();
 104     }
 105 
 106     abstract class AugmentationsItemsContainer {
 107         abstract public Object putItem(Object key, Object item);
 108         abstract public Object getItem(Object key);
 109         abstract public Object removeItem(Object key);
 110         abstract public Enumeration<Object> keys();
 111         abstract public void clear();
 112         abstract public boolean isFull();
 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 
 121         public Enumeration<Object> keys() {
 122             return new SmallContainerKeyEnumeration();
 123         }
 124 
 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 
 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 
 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 
 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 
 183         public boolean isFull() {
 184             return (fNumEntries == SIZE_LIMIT);
 185         }
 186 
 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 
 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 
 220             SmallContainerKeyEnumeration() {
 221                 for (int i = 0; i < fNumEntries; i++) {
 222                     enumArray[i] = fAugmentations[i*2];
 223                 }
 224             }
 225 
 226             public boolean hasMoreElements() {
 227                 return next < enumArray.length;
 228             }
 229 
 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 
 247         public Object getItem(Object key) {
 248             return fAugmentations.get(key);
 249         }
 250 
 251         public Object putItem(Object key, Object item) {
 252             return fAugmentations.put(key, item);
 253         }
 254 
 255         public Object removeItem(Object key) {
 256             return fAugmentations.remove(key);
 257         }
 258 
 259         public Enumeration<Object> keys() {
 260             return Collections.enumeration(fAugmentations.keySet());
 261         }
 262 
 263         public void clear() {
 264             fAugmentations.clear();
 265         }
 266 
 267         public boolean isFull() {
 268             return false;
 269         }
 270 
 271         public AugmentationsItemsContainer expand() {
 272             return this;
 273         }
 274 
 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 }