From 22094368c2865dcfb6daf8366425212b721a4657 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Thu, 05 Feb 2009 17:42:14 +0000
Subject: [PATCH] Merge ASN1 branch to trunk

---
 opends/src/server/org/opends/server/backends/jeb/JECompressedSchema.java |  379 +++++++++++++++++++++++-------------------------------
 1 files changed, 162 insertions(+), 217 deletions(-)

diff --git a/opends/src/server/org/opends/server/backends/jeb/JECompressedSchema.java b/opends/src/server/org/opends/server/backends/jeb/JECompressedSchema.java
index f480da1..af4c396 100644
--- a/opends/src/server/org/opends/server/backends/jeb/JECompressedSchema.java
+++ b/opends/src/server/org/opends/server/backends/jeb/JECompressedSchema.java
@@ -32,31 +32,20 @@
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.util.StaticUtils.*;
 
-import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.io.IOException;
 
 import org.opends.messages.Message;
 import org.opends.server.api.CompressedSchema;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-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 org.opends.server.protocols.asn1.*;
+import org.opends.server.types.*;
 
 import com.sleepycat.je.Cursor;
 import com.sleepycat.je.Database;
@@ -107,21 +96,22 @@
   private AtomicInteger ocCounter;
 
   // The map between encoded representations and attribute types.
-  private ConcurrentHashMap<ByteArray,AttributeType> atDecodeMap;
+  private ConcurrentHashMap<ByteSequence,AttributeType> atDecodeMap;
 
   // The map between encoded representations and attribute options.
-  private ConcurrentHashMap<ByteArray,Set<String>> aoDecodeMap;
+  private ConcurrentHashMap<ByteSequence,Set<String>> aoDecodeMap;
 
   // The map between encoded representations and object class sets.
-  private ConcurrentHashMap<ByteArray,Map<ObjectClass,String>> ocDecodeMap;
+  private ConcurrentHashMap<ByteSequence,Map<ObjectClass,String>> ocDecodeMap;
 
   // The map between attribute descriptions and their encoded
   // representations.
-  private ConcurrentHashMap<AttributeType,
-               ConcurrentHashMap<Set<String>,ByteArray>> adEncodeMap;
+  private final ConcurrentHashMap<AttributeType,
+                ConcurrentHashMap<Set<String>, ByteSequence>> adEncodeMap;
 
   // The map between object class sets and encoded representations.
-  private ConcurrentHashMap<Map<ObjectClass,String>,ByteArray> ocEncodeMap;
+  private final ConcurrentHashMap<Map<ObjectClass,String>,
+      ByteSequence> ocEncodeMap;
 
   // The compressed attribute description schema database.
   private Database adDatabase;
@@ -132,6 +122,9 @@
   // The environment in which the databases are held.
   private Environment environment;
 
+  private final ByteStringBuilder storeWriterBuffer;
+  private final ASN1Writer storeWriter;
+
 
 
   /**
@@ -149,17 +142,21 @@
   {
     this.environment = environment;
 
-    atDecodeMap = new ConcurrentHashMap<ByteArray,AttributeType>();
-    aoDecodeMap = new ConcurrentHashMap<ByteArray,Set<String>>();
-    ocDecodeMap = new ConcurrentHashMap<ByteArray,Map<ObjectClass,String>>();
+    atDecodeMap = new ConcurrentHashMap<ByteSequence,AttributeType>();
+    aoDecodeMap = new ConcurrentHashMap<ByteSequence,Set<String>>();
+    ocDecodeMap = new ConcurrentHashMap<ByteSequence,Map<ObjectClass,String>>();
     adEncodeMap =
          new ConcurrentHashMap<AttributeType,
-                  ConcurrentHashMap<Set<String>,ByteArray>>();
-    ocEncodeMap = new ConcurrentHashMap<Map<ObjectClass,String>,ByteArray>();
+                  ConcurrentHashMap<Set<String>, ByteSequence>>();
+    ocEncodeMap = new ConcurrentHashMap<Map<ObjectClass,String>,
+        ByteSequence>();
 
     adCounter = new AtomicInteger(1);
     ocCounter = new AtomicInteger(1);
 
+    storeWriterBuffer = new ByteStringBuilder();
+    storeWriter = ASN1.getWriter(storeWriterBuffer);
+
     load();
   }
 
@@ -211,21 +208,23 @@
                                                  LockMode.READ_UNCOMMITTED);
       while (status == OperationStatus.SUCCESS)
       {
-        ByteArray token = new ByteArray(keyEntry.getData());
-        highestToken = Math.max(highestToken, decodeInt(token.array()));
+        byte[] tokenBytes = keyEntry.getData();
+        ByteString token = ByteString.wrap(tokenBytes);
+        highestToken = Math.max(highestToken, decodeInt(tokenBytes));
 
-        ArrayList<ASN1Element> elements =
-             ASN1Sequence.decodeAsSequence(valueEntry.getData()).elements();
+        ASN1Reader reader =
+            ASN1.getReader(valueEntry.getData());
+        reader.readStartSequence();
         LinkedHashMap<ObjectClass,String> ocMap =
-             new LinkedHashMap<ObjectClass,String>(elements.size());
-        for (int i=0; i < elements.size(); i++)
+             new LinkedHashMap<ObjectClass,String>();
+        while(reader.hasNextElement())
         {
-          ASN1OctetString os = elements.get(i).decodeAsOctetString();
-          String ocName = os.stringValue();
+          String ocName = reader.readOctetStringAsString();
           String lowerName = toLowerCase(ocName);
           ObjectClass oc = DirectoryServer.getObjectClass(lowerName, true);
           ocMap.put(oc, ocName);
         }
+        reader.readEndSequence();
 
         ocEncodeMap.put(ocMap, token);
         ocDecodeMap.put(token, ocMap);
@@ -266,34 +265,34 @@
                                                  LockMode.READ_UNCOMMITTED);
       while (status == OperationStatus.SUCCESS)
       {
-        ByteArray token = new ByteArray(keyEntry.getData());
-        highestToken = Math.max(highestToken, decodeInt(token.array()));
+        byte[] tokenBytes = keyEntry.getData();
+        ByteString token = ByteString.wrap(tokenBytes);
+        highestToken = Math.max(highestToken, decodeInt(tokenBytes));
 
-        ArrayList<ASN1Element> elements =
-             ASN1Sequence.decodeAsSequence(valueEntry.getData()).elements();
-
-        ASN1OctetString os = elements.get(0).decodeAsOctetString();
-        String attrName = os.stringValue();
+        ASN1Reader reader =
+            ASN1.getReader(valueEntry.getData());
+        reader.readStartSequence();
+        String attrName = reader.readOctetStringAsString();
         String lowerName = toLowerCase(attrName);
         AttributeType attrType =
-             DirectoryServer.getAttributeType(lowerName, true);
+            DirectoryServer.getAttributeType(lowerName, true);
 
         LinkedHashSet<String> options =
-             new LinkedHashSet<String>(elements.size()-1);
-        for (int i=1; i < elements.size(); i++)
+            new LinkedHashSet<String>();
+        while(reader.hasNextElement())
         {
-          os = elements.get(i).decodeAsOctetString();
-          options.add(os.stringValue());
+          options.add(reader.readOctetStringAsString());
         }
+        reader.readEndSequence();
 
         atDecodeMap.put(token, attrType);
         aoDecodeMap.put(token, options);
 
-        ConcurrentHashMap<Set<String>,ByteArray> map =
-             adEncodeMap.get(attrType);
+        ConcurrentHashMap<Set<String>, ByteSequence> map = adEncodeMap
+            .get(attrType);
         if (map == null)
         {
-          map = new ConcurrentHashMap<Set<String>,ByteArray>(1);
+          map = new ConcurrentHashMap<Set<String>, ByteSequence>(1);
           map.put(options, token);
           adEncodeMap.put(attrType, map);
         }
@@ -359,8 +358,8 @@
     atDecodeMap = null;
     aoDecodeMap = null;
     ocDecodeMap = null;
-    adEncodeMap = null;
-    ocEncodeMap = null;
+    //adEncodeMap = null;
+    //ocEncodeMap = null;
     adCounter   = null;
     ocCounter   = null;
   }
@@ -371,58 +370,45 @@
    * {@inheritDoc}
    */
   @Override()
-  public byte[] encodeObjectClasses(Map<ObjectClass,String> objectClasses)
+  public void encodeObjectClasses(ByteStringBuilder entryBuffer,
+                                  Map<ObjectClass,String> objectClasses)
          throws DirectoryException
   {
-    ByteArray encodedClasses = ocEncodeMap.get(objectClasses);
+    ByteSequence encodedClasses = ocEncodeMap.get(objectClasses);
     if (encodedClasses == null)
     {
       synchronized (ocEncodeMap)
       {
         int setValue = ocCounter.getAndIncrement();
         byte[] tokenArray = encodeInt(setValue);
+        encodedClasses = ByteString.wrap(tokenArray);
 
-        ArrayList<ASN1Element> elements =
-             new ArrayList<ASN1Element>(objectClasses.size());
-        for (String ocName : objectClasses.values())
-        {
-          elements.add(new ASN1OctetString(ocName));
-        }
-
-        byte[] encodedOCs = new ASN1Sequence(elements).encode();
-        store(ocDatabase, tokenArray, encodedOCs);
-
-        encodedClasses = new ByteArray(tokenArray);
+        storeObjectClass(tokenArray, objectClasses);
         ocEncodeMap.put(objectClasses, encodedClasses);
         ocDecodeMap.put(encodedClasses, objectClasses);
-
-        return tokenArray;
       }
     }
-    else
-    {
-      return encodedClasses.array();
-    }
+
+    entryBuffer.appendBERLength(encodedClasses.length());
+    encodedClasses.copyTo(entryBuffer);
   }
 
-
-
   /**
    * {@inheritDoc}
    */
   @Override()
   public Map<ObjectClass,String> decodeObjectClasses(
-                                      byte[] encodedObjectClasses)
-         throws DirectoryException
+      ByteSequenceReader entryBufferReader) throws DirectoryException
   {
-    ByteArray byteArray = new ByteArray(encodedObjectClasses);
+    int tokenLength = entryBufferReader.getBERLength();
+    ByteSequence byteArray = entryBufferReader.getByteSequence(tokenLength);
     Map<ObjectClass,String> ocMap = ocDecodeMap.get(byteArray);
     if (ocMap == null)
     {
-      Message message = ERR_JEB_COMPSCHEMA_UNKNOWN_OC_TOKEN.get(
-                             bytesToHex(encodedObjectClasses));
+      Message message = ERR_JEB_COMPSCHEMA_UNKNOWN_OC_TOKEN.get(byteArray
+          .toByteString().toHex());
       throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-                                   message);
+          message);
     }
     else
     {
@@ -430,52 +416,90 @@
     }
   }
 
+  private void storeObjectClass(byte[] token,
+                                Map<ObjectClass,String> objectClasses)
+      throws DirectoryException
+  {
+    synchronized(storeWriter)
+    {
+      try
+      {
+        storeWriterBuffer.clear();
+        storeWriter.writeStartSequence();
+        for (String ocName : objectClasses.values())
+        {
+          storeWriter.writeOctetString(ocName);
+        }
+        storeWriter.writeEndSequence();
+        store(ocDatabase, token, storeWriterBuffer);
+      }
+      catch(IOException ioe)
+      {
+        // TODO: Shouldn't happen but should log a message
+      }
+    }
+  }
 
+  private void storeAttribute(byte[] token,
+                              AttributeType attrType, Set<String> options)
+      throws DirectoryException
+  {
+    synchronized(storeWriter)
+    {
+      try
+      {
+        storeWriterBuffer.clear();
+        storeWriter.writeStartSequence();
+        storeWriter.writeOctetString(attrType.getNameOrOID());
+        for (String option : options)
+        {
+          storeWriter.writeOctetString(option);
+        }
+        storeWriter.writeEndSequence();
+        store(adDatabase, token, storeWriterBuffer);
+      }
+      catch(IOException ioe)
+      {
+        // TODO: Shouldn't happen but should log a message
+      }
+    }
+  }
 
   /**
    * {@inheritDoc}
    */
   @Override()
-  public byte[] encodeAttribute(Attribute attribute)
-         throws DirectoryException
+  public void encodeAttribute(ByteStringBuilder entryBuffer,
+                              Attribute attribute) throws DirectoryException
   {
     AttributeType type = attribute.getAttributeType();
     Set<String> options = attribute.getOptions();
 
-    ConcurrentHashMap<Set<String>,ByteArray> map =
-         adEncodeMap.get(type);
+    ConcurrentHashMap<Set<String>, ByteSequence> map = adEncodeMap.get(type);
     if (map == null)
     {
       byte[] tokenArray;
+      ByteString byteString;
       synchronized (adEncodeMap)
       {
-        map = new ConcurrentHashMap<Set<String>,ByteArray>(1);
+        map = new ConcurrentHashMap<Set<String>, ByteSequence>(1);
 
         int intValue = adCounter.getAndIncrement();
         tokenArray = encodeInt(intValue);
-        ByteArray byteArray = new ByteArray(tokenArray);
-        map.put(options,byteArray);
+        byteString = ByteString.wrap(tokenArray);
+        map.put(options,byteString);
 
-        ArrayList<ASN1Element> elements =
-             new ArrayList<ASN1Element>(options.size()+1);
-        elements.add(new ASN1OctetString(attribute.getName()));
-        for (String option : options)
-        {
-          elements.add(new ASN1OctetString(option));
-        }
-        byte[] encodedValue = new ASN1Sequence(elements).encode();
-        store(adDatabase, tokenArray, encodedValue);
-
+        storeAttribute(tokenArray, type, options);
         adEncodeMap.put(type, map);
-        atDecodeMap.put(byteArray, type);
-        aoDecodeMap.put(byteArray, options);
+        atDecodeMap.put(byteString, type);
+        aoDecodeMap.put(byteString, options);
       }
 
-      return encodeAttribute(tokenArray, attribute);
+      encodeAttribute(entryBuffer, byteString, attribute);
     }
     else
     {
-      ByteArray byteArray = map.get(options);
+      ByteSequence byteArray = map.get(options);
       if (byteArray == null)
       {
         byte[] tokenArray;
@@ -483,29 +507,16 @@
         {
           int intValue = adCounter.getAndIncrement();
           tokenArray = encodeInt(intValue);
-          byteArray = new ByteArray(tokenArray);
+          byteArray = ByteString.wrap(tokenArray);
           map.put(options,byteArray);
 
-          ArrayList<ASN1Element> elements =
-               new ArrayList<ASN1Element>(options.size()+1);
-          elements.add(new ASN1OctetString(attribute.getName()));
-          for (String option : options)
-          {
-            elements.add(new ASN1OctetString(option));
-          }
-          byte[] encodedValue = new ASN1Sequence(elements).encode();
-          store(adDatabase, tokenArray, encodedValue);
-
+          storeAttribute(tokenArray, type, options);
           atDecodeMap.put(byteArray, type);
           aoDecodeMap.put(byteArray, options);
         }
+      }
 
-        return encodeAttribute(tokenArray, attribute);
-      }
-      else
-      {
-        return encodeAttribute(byteArray.array(), attribute);
-      }
+      encodeAttribute(entryBuffer, byteArray, attribute);
     }
   }
 
@@ -515,126 +526,70 @@
    * Encodes the information in the provided attribute to a byte
    * array.
    *
+   * @param  buffer     The byte buffer to encode the attribute into.
    * @param  adArray    The byte array that is a placeholder for the
    *                    attribute type and set of options.
    * @param  attribute  The attribute to be encoded.
-   *
-   * @return  An encoded representation of the provided attribute.
    */
-  private byte[] encodeAttribute(byte[] adArray, Attribute attribute)
+  private void encodeAttribute(ByteStringBuilder buffer, ByteSequence adArray,
+                                 Attribute attribute)
   {
-    int totalValuesLength = 0;
-    byte[][] subArrays = new  byte[attribute.size()*2][];
-    int pos = 0;
-    for (AttributeValue v : attribute)
+    // Write the length of the adArray followed by the adArray.
+    buffer.appendBERLength(adArray.length());
+    adArray.copyTo(buffer);
+
+    // Write the number of attributes
+    buffer.appendBERLength(attribute.size());
+
+    // Write the attribute values as length / value pairs
+    for(AttributeValue v : attribute)
     {
-      byte[] vBytes = v.getValueBytes();
-      byte[] lBytes = ASN1Element.encodeLength(vBytes.length);
-
-      subArrays[pos++] = lBytes;
-      subArrays[pos++] = vBytes;
-
-      totalValuesLength += lBytes.length + vBytes.length;
+      buffer.appendBERLength(v.getValue().length());
+      buffer.append(v.getValue());
     }
-
-    byte[] adArrayLength = ASN1Element.encodeLength(adArray.length);
-    byte[] countBytes = ASN1Element.encodeLength(attribute.size());
-    int totalLength = adArrayLength.length + adArray.length +
-                      countBytes.length + totalValuesLength;
-    byte[] array = new byte[totalLength];
-
-    System.arraycopy(adArrayLength, 0, array, 0,
-                     adArrayLength.length);
-    pos = adArrayLength.length;
-    System.arraycopy(adArray, 0, array, pos, adArray.length);
-    pos += adArray.length;
-    System.arraycopy(countBytes, 0, array, pos, countBytes.length);
-    pos += countBytes.length;
-
-    for (int i=0; i < subArrays.length; i++)
-    {
-      System.arraycopy(subArrays[i], 0, array, pos,
-                       subArrays[i].length);
-      pos += subArrays[i].length;
-    }
-
-    return array;
   }
 
-
-
   /**
    * {@inheritDoc}
    */
   @Override()
-  public Attribute decodeAttribute(byte[] encodedEntry, int startPos,
-                                   int length)
+  public Attribute decodeAttribute(ByteSequenceReader entryBufferReader)
          throws DirectoryException
   {
     // 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++])
-    {
-      int numLengthBytes = adArrayLength;
-      adArrayLength = 0;
-      for (int i=0; i < numLengthBytes; i++, pos++)
-      {
-        adArrayLength = (adArrayLength << 8) | (encodedEntry[pos] & 0xFF);
-      }
-    }
+    int adArrayLength = entryBufferReader.getBERLength();
 
 
     // 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);
-    pos += adArrayLength;
+    ByteSequence adArray = entryBufferReader.getByteSequence(adArrayLength);
+
     AttributeType attrType = atDecodeMap.get(adArray);
     Set<String> options = aoDecodeMap.get(adArray);
     if ((attrType == null) || (options == null))
     {
-      Message message = ERR_JEB_COMPSCHEMA_UNRECOGNIZED_AD_TOKEN.get(
-                             bytesToHex(adArray.array()));
+      Message message = ERR_JEB_COMPSCHEMA_UNRECOGNIZED_AD_TOKEN.get(adArray
+          .toByteString().toHex());
       throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-                                   message);
+          message);
     }
 
 
     // Determine the number of values for the attribute.
-    int numValues = encodedEntry[pos] & 0x7F;
-    if (numValues != encodedEntry[pos++])
-    {
-      int numValuesBytes = numValues;
-      numValues = 0;
-      for (int i=0; i < numValuesBytes; i++, pos++)
-      {
-        numValues = (numValues << 8) | (encodedEntry[pos] & 0xFF);
-      }
-    }
+    int numValues = entryBufferReader.getBERLength();
 
 
     // For the common case of a single value with no options, generate
     // less garbage.
     if (numValues == 1 && options.isEmpty())
     {
-      int valueLength = encodedEntry[pos] & 0x7F;
-      if (valueLength != encodedEntry[pos++])
-      {
-        int valueLengthBytes = valueLength;
-        valueLength = 0;
-        for (int j = 0; j < valueLengthBytes; j++, pos++)
-        {
-          valueLength = (valueLength << 8) | (encodedEntry[pos] & 0xFF);
-        }
-      }
+      int valueLength = entryBufferReader.getBERLength();
 
-      byte[] valueBytes = new byte[valueLength];
-      System.arraycopy(encodedEntry, pos, valueBytes, 0, valueLength);
-
-      return Attributes.create(attrType, new AttributeValue(attrType,
-          new ASN1OctetString(valueBytes)));
+      ByteString valueBytes =
+          entryBufferReader.getByteSequence(valueLength).toByteString();
+      return Attributes.create(attrType,
+          AttributeValues.create(attrType, valueBytes));
     }
     else
     {
@@ -644,30 +599,18 @@
       builder.setInitialCapacity(numValues);
       for (int i = 0; i < numValues; i++)
       {
-        int valueLength = encodedEntry[pos] & 0x7F;
-        if (valueLength != encodedEntry[pos++])
-        {
-          int valueLengthBytes = valueLength;
-          valueLength = 0;
-          for (int j = 0; j < valueLengthBytes; j++, pos++)
-          {
-            valueLength = (valueLength << 8) | (encodedEntry[pos] & 0xFF);
-          }
-        }
+        int valueLength = entryBufferReader.getBERLength();
 
-        byte[] valueBytes = new byte[valueLength];
-        System.arraycopy(encodedEntry, pos, valueBytes, 0, valueLength);
-        pos += valueLength;
-        builder.add(new AttributeValue(attrType,
-            new ASN1OctetString(valueBytes)));
+        ByteString valueBytes =
+            entryBufferReader.getByteSequence(valueLength).toByteString();
+        builder.add(AttributeValues.create(attrType,
+            valueBytes));
       }
 
       return builder.toAttribute();
     }
   }
 
-
-
   /**
    * Stores the provided key-value pair in the specified database container.
    *
@@ -678,12 +621,14 @@
    * @throws  DirectoryException  If a problem occurs while attempting to store
    *                              the data.
    */
-  private void store(Database database, byte[] keyBytes, byte[] valueBytes)
+  private void store(Database database, byte[] keyBytes,
+                     ByteStringBuilder valueBytes)
           throws DirectoryException
   {
     boolean successful = false;
     DatabaseEntry keyEntry   = new DatabaseEntry(keyBytes);
-    DatabaseEntry valueEntry = new DatabaseEntry(valueBytes);
+    DatabaseEntry valueEntry = new DatabaseEntry(valueBytes.getBackingArray(),
+        0, valueBytes.length());
 
     for (int i=0; i < 3; i++)
     {

--
Gitblit v1.10.0