From 8a060091156c631c76476582458a32daa50a5bb2 Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Wed, 29 Aug 2007 06:10:13 +0000
Subject: [PATCH] Add an API that can be used to allow compressed schema tokens to be stored in alternate repositories.  The current implementation is still the default server-wide mechanism using the config/schematokens.dat file, but it will be possible to use this API to create alternate implementations (e.g., one for the JE backend that stores the tokens in the database).

---
 opends/src/server/org/opends/server/core/DefaultCompressedSchema.java |  324 ++++++++++++++++++++---------------------------------
 1 files changed, 124 insertions(+), 200 deletions(-)

diff --git a/opends/src/server/org/opends/server/types/CompressedSchema.java b/opends/src/server/org/opends/server/core/DefaultCompressedSchema.java
similarity index 63%
rename from opends/src/server/org/opends/server/types/CompressedSchema.java
rename to opends/src/server/org/opends/server/core/DefaultCompressedSchema.java
index d7548b9..c045ed3 100644
--- a/opends/src/server/org/opends/server/types/CompressedSchema.java
+++ b/opends/src/server/org/opends/server/core/DefaultCompressedSchema.java
@@ -24,8 +24,7 @@
  *
  *      Portions Copyright 2007 Sun Microsystems, Inc.
  */
-package org.opends.server.types;
-import org.opends.messages.Message;
+package org.opends.server.core;
 
 
 
@@ -39,7 +38,8 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import org.opends.server.core.DirectoryServer;
+import org.opends.messages.Message;
+import org.opends.server.api.CompressedSchema;
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.protocols.asn1.ASN1Element;
 import org.opends.server.protocols.asn1.ASN1Integer;
@@ -47,6 +47,13 @@
 import org.opends.server.protocols.asn1.ASN1Reader;
 import org.opends.server.protocols.asn1.ASN1Sequence;
 import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.AttributeValue;
+import org.opends.server.types.ByteArray;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ObjectClass;
 
 import static org.opends.server.config.ConfigConstants.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -56,15 +63,12 @@
 
 
 /**
- * This class provides a utility for interacting with compressed
- * representations of schema elements.
+ * This class provides a default implementation of a compressed schema manager
+ * that will store the schema definitions in a binary file
+ * (config/schematokens.dat).
  */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.PRIVATE,
-     mayInstantiate=false,
-     mayExtend=false,
-     mayInvoke=false)
-public final class CompressedSchema
+public final class DefaultCompressedSchema
+       extends CompressedSchema
 {
   /**
    * The tracer object for the debug logger.
@@ -73,13 +77,6 @@
 
 
 
-  /**
-   * The singleton instance that will be used to perform the mapping.
-   */
-  private static CompressedSchema instance = new CompressedSchema();
-
-
-
   // The counter used for attribute descriptions.
   private AtomicInteger adCounter;
 
@@ -90,40 +87,33 @@
   private ConcurrentHashMap<ByteArray,AttributeType> atDecodeMap;
 
   // The map between encoded representations and attribute options.
-  private ConcurrentHashMap<ByteArray,
-               LinkedHashSet<String>> aoDecodeMap;
+  private ConcurrentHashMap<ByteArray,LinkedHashSet<String>> aoDecodeMap;
 
   // The map between encoded representations and object class sets.
-  private ConcurrentHashMap<ByteArray,
-               Map<ObjectClass,String>> ocDecodeMap;
+  private ConcurrentHashMap<ByteArray,Map<ObjectClass,String>> ocDecodeMap;
 
   // The map between attribute descriptions and their encoded
   // representations.
   private ConcurrentHashMap<AttributeType,
-               ConcurrentHashMap<LinkedHashSet<String>,ByteArray>>
-                    adEncodeMap;
+               ConcurrentHashMap<LinkedHashSet<String>,ByteArray>> adEncodeMap;
 
   // The map between object class sets and encoded representations.
-  private ConcurrentHashMap<Map<ObjectClass,String>,
-               ByteArray> ocEncodeMap;
+  private ConcurrentHashMap<Map<ObjectClass,String>,ByteArray> ocEncodeMap;
 
 
 
   /**
    * Creates a new instance of this compressed schema manager.
    */
-  private CompressedSchema()
+  public DefaultCompressedSchema()
   {
     atDecodeMap = new ConcurrentHashMap<ByteArray,AttributeType>();
-    aoDecodeMap = new ConcurrentHashMap<ByteArray,
-                           LinkedHashSet<String>>();
-    ocDecodeMap = new ConcurrentHashMap<ByteArray,
-                           Map<ObjectClass,String>>();
-    adEncodeMap = new ConcurrentHashMap<AttributeType,
-                           ConcurrentHashMap<LinkedHashSet<String>,
-                                ByteArray>>();
-    ocEncodeMap = new ConcurrentHashMap<Map<ObjectClass,String>,
-                           ByteArray>();
+    aoDecodeMap = new ConcurrentHashMap<ByteArray,LinkedHashSet<String>>();
+    ocDecodeMap = new ConcurrentHashMap<ByteArray,Map<ObjectClass,String>>();
+    adEncodeMap =
+         new ConcurrentHashMap<AttributeType,
+                  ConcurrentHashMap<LinkedHashSet<String>,ByteArray>>();
+    ocEncodeMap = new ConcurrentHashMap<Map<ObjectClass,String>,ByteArray>();
 
     adCounter = new AtomicInteger(1);
     ocCounter = new AtomicInteger(1);
@@ -142,10 +132,9 @@
 
     try
     {
-      // Determine the location of the compressed schema data file
-      // It should be in the config directory with a name of
-      // "schematokens.dat".  If that file doesn't exist, then don't
-      // do anything.
+      // Determine the location of the compressed schema data file.  It should
+      // be in the config directory with a name of "schematokens.dat".  If that
+      // file doesn't exist, then don't do anything.
       String path = DirectoryServer.getServerRoot() + File.separator +
                     CONFIG_DIR_NAME + File.separator +
                     COMPRESSED_SCHEMA_FILE_NAME;
@@ -157,17 +146,14 @@
       reader = new ASN1Reader(inputStream);
 
 
-      // The first element in the file should be a sequence of object
-      // class sets.  Each object class set will itself be a sequence
-      // of octet strings, where the first one is the token and the
-      // remaining elements are the names of the associated object
-      // classes.
-      ASN1Sequence ocSequence =
-           reader.readElement().decodeAsSequence();
+      // The first element in the file should be a sequence of object class
+      // sets.  Each object class set will itself be a sequence of octet
+      // strings, where the first one is the token and the remaining elements
+      // are the names of the associated object classes.
+      ASN1Sequence ocSequence = reader.readElement().decodeAsSequence();
       for (ASN1Element element : ocSequence.elements())
       {
-        ArrayList<ASN1Element> elements =
-             element.decodeAsSequence().elements();
+        ArrayList<ASN1Element> elements = element.decodeAsSequence().elements();
         ASN1OctetString os = elements.get(0).decodeAsOctetString();
         ByteArray token = new ByteArray(os.value());
 
@@ -178,8 +164,7 @@
           os = elements.get(i).decodeAsOctetString();
           String ocName = os.stringValue();
           String lowerName = toLowerCase(ocName);
-          ObjectClass oc =
-               DirectoryServer.getObjectClass(lowerName, true);
+          ObjectClass oc = DirectoryServer.getObjectClass(lowerName, true);
           ocMap.put(oc, ocName);
         }
 
@@ -188,24 +173,21 @@
       }
 
 
-      // The second element in the file should be an integer element
-      // that holds the value to use to initialize the object class
-      // counter.
+      // The second element in the file should be an integer element that holds
+      // the value to use to initialize the object class counter.
       ASN1Element counterElement = reader.readElement();
       ocCounter.set(counterElement.decodeAsInteger().intValue());
 
 
-      // The third element in the file should be a sequence of
-      // attribute description components.  Each attribute description
-      // component will itself be a sequence of octet strings, where
-      // the first one is the token, the second is the attribute name,
-      // and all remaining elements are the attribute options.
-      ASN1Sequence adSequence =
-           reader.readElement().decodeAsSequence();
+      // The third element in the file should be a sequence of attribute
+      // description components.  Each attribute description component will
+      // itself be a sequence of octet strings, where the first one is the
+      // token, the second is the attribute name, and all remaining elements are
+      // the attribute options.
+      ASN1Sequence adSequence = reader.readElement().decodeAsSequence();
       for (ASN1Element element : adSequence.elements())
       {
-        ArrayList<ASN1Element> elements =
-             element.decodeAsSequence().elements();
+        ArrayList<ASN1Element> elements = element.decodeAsSequence().elements();
         ASN1OctetString os = elements. get(0).decodeAsOctetString();
         ByteArray token = new ByteArray(os.value());
 
@@ -230,8 +212,7 @@
              adEncodeMap.get(attrType);
         if (map == null)
         {
-          map = new ConcurrentHashMap<LinkedHashSet<String>,
-                         ByteArray>(1);
+          map = new ConcurrentHashMap<LinkedHashSet<String>,ByteArray>(1);
           map.put(options, token);
           adEncodeMap.put(attrType, map);
         }
@@ -242,9 +223,8 @@
       }
 
 
-      // The fourth element in the file should be an integer element
-      // that holds the value to use to initialize the attribute
-      // description counter.
+      // The fourth element in the file should be an integer element that holds
+      // the value to use to initialize the attribute description counter.
       counterElement = reader.readElement();
       adCounter.set(counterElement.decodeAsInteger().intValue());
     }
@@ -282,8 +262,8 @@
   /**
    * Writes the compressed schema information to disk.
    *
-   * @throws  DirectoryException  If a problem occurs while writing
-   *                              the updated information.
+   * @throws  DirectoryException  If a problem occurs while writing the updated
+   *                              information.
    */
   private void save()
           throws DirectoryException
@@ -291,9 +271,9 @@
     ASN1Writer writer = null;
     try
     {
-      // Determine the location of the "live" compressed schema data
-      // file, and then append ".tmp" to get the name of the temporary
-      // file that we will use.
+      // Determine the location of the "live" compressed schema data file, and
+      // then append ".tmp" to get the name of the temporary file that we will
+      // use.
       String path = DirectoryServer.getServerRoot() + File.separator +
                     CONFIG_DIR_NAME + File.separator +
                     COMPRESSED_SCHEMA_FILE_NAME;
@@ -303,11 +283,10 @@
       writer = new ASN1Writer(outputStream);
 
 
-      // The first element in the file should be a sequence of object
-      // class sets.  Each object class set will itself be a sequence
-      // of octet strings, where the first one is the token and the
-      // remaining elements are the names of the associated object
-      // classes.
+      // The first element in the file should be a sequence of object class
+      // sets.  Each object class set will itself be a sequence of octet
+      // strings, where the first one is the token and the remaining elements
+      // are the names of the associated object classes.
       ArrayList<ASN1Element> ocElements =
            new ArrayList<ASN1Element>(ocDecodeMap.size());
       for (Map.Entry<ByteArray,Map<ObjectClass,String>> mapEntry :
@@ -330,17 +309,16 @@
       writer.writeElement(new ASN1Sequence(ocElements));
 
 
-      // The second element in the file should be an integer element
-      // that holds the value to use to initialize the object class
-      // counter.
+      // The second element in the file should be an integer element that holds
+      // the value to use to initialize the object class counter.
       writer.writeElement(new ASN1Integer(ocCounter.get()));
 
 
-      // The third element in the file should be a sequence of
-      // attribute description components.  Each attribute description
-      // component will itself be a sequence of octet strings, where
-      // the first one is the token, the second is the attribute name,
-      // and all remaining elements are the attribute options.
+      // The third element in the file should be a sequence of attribute
+      // description components.  Each attribute description component will
+      // itself be a sequence of octet strings, where the first one is the
+      // token, the second is the attribute name, and all remaining elements are
+      // the attribute options.
       ArrayList<ASN1Element> adElements =
            new ArrayList<ASN1Element>(atDecodeMap.size());
       for (ByteArray token : atDecodeMap.keySet())
@@ -362,9 +340,8 @@
       writer.writeElement(new ASN1Sequence(adElements));
 
 
-      // The fourth element in the file should be an integer element
-      // that holds the value to use to initialize the attribute
-      // description counter.
+      // The fourth element in the file should be an integer element that holds
+      // the value to use to initialize the attribute description counter.
       writer.writeElement(new ASN1Integer(adCounter.get()));
 
 
@@ -375,8 +352,7 @@
 
       if (liveFile.exists())
       {
-        File saveFile =
-                  new File(liveFile.getAbsolutePath() + ".save");
+        File saveFile = new File(liveFile.getAbsolutePath() + ".save");
         if (saveFile.exists())
         {
           saveFile.delete();
@@ -392,12 +368,10 @@
         TRACER.debugCaught(DebugLogLevel.ERROR, e);
       }
 
-      Message message =
-        ERR_COMPRESSEDSCHEMA_CANNOT_WRITE_UPDATED_DATA.
-            get(stackTraceToSingleLineString(e));
-      throw new DirectoryException(
-                     DirectoryServer.getServerErrorResultCode(),
-                     message, e);
+      Message message = ERR_COMPRESSEDSCHEMA_CANNOT_WRITE_UPDATED_DATA.get(
+                             stackTraceToSingleLineString(e));
+      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+                                   message, e);
     }
     finally
     {
@@ -421,39 +395,25 @@
 
 
   /**
-   * Encodes the provided set of object classes to a byte array.  If
-   * the same set had been previously encoded, then the cached value
-   * will be used.  Otherwise, a new value will be created.
-   *
-   * @param  objectClasses  The set of object classes for which to
-   *                        retrieve the corresponding byte array
-   *                        token.
-   *
-   * @return  A byte array containing the identifier assigned to the
-   *          object class set.
-   *
-   * @throws  DirectoryException  If a problem occurs while attempting
-   *                              to determine the appropriate
-   *                              identifier.
+   * {@inheritDoc}
    */
-  public static byte[]
-         encodeObjectClasses(Map<ObjectClass,String> objectClasses)
+  @Override()
+  public byte[] encodeObjectClasses(Map<ObjectClass,String> objectClasses)
          throws DirectoryException
   {
-    ByteArray encodedClasses =
-                    instance.ocEncodeMap.get(objectClasses);
+    ByteArray encodedClasses = ocEncodeMap.get(objectClasses);
     if (encodedClasses == null)
     {
-      synchronized (instance.ocEncodeMap)
+      synchronized (ocEncodeMap)
       {
-        int setValue = instance.ocCounter.getAndIncrement();
+        int setValue = ocCounter.getAndIncrement();
         byte[] array = encodeInt(setValue);
 
         encodedClasses = new ByteArray(array);
-        instance.ocEncodeMap.put(objectClasses, encodedClasses);
-        instance.ocDecodeMap.put(encodedClasses, objectClasses);
+        ocEncodeMap.put(objectClasses, encodedClasses);
+        ocDecodeMap.put(encodedClasses, objectClasses);
 
-        instance.save();
+        save();
         return array;
       }
     }
@@ -466,30 +426,21 @@
 
 
   /**
-   * Decodes an object class set from the provided byte array.
-   *
-   * @param  encodedObjectClasses  The byte array containing the
-   *                               object class set identifier.
-   *
-   * @return  The decoded object class set.
-   *
-   * @throws  DirectoryException  If the provided byte array cannot be
-   *                              decoded as an object class set.
+   * {@inheritDoc}
    */
-  public static Map<ObjectClass,String>
-         decodeObjectClasses(byte[] encodedObjectClasses)
+  @Override()
+  public Map<ObjectClass,String> decodeObjectClasses(
+                                      byte[] encodedObjectClasses)
          throws DirectoryException
   {
     ByteArray byteArray = new ByteArray(encodedObjectClasses);
-    Map<ObjectClass,String> ocMap =
-         instance.ocDecodeMap.get(byteArray);
+    Map<ObjectClass,String> ocMap = ocDecodeMap.get(byteArray);
     if (ocMap == null)
     {
       Message message = ERR_COMPRESSEDSCHEMA_UNKNOWN_OC_TOKEN.get(
-          bytesToHex(encodedObjectClasses));
-      throw new DirectoryException(
-                     DirectoryServer.getServerErrorResultCode(),
-                     message);
+                             bytesToHex(encodedObjectClasses));
+      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+                                   message);
     }
     else
     {
@@ -500,42 +451,33 @@
 
 
   /**
-   * Encodes the information in the provided attribute to a byte
-   * array.
-   *
-   * @param  attribute  The attribute to be encoded.
-   *
-   * @return  An encoded representation of the provided attribute.
-   *
-   * @throws  DirectoryException  If a problem occurs while attempting
-   *                              to determine the appropriate
-   *                              identifier.
+   * {@inheritDoc}
    */
-  public static byte[] encodeAttribute(Attribute attribute)
+  @Override()
+  public byte[] encodeAttribute(Attribute attribute)
          throws DirectoryException
   {
     AttributeType type = attribute.getAttributeType();
     LinkedHashSet<String> options = attribute.getOptions();
 
     ConcurrentHashMap<LinkedHashSet<String>,ByteArray> map =
-         instance.adEncodeMap.get(type);
+         adEncodeMap.get(type);
     if (map == null)
     {
       byte[] array;
-      synchronized (instance.adEncodeMap)
+      synchronized (adEncodeMap)
       {
-        map = new ConcurrentHashMap<LinkedHashSet<String>,
-                       ByteArray>(1);
+        map = new ConcurrentHashMap<LinkedHashSet<String>,ByteArray>(1);
 
-        int intValue = instance.adCounter.getAndIncrement();
+        int intValue = adCounter.getAndIncrement();
         array = encodeInt(intValue);
         ByteArray byteArray = new ByteArray(array);
         map.put(options,byteArray);
 
-        instance.adEncodeMap.put(type, map);
-        instance.atDecodeMap.put(byteArray, type);
-        instance.aoDecodeMap.put(byteArray, options);
-        instance.save();
+        adEncodeMap.put(type, map);
+        atDecodeMap.put(byteArray, type);
+        aoDecodeMap.put(byteArray, options);
+        save();
       }
 
       return encodeAttribute(array, attribute);
@@ -548,14 +490,14 @@
         byte[] array;
         synchronized (map)
         {
-          int intValue = instance.adCounter.getAndIncrement();
+          int intValue = adCounter.getAndIncrement();
           array = encodeInt(intValue);
           byteArray = new ByteArray(array);
           map.put(options,byteArray);
 
-          instance.atDecodeMap.put(byteArray, type);
-          instance.aoDecodeMap.put(byteArray, options);
-          instance.save();
+          atDecodeMap.put(byteArray, type);
+          aoDecodeMap.put(byteArray, options);
+          save();
         }
 
         return encodeAttribute(array, attribute);
@@ -579,8 +521,7 @@
    *
    * @return  An encoded representation of the provided attribute.
    */
-  private static byte[] encodeAttribute(byte[] adArray,
-                                        Attribute attribute)
+  private byte[] encodeAttribute(byte[] adArray, Attribute attribute)
   {
     LinkedHashSet<AttributeValue> values = attribute.getValues();
     int totalValuesLength = 0;
@@ -624,26 +565,15 @@
 
 
   /**
-   * Decodes the contents of the provided array as an attribute.
-   *
-   * @param  encodedEntry  The byte array containing the encoded
-   *                       entry.
-   * @param  startPos      The position within the array of the first
-   *                       byte for the attribute to decode.
-   * @param  length        The number of bytes contained in the
-   *                       encoded attribute.
-   *
-   * @return  The decoded attribute.
-   *
-   * @throws  DirectoryException  If the attribute could not be
-   *                              decoded properly for some reason.
+   * {@inheritDoc}
    */
-  public static Attribute decodeAttribute(byte[] encodedEntry,
-                                          int startPos, int length)
+  @Override()
+  public Attribute decodeAttribute(byte[] encodedEntry, int startPos,
+                                   int length)
          throws DirectoryException
   {
-    // Figure out how many bytes are in the token that is the
-    // placeholder for the attribute description.
+    // Figure out how many bytes are in the token that is the placeholder for
+    // the attribute description.
     int pos = startPos;
     int adArrayLength = encodedEntry[pos] & 0x7F;
     if (adArrayLength != encodedEntry[pos++])
@@ -652,27 +582,24 @@
       adArrayLength = 0;
       for (int i=0; i < numLengthBytes; i++, pos++)
       {
-        adArrayLength =
-             (adArrayLength << 8) | (encodedEntry[pos] & 0xFF);
+        adArrayLength = (adArrayLength << 8) | (encodedEntry[pos] & 0xFF);
       }
     }
 
 
-    // Get the attribute description token and make sure it resolves
-    // to an attribute type and option set.
+    // Get the attribute description token and make sure it resolves to an
+    // attribute type and option set.
     ByteArray adArray = new ByteArray(new byte[adArrayLength]);
-    System.arraycopy(encodedEntry, pos, adArray.array(), 0,
-                     adArrayLength);
+    System.arraycopy(encodedEntry, pos, adArray.array(), 0, adArrayLength);
     pos += adArrayLength;
-    AttributeType attrType = instance.atDecodeMap.get(adArray);
-    LinkedHashSet<String> options = instance.aoDecodeMap.get(adArray);
+    AttributeType attrType = atDecodeMap.get(adArray);
+    LinkedHashSet<String> options = aoDecodeMap.get(adArray);
     if ((attrType == null) || (options == null))
     {
-      Message message = ERR_COMPRESSEDSCHEMA_UNRECOGNIZED_AD_TOKEN.
-          get(bytesToHex(adArray.array()));
-      throw new DirectoryException(
-                     DirectoryServer.getServerErrorResultCode(),
-                     message);
+      Message message = ERR_COMPRESSEDSCHEMA_UNRECOGNIZED_AD_TOKEN.get(
+                             bytesToHex(adArray.array()));
+      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+                                   message);
     }
 
 
@@ -701,20 +628,17 @@
         valueLength = 0;
         for (int j=0; j < valueLengthBytes; j++, pos++)
         {
-          valueLength =
-               (valueLength << 8) | (encodedEntry[pos] & 0xFF);
+          valueLength = (valueLength << 8) | (encodedEntry[pos] & 0xFF);
         }
       }
 
       byte[] valueBytes = new byte[valueLength];
       System.arraycopy(encodedEntry, pos, valueBytes, 0, valueLength);
       pos += valueLength;
-      values.add(new AttributeValue(attrType,
-                                    new ASN1OctetString(valueBytes)));
+      values.add(new AttributeValue(attrType, new ASN1OctetString(valueBytes)));
     }
 
-    return new Attribute(attrType, attrType.getPrimaryName(), options,
-                         values);
+    return new Attribute(attrType, attrType.getPrimaryName(), options, values);
   }
 
 
@@ -726,7 +650,7 @@
    *
    * @return  The byte array containing the encoded int value.
    */
-  private static byte[] encodeInt(int intValue)
+  private byte[] encodeInt(int intValue)
   {
     byte[] array;
     if (intValue <= 0xFF)

--
Gitblit v1.10.0