| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Portions Copyright 2007 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.Map; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | |
| | | import com.sleepycat.je.Cursor; |
| | | import com.sleepycat.je.Database; |
| | | import com.sleepycat.je.DatabaseConfig; |
| | | import com.sleepycat.je.DatabaseEntry; |
| | | import com.sleepycat.je.DatabaseException; |
| | | import com.sleepycat.je.DeadlockException; |
| | | import com.sleepycat.je.Environment; |
| | | import com.sleepycat.je.LockMode; |
| | | import com.sleepycat.je.OperationStatus; |
| | | |
| | | 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.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.*; |
| | | import static org.opends.messages.JebMessages.*; |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class provides a compressed schema implementation whose definitions are |
| | | * stored in a Berkeley DB JE database. |
| | | */ |
| | | public final class JECompressedSchema |
| | | extends CompressedSchema |
| | | { |
| | | /** |
| | | * The tracer object for the debug logger. |
| | | */ |
| | | private static final DebugTracer TRACER = getTracer(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * The name of the database used to store compressed attribute description |
| | | * definitions. |
| | | */ |
| | | public static final String DB_NAME_AD = "compressed_attributes"; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The name of the database used to store compressed object class set |
| | | * definitions. |
| | | */ |
| | | public static final String DB_NAME_OC = "compressed_object_classes"; |
| | | |
| | | |
| | | |
| | | // The counter used for attribute descriptions. |
| | | private AtomicInteger adCounter; |
| | | |
| | | // The counter used for object class sets. |
| | | private AtomicInteger ocCounter; |
| | | |
| | | // The map between encoded representations and attribute types. |
| | | private ConcurrentHashMap<ByteArray,AttributeType> atDecodeMap; |
| | | |
| | | // The map between encoded representations and attribute options. |
| | | private ConcurrentHashMap<ByteArray,LinkedHashSet<String>> aoDecodeMap; |
| | | |
| | | // The map between encoded representations and object class sets. |
| | | private ConcurrentHashMap<ByteArray,Map<ObjectClass,String>> ocDecodeMap; |
| | | |
| | | // The map between attribute descriptions and their encoded |
| | | // representations. |
| | | private ConcurrentHashMap<AttributeType, |
| | | ConcurrentHashMap<LinkedHashSet<String>,ByteArray>> adEncodeMap; |
| | | |
| | | // The map between object class sets and encoded representations. |
| | | private ConcurrentHashMap<Map<ObjectClass,String>,ByteArray> ocEncodeMap; |
| | | |
| | | // The compressed attribute description schema database. |
| | | private Database adDatabase; |
| | | |
| | | // The compresesd object class set schema database. |
| | | private Database ocDatabase; |
| | | |
| | | // The environment in which the databases are held. |
| | | private Environment environment; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new instance of this JE compressed schema manager. |
| | | * |
| | | * @param environment A reference to the database environment in which the |
| | | * databases will be held. |
| | | * |
| | | * @throws DatabaseException If a problem occurs while loading the |
| | | * compressed schema definitions from the |
| | | * database. |
| | | */ |
| | | public JECompressedSchema(Environment environment) |
| | | throws DatabaseException |
| | | { |
| | | this.environment = environment; |
| | | |
| | | 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>(); |
| | | |
| | | adCounter = new AtomicInteger(1); |
| | | ocCounter = new AtomicInteger(1); |
| | | |
| | | load(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Loads the compressed schema information from the database. |
| | | * |
| | | * @throws DatabaseException If a problem occurs while loading the |
| | | * definitions from the database. |
| | | */ |
| | | private void load() |
| | | throws DatabaseException |
| | | { |
| | | DatabaseConfig dbConfig = new DatabaseConfig(); |
| | | |
| | | if(environment.getConfig().getReadOnly()) |
| | | { |
| | | dbConfig.setReadOnly(true); |
| | | dbConfig.setAllowCreate(false); |
| | | dbConfig.setTransactional(false); |
| | | } |
| | | else if(!environment.getConfig().getTransactional()) |
| | | { |
| | | dbConfig.setAllowCreate(true); |
| | | dbConfig.setTransactional(false); |
| | | dbConfig.setDeferredWrite(true); |
| | | } |
| | | else |
| | | { |
| | | dbConfig.setAllowCreate(true); |
| | | dbConfig.setTransactional(true); |
| | | } |
| | | |
| | | adDatabase = environment.openDatabase(null, DB_NAME_AD, dbConfig); |
| | | ocDatabase = environment.openDatabase(null, DB_NAME_OC, dbConfig); |
| | | |
| | | // Cursor through the object class database and load the object class set |
| | | // definitions. At the same time, figure out the highest token value and |
| | | // initialize the object class counter to one greater than that. |
| | | Cursor ocCursor = ocDatabase.openCursor(null, null); |
| | | int highestToken = 0; |
| | | |
| | | try |
| | | { |
| | | DatabaseEntry keyEntry = new DatabaseEntry(); |
| | | DatabaseEntry valueEntry = new DatabaseEntry(); |
| | | OperationStatus status = ocCursor.getFirst(keyEntry, valueEntry, |
| | | LockMode.READ_UNCOMMITTED); |
| | | while (status == OperationStatus.SUCCESS) |
| | | { |
| | | ByteArray token = new ByteArray(keyEntry.getData()); |
| | | highestToken = Math.max(highestToken, decodeInt(token.array())); |
| | | |
| | | ArrayList<ASN1Element> elements = |
| | | ASN1Sequence.decodeAsSequence(valueEntry.getData()).elements(); |
| | | LinkedHashMap<ObjectClass,String> ocMap = |
| | | new LinkedHashMap<ObjectClass,String>(elements.size()); |
| | | for (int i=0; i < elements.size(); i++) |
| | | { |
| | | ASN1OctetString os = elements.get(i).decodeAsOctetString(); |
| | | String ocName = os.stringValue(); |
| | | String lowerName = toLowerCase(ocName); |
| | | ObjectClass oc = DirectoryServer.getObjectClass(lowerName, true); |
| | | ocMap.put(oc, ocName); |
| | | } |
| | | |
| | | ocEncodeMap.put(ocMap, token); |
| | | ocDecodeMap.put(token, ocMap); |
| | | |
| | | status = ocCursor.getNext(keyEntry, valueEntry, |
| | | LockMode.READ_UNCOMMITTED); |
| | | } |
| | | } |
| | | catch (ASN1Exception ae) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, ae); |
| | | } |
| | | |
| | | Message m = |
| | | ERR_JEB_COMPSCHEMA_CANNOT_DECODE_OC_TOKEN.get(ae.getMessage()); |
| | | throw new DatabaseException(m.toString(), ae); |
| | | } |
| | | finally |
| | | { |
| | | ocCursor.close(); |
| | | } |
| | | |
| | | ocCounter.set(highestToken+1); |
| | | |
| | | |
| | | // Cursor through the attribute description database and load the attribute |
| | | // set definitions. |
| | | Cursor adCursor = adDatabase.openCursor(null, null); |
| | | highestToken = 0; |
| | | |
| | | try |
| | | { |
| | | DatabaseEntry keyEntry = new DatabaseEntry(); |
| | | DatabaseEntry valueEntry = new DatabaseEntry(); |
| | | OperationStatus status = adCursor.getFirst(keyEntry, valueEntry, |
| | | LockMode.READ_UNCOMMITTED); |
| | | while (status == OperationStatus.SUCCESS) |
| | | { |
| | | ByteArray token = new ByteArray(keyEntry.getData()); |
| | | highestToken = Math.max(highestToken, decodeInt(token.array())); |
| | | |
| | | ArrayList<ASN1Element> elements = |
| | | ASN1Sequence.decodeAsSequence(valueEntry.getData()).elements(); |
| | | |
| | | ASN1OctetString os = elements.get(0).decodeAsOctetString(); |
| | | String attrName = os.stringValue(); |
| | | String lowerName = toLowerCase(attrName); |
| | | AttributeType attrType = |
| | | DirectoryServer.getAttributeType(lowerName, true); |
| | | |
| | | LinkedHashSet<String> options = |
| | | new LinkedHashSet<String>(elements.size()-1); |
| | | for (int i=1; i < elements.size(); i++) |
| | | { |
| | | os = elements.get(i).decodeAsOctetString(); |
| | | options.add(os.stringValue()); |
| | | } |
| | | |
| | | atDecodeMap.put(token, attrType); |
| | | aoDecodeMap.put(token, options); |
| | | |
| | | ConcurrentHashMap<LinkedHashSet<String>,ByteArray> map = |
| | | adEncodeMap.get(attrType); |
| | | if (map == null) |
| | | { |
| | | map = new ConcurrentHashMap<LinkedHashSet<String>,ByteArray>(1); |
| | | map.put(options, token); |
| | | adEncodeMap.put(attrType, map); |
| | | } |
| | | else |
| | | { |
| | | map.put(options, token); |
| | | } |
| | | |
| | | status = adCursor.getNext(keyEntry, valueEntry, |
| | | LockMode.READ_UNCOMMITTED); |
| | | } |
| | | } |
| | | catch (ASN1Exception ae) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, ae); |
| | | } |
| | | |
| | | Message m = |
| | | ERR_JEB_COMPSCHEMA_CANNOT_DECODE_AD_TOKEN.get(ae.getMessage()); |
| | | throw new DatabaseException(m.toString(), ae); |
| | | } |
| | | finally |
| | | { |
| | | adCursor.close(); |
| | | } |
| | | |
| | | adCounter.set(highestToken+1); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Closes the databases and releases any resources held by this compressed |
| | | * schema manager. |
| | | */ |
| | | public void close() |
| | | { |
| | | try |
| | | { |
| | | adDatabase.sync(); |
| | | } catch (Exception e) {} |
| | | |
| | | try |
| | | { |
| | | adDatabase.close(); |
| | | } catch (Exception e) {} |
| | | |
| | | try |
| | | { |
| | | ocDatabase.sync(); |
| | | } catch (Exception e) {} |
| | | |
| | | try |
| | | { |
| | | ocDatabase.close(); |
| | | } catch (Exception e) {} |
| | | |
| | | adDatabase = null; |
| | | ocDatabase = null; |
| | | environment = null; |
| | | atDecodeMap = null; |
| | | aoDecodeMap = null; |
| | | ocDecodeMap = null; |
| | | adEncodeMap = null; |
| | | ocEncodeMap = null; |
| | | adCounter = null; |
| | | ocCounter = null; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | public byte[] encodeObjectClasses(Map<ObjectClass,String> objectClasses) |
| | | throws DirectoryException |
| | | { |
| | | ByteArray encodedClasses = ocEncodeMap.get(objectClasses); |
| | | if (encodedClasses == null) |
| | | { |
| | | synchronized (ocEncodeMap) |
| | | { |
| | | int setValue = ocCounter.getAndIncrement(); |
| | | byte[] tokenArray = encodeInt(setValue); |
| | | |
| | | 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); |
| | | ocEncodeMap.put(objectClasses, encodedClasses); |
| | | ocDecodeMap.put(encodedClasses, objectClasses); |
| | | |
| | | return tokenArray; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | return encodedClasses.array(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | public Map<ObjectClass,String> decodeObjectClasses( |
| | | byte[] encodedObjectClasses) |
| | | throws DirectoryException |
| | | { |
| | | ByteArray byteArray = new ByteArray(encodedObjectClasses); |
| | | Map<ObjectClass,String> ocMap = ocDecodeMap.get(byteArray); |
| | | if (ocMap == null) |
| | | { |
| | | Message message = ERR_JEB_COMPSCHEMA_UNKNOWN_OC_TOKEN.get( |
| | | bytesToHex(encodedObjectClasses)); |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | message); |
| | | } |
| | | else |
| | | { |
| | | return ocMap; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | public byte[] encodeAttribute(Attribute attribute) |
| | | throws DirectoryException |
| | | { |
| | | AttributeType type = attribute.getAttributeType(); |
| | | LinkedHashSet<String> options = attribute.getOptions(); |
| | | |
| | | ConcurrentHashMap<LinkedHashSet<String>,ByteArray> map = |
| | | adEncodeMap.get(type); |
| | | if (map == null) |
| | | { |
| | | byte[] tokenArray; |
| | | synchronized (adEncodeMap) |
| | | { |
| | | map = new ConcurrentHashMap<LinkedHashSet<String>,ByteArray>(1); |
| | | |
| | | int intValue = adCounter.getAndIncrement(); |
| | | tokenArray = encodeInt(intValue); |
| | | ByteArray byteArray = new ByteArray(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); |
| | | |
| | | adEncodeMap.put(type, map); |
| | | atDecodeMap.put(byteArray, type); |
| | | aoDecodeMap.put(byteArray, options); |
| | | } |
| | | |
| | | return encodeAttribute(tokenArray, attribute); |
| | | } |
| | | else |
| | | { |
| | | ByteArray byteArray = map.get(options); |
| | | if (byteArray == null) |
| | | { |
| | | byte[] tokenArray; |
| | | synchronized (map) |
| | | { |
| | | int intValue = adCounter.getAndIncrement(); |
| | | tokenArray = encodeInt(intValue); |
| | | byteArray = new ByteArray(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); |
| | | |
| | | atDecodeMap.put(byteArray, type); |
| | | aoDecodeMap.put(byteArray, options); |
| | | } |
| | | |
| | | return encodeAttribute(tokenArray, attribute); |
| | | } |
| | | else |
| | | { |
| | | return encodeAttribute(byteArray.array(), attribute); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Encodes the information in the provided attribute to a byte |
| | | * array. |
| | | * |
| | | * @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) |
| | | { |
| | | LinkedHashSet<AttributeValue> values = attribute.getValues(); |
| | | int totalValuesLength = 0; |
| | | byte[][] subArrays = new byte[values.size()*2][]; |
| | | int pos = 0; |
| | | for (AttributeValue v : values) |
| | | { |
| | | byte[] vBytes = v.getValueBytes(); |
| | | byte[] lBytes = ASN1Element.encodeLength(vBytes.length); |
| | | |
| | | subArrays[pos++] = lBytes; |
| | | subArrays[pos++] = vBytes; |
| | | |
| | | totalValuesLength += lBytes.length + vBytes.length; |
| | | } |
| | | |
| | | byte[] adArrayLength = ASN1Element.encodeLength(adArray.length); |
| | | byte[] countBytes = ASN1Element.encodeLength(values.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) |
| | | 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); |
| | | } |
| | | } |
| | | |
| | | |
| | | // 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; |
| | | AttributeType attrType = atDecodeMap.get(adArray); |
| | | LinkedHashSet<String> options = aoDecodeMap.get(adArray); |
| | | if ((attrType == null) || (options == null)) |
| | | { |
| | | Message message = ERR_JEB_COMPSCHEMA_UNRECOGNIZED_AD_TOKEN.get( |
| | | bytesToHex(adArray.array())); |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | 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); |
| | | } |
| | | } |
| | | |
| | | |
| | | // Read the appropriate number of values. |
| | | LinkedHashSet<AttributeValue> values = |
| | | new LinkedHashSet<AttributeValue>(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); |
| | | } |
| | | } |
| | | |
| | | byte[] valueBytes = new byte[valueLength]; |
| | | System.arraycopy(encodedEntry, pos, valueBytes, 0, valueLength); |
| | | pos += valueLength; |
| | | values.add(new AttributeValue(attrType, new ASN1OctetString(valueBytes))); |
| | | } |
| | | |
| | | return new Attribute(attrType, attrType.getPrimaryName(), options, values); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Stores the provided key-value pair in the specified database container. |
| | | * |
| | | * @param database The database in which to store the information. |
| | | * @param keyBytes The byte array containing the key to store. |
| | | * @param valueBytes The byte array containing the value to store. |
| | | * |
| | | * @throws DirectoryException If a problem occurs while attempting to store |
| | | * the data. |
| | | */ |
| | | private void store(Database database, byte[] keyBytes, byte[] valueBytes) |
| | | throws DirectoryException |
| | | { |
| | | boolean successful = false; |
| | | DatabaseEntry keyEntry = new DatabaseEntry(keyBytes); |
| | | DatabaseEntry valueEntry = new DatabaseEntry(valueBytes); |
| | | |
| | | for (int i=0; i < 3; i++) |
| | | { |
| | | try |
| | | { |
| | | OperationStatus status = database.putNoOverwrite(null, keyEntry, |
| | | valueEntry); |
| | | if (status == OperationStatus.SUCCESS) |
| | | { |
| | | successful = true; |
| | | break; |
| | | } |
| | | else |
| | | { |
| | | Message m = ERR_JEB_COMPSCHEMA_CANNOT_STORE_STATUS.get( |
| | | status.toString()); |
| | | throw new DirectoryException( |
| | | DirectoryServer.getServerErrorResultCode(), m); |
| | | } |
| | | } |
| | | catch (DeadlockException de) |
| | | { |
| | | continue; |
| | | } |
| | | catch (DatabaseException de) |
| | | { |
| | | Message m = ERR_JEB_COMPSCHEMA_CANNOT_STORE_EX.get(de.getMessage()); |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | m, de); |
| | | } |
| | | } |
| | | |
| | | if (! successful) |
| | | { |
| | | Message m = ERR_JEB_COMPSCHEMA_CANNOT_STORE_MULTIPLE_FAILURES.get(); |
| | | throw new DirectoryException( |
| | | DirectoryServer.getServerErrorResultCode(), m); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * Encodes the provided int value to a byte array. |
| | | * |
| | | * @param intValue The int value to be encoded. |
| | | * |
| | | * @return The byte array containing the encoded int value. |
| | | */ |
| | | private byte[] encodeInt(int intValue) |
| | | { |
| | | byte[] array; |
| | | if (intValue <= 0xFF) |
| | | { |
| | | array = new byte[1]; |
| | | array[0] = (byte) (intValue & 0xFF); |
| | | } |
| | | else if (intValue <= 0xFFFF) |
| | | { |
| | | array = new byte[2]; |
| | | array[0] = (byte) ((intValue >> 8) & 0xFF); |
| | | array[1] = (byte) (intValue & 0xFF); |
| | | } |
| | | else if (intValue <= 0xFFFFFF) |
| | | { |
| | | array = new byte[3]; |
| | | array[0] = (byte) ((intValue >> 16) & 0xFF); |
| | | array[1] = (byte) ((intValue >> 8) & 0xFF); |
| | | array[2] = (byte) (intValue & 0xFF); |
| | | } |
| | | else |
| | | { |
| | | array = new byte[4]; |
| | | array[0] = (byte) ((intValue >> 24) & 0xFF); |
| | | array[1] = (byte) ((intValue >> 16) & 0xFF); |
| | | array[2] = (byte) ((intValue >> 8) & 0xFF); |
| | | array[3] = (byte) (intValue & 0xFF); |
| | | } |
| | | |
| | | return array; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the contents of the provided byte array as an int. |
| | | * |
| | | * @param byteArray The byte array containing the data to decode. |
| | | * |
| | | * @return The decoded int value. |
| | | */ |
| | | private int decodeInt(byte[] byteArray) |
| | | { |
| | | int intValue = 0; |
| | | |
| | | for (byte b : byteArray) |
| | | { |
| | | intValue <<= 8; |
| | | intValue |= (b & 0xFF); |
| | | } |
| | | |
| | | return intValue; |
| | | } |
| | | } |
| | | |