mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

matthew_swift
05.42.2009 22094368c2865dcfb6daf8366425212b721a4657
opends/src/server/org/opends/server/core/DefaultCompressedSchema.java
@@ -31,7 +31,6 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -42,21 +41,10 @@
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;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.asn1.ASN1Reader;
import org.opends.server.protocols.asn1.ASN1Sequence;
import org.opends.server.protocols.asn1.ASN1;
import org.opends.server.protocols.asn1.ASN1Writer;
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.types.*;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -87,21 +75,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;
@@ -110,12 +99,14 @@
   */
  public DefaultCompressedSchema()
  {
    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>();
      <AttributeType, ConcurrentHashMap<Set<String>, ByteSequence>>();
    ocEncodeMap = new ConcurrentHashMap<Map<ObjectClass, String>,
        ByteSequence>();
    adCounter = new AtomicInteger(1);
    ocCounter = new AtomicInteger(1);
@@ -130,7 +121,7 @@
   */
  private void load()
  {
    ASN1Reader reader = null;
    FileInputStream inputStream = null;
    try
    {
@@ -144,41 +135,40 @@
      {
        return;
      }
      FileInputStream inputStream = new FileInputStream(path);
      reader = new ASN1Reader(inputStream);
      inputStream = new FileInputStream(path);
      ASN1Reader reader = ASN1.getReader(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();
      for (ASN1Element element : ocSequence.elements())
      reader.readStartSequence();
      while(reader.hasNextElement())
      {
        ArrayList<ASN1Element> elements = element.decodeAsSequence().elements();
        ASN1OctetString os = elements.get(0).decodeAsOctetString();
        ByteArray token = new ByteArray(os.value());
        reader.readStartSequence();
        ByteSequence token = reader.readOctetString();
        LinkedHashMap<ObjectClass,String> ocMap =
             new LinkedHashMap<ObjectClass,String>(elements.size()-1);
        for (int i=1; i < elements.size(); i++)
             new LinkedHashMap<ObjectClass,String>();
        while(reader.hasNextElement())
        {
          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);
      }
      reader.readEndSequence();
      // 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());
      ocCounter.set((int)reader.readInteger());
      // The third element in the file should be a sequence of attribute
@@ -186,35 +176,32 @@
      // 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())
      reader.readStartSequence();
      while(reader.hasNextElement())
      {
        ArrayList<ASN1Element> elements = element.decodeAsSequence().elements();
        ASN1OctetString os = elements. get(0).decodeAsOctetString();
        ByteArray token = new ByteArray(os.value());
        os = elements.get(1).decodeAsOctetString();
        String attrName = os.stringValue();
        reader.readStartSequence();
        ByteSequence token = reader.readOctetString();
        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()-2);
        for (int i=2; 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
        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);
        }
@@ -223,12 +210,12 @@
          map.put(options, token);
        }
      }
      reader.readEndSequence();
      // 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());
      adCounter.set((int)reader.readInteger());
    }
    catch (Exception e)
    {
@@ -244,9 +231,9 @@
    {
      try
      {
        if (reader != null)
        if (inputStream != null)
        {
          reader.close();
          inputStream.close();
        }
      }
      catch (Exception e)
@@ -270,7 +257,7 @@
  private void save()
          throws DirectoryException
  {
    ASN1Writer writer = null;
    FileOutputStream outputStream = null;
    try
    {
      // Determine the location of the "live" compressed schema data file, and
@@ -281,39 +268,34 @@
                    COMPRESSED_SCHEMA_FILE_NAME;
      String tempPath = path + ".tmp";
      FileOutputStream outputStream = new FileOutputStream(tempPath);
      writer = new ASN1Writer(outputStream);
      outputStream = new FileOutputStream(tempPath);
      ASN1Writer writer = ASN1.getWriter(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.
      ArrayList<ASN1Element> ocElements =
           new ArrayList<ASN1Element>(ocDecodeMap.size());
      for (Map.Entry<ByteArray,Map<ObjectClass,String>> mapEntry :
      writer.writeStartSequence();
      for (Map.Entry<ByteSequence,Map<ObjectClass,String>> mapEntry :
           ocDecodeMap.entrySet())
      {
        ByteArray token = mapEntry.getKey();
        writer.writeStartSequence();
        writer.writeOctetString(mapEntry.getKey());
        Map<ObjectClass,String> ocMap = mapEntry.getValue();
        ArrayList<ASN1Element> elements =
             new ArrayList<ASN1Element>(ocMap.size()+1);
        elements.add(new ASN1OctetString(token.array()));
        for (String ocName : ocMap.values())
        {
          elements.add(new ASN1OctetString(ocName));
          writer.writeOctetString(ocName);
        }
        ocElements.add(new ASN1Sequence(elements));
        writer.writeEndSequence();
      }
      writer.writeElement(new ASN1Sequence(ocElements));
      writer.writeEndSequence();
      // 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()));
      writer.writeInteger(ocCounter.get());
      // The third element in the file should be a sequence of attribute
@@ -321,34 +303,31 @@
      // 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())
      writer.writeStartSequence();
      for (ByteSequence token : atDecodeMap.keySet())
      {
        writer.writeStartSequence();
        AttributeType attrType = atDecodeMap.get(token);
        Set<String> options = aoDecodeMap.get(token);
        ArrayList<ASN1Element> elements =
             new ArrayList<ASN1Element>(options.size()+2);
        elements.add(new ASN1OctetString(token.array()));
        elements.add(new ASN1OctetString(attrType.getNameOrOID()));
        writer.writeOctetString(token);
        writer.writeOctetString(attrType.getNameOrOID());
        for (String option : options)
        {
          elements.add(new ASN1OctetString(option));
          writer.writeOctetString(option);
        }
        adElements.add(new ASN1Sequence(elements));
        writer.writeEndSequence();
      }
      writer.writeElement(new ASN1Sequence(adElements));
      writer.writeEndSequence();
      // 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()));
      writer.writeInteger(adCounter.get());
      // Close the writer and swing the temp file into place.
      writer.close();
      outputStream.close();
      File liveFile = new File(path);
      File tempFile = new File(tempPath);
@@ -379,9 +358,9 @@
    {
      try
      {
        if (writer != null)
        if (outputStream != null)
        {
          writer.close();
          outputStream.close();
        }
      }
      catch (Exception e)
@@ -400,29 +379,27 @@
   * {@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[] array = encodeInt(setValue);
        encodedClasses = new ByteArray(array);
        encodedClasses = ByteString.wrap(encodeInt(setValue));
        ocEncodeMap.put(objectClasses, encodedClasses);
        ocDecodeMap.put(encodedClasses, objectClasses);
        save();
        return array;
      }
    }
    else
    {
      return encodedClasses.array();
    }
    entryBuffer.appendBERLength(encodedClasses.length());
    encodedClasses.copyTo(entryBuffer);
  }
@@ -432,17 +409,17 @@
   */
  @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_COMPRESSEDSCHEMA_UNKNOWN_OC_TOKEN.get(
                             bytesToHex(encodedObjectClasses));
      Message message = ERR_COMPRESSEDSCHEMA_UNKNOWN_OC_TOKEN.get(byteArray
          .toByteString().toHex());
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message);
          message);
    }
    else
    {
@@ -456,23 +433,22 @@
   * {@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[] array;
      ByteString byteArray;
      synchronized (adEncodeMap)
      {
        map = new ConcurrentHashMap<Set<String>,ByteArray>(1);
        map = new ConcurrentHashMap<Set<String>, ByteSequence>(1);
        int intValue = adCounter.getAndIncrement();
        array = encodeInt(intValue);
        ByteArray byteArray = new ByteArray(array);
        byteArray = ByteString.wrap(encodeInt(intValue));
        map.put(options,byteArray);
        adEncodeMap.put(type, map);
@@ -481,32 +457,26 @@
        save();
      }
      return encodeAttribute(array, attribute);
      encodeAttribute(entryBuffer, byteArray, attribute);
    }
    else
    {
      ByteArray byteArray = map.get(options);
      ByteSequence byteArray = map.get(options);
      if (byteArray == null)
      {
        byte[] array;
        synchronized (map)
        {
          int intValue = adCounter.getAndIncrement();
          array = encodeInt(intValue);
          byteArray = new ByteArray(array);
          byteArray = ByteString.wrap(encodeInt(intValue));
          map.put(options,byteArray);
          atDecodeMap.put(byteArray, type);
          aoDecodeMap.put(byteArray, options);
          save();
        }
      }
        return encodeAttribute(array, attribute);
      }
      else
      {
        return encodeAttribute(byteArray.array(), attribute);
      }
      encodeAttribute(entryBuffer, byteArray, attribute);
    }
  }
@@ -516,50 +486,27 @@
   * 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;
  }
@@ -568,75 +515,43 @@
   * {@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_COMPRESSEDSCHEMA_UNRECOGNIZED_AD_TOKEN.get(
                             bytesToHex(adArray.array()));
      Message message = ERR_COMPRESSEDSCHEMA_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
    {
@@ -646,22 +561,12 @@
      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();