001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.backends.jeb;
028    import org.opends.messages.Message;
029    
030    import static org.opends.server.loggers.debug.DebugLogger.*;
031    import org.opends.server.loggers.debug.DebugTracer;
032    import static org.opends.messages.JebMessages.*;
033    
034    import com.sleepycat.je.*;
035    
036    import org.opends.server.types.DirectoryException;
037    import org.opends.server.types.Entry;
038    
039    /**
040     * Represents the database containing the LDAP entries. The database key is
041     * the entry ID and the value is the entry contents.
042     *
043     */
044    public class ID2Entry extends DatabaseContainer
045    {
046      /**
047       * The tracer object for the debug logger.
048       */
049      private static final DebugTracer TRACER = getTracer();
050    
051      /**
052       * Parameters for compression and encryption.
053       */
054      private DataConfig dataConfig;
055    
056      /**
057       * Create a new ID2Entry object.
058       *
059       * @param name The name of the entry database.
060       * @param dataConfig The desired compression and encryption options for data
061       * stored in the entry database.
062       * @param env The JE Environment.
063       * @param entryContainer The entryContainer of the entry database.
064       * @throws DatabaseException If an error occurs in the JE database.
065       *
066       */
067      ID2Entry(String name, DataConfig dataConfig,
068               Environment env, EntryContainer entryContainer)
069          throws DatabaseException
070      {
071        super(name, env, entryContainer);
072        this.dataConfig = dataConfig;
073    
074        DatabaseConfig dbNodupsConfig = new DatabaseConfig();
075    
076        if(env.getConfig().getReadOnly())
077        {
078          dbNodupsConfig.setReadOnly(true);
079          dbNodupsConfig.setAllowCreate(false);
080          dbNodupsConfig.setTransactional(false);
081        }
082        else if(!env.getConfig().getTransactional())
083        {
084          dbNodupsConfig.setAllowCreate(true);
085          dbNodupsConfig.setTransactional(false);
086          dbNodupsConfig.setDeferredWrite(true);
087        }
088        else
089        {
090          dbNodupsConfig.setAllowCreate(true);
091          dbNodupsConfig.setTransactional(true);
092        }
093    
094        this.dbConfig = dbNodupsConfig;
095      }
096    
097      /**
098       * Convert an entry to its database format.
099       *
100       * @param entry The LDAP entry to be converted.
101       * @return The database entry.
102       *
103       * @throws  DirectoryException  If a problem occurs while attempting to encode
104       *                              the entry.
105       */
106      public DatabaseEntry entryData(Entry entry)
107              throws DirectoryException
108      {
109        byte[] entryBytes;
110        entryBytes = JebFormat.entryToDatabase(entry, dataConfig);
111        return new DatabaseEntry(entryBytes);
112      }
113    
114      /**
115       * Insert a record into the entry database.
116       *
117       * @param txn The database transaction or null if none.
118       * @param id The entry ID which forms the key.
119       * @param entry The LDAP entry.
120       * @return true if the entry was inserted, false if a record with that
121       *         ID already existed.
122       * @throws DatabaseException If an error occurs in the JE database.
123       * @throws  DirectoryException  If a problem occurs while attempting to encode
124       *                              the entry.
125       */
126      public boolean insert(Transaction txn, EntryID id, Entry entry)
127           throws DatabaseException, DirectoryException
128      {
129        DatabaseEntry key = id.getDatabaseEntry();
130        DatabaseEntry data = entryData(entry);
131    
132        OperationStatus status;
133        status = insert(txn, key, data);
134        if (status != OperationStatus.SUCCESS)
135        {
136          return false;
137        }
138        return true;
139      }
140    
141      /**
142       * Write a record in the entry database.
143       *
144       * @param txn The database transaction or null if none.
145       * @param id The entry ID which forms the key.
146       * @param entry The LDAP entry.
147       * @return true if the entry was written, false if it was not.
148       * @throws DatabaseException If an error occurs in the JE database.
149       * @throws  DirectoryException  If a problem occurs while attempting to encode
150       *                              the entry.
151       */
152      public boolean put(Transaction txn, EntryID id, Entry entry)
153           throws DatabaseException, DirectoryException
154      {
155        DatabaseEntry key = id.getDatabaseEntry();
156        DatabaseEntry data = entryData(entry);
157    
158        OperationStatus status;
159        status = put(txn, key, data);
160        if (status != OperationStatus.SUCCESS)
161        {
162          return false;
163        }
164        return true;
165      }
166    
167      /**
168       * Write a pre-formatted record into the entry database.
169       *
170       * @param txn The database transaction or null if none.
171       * @param key The key containing a pre-formatted entry ID.
172       * @param data The data value containing a pre-formatted LDAP entry.
173       * @return true if the entry was written, false if it was not.
174       * @throws DatabaseException If an error occurs in the JE database.
175       */
176      public boolean putRaw(Transaction txn, DatabaseEntry key, DatabaseEntry data)
177           throws DatabaseException
178      {
179        OperationStatus status;
180        status = put(txn, key, data);
181        if (status != OperationStatus.SUCCESS)
182        {
183          return false;
184        }
185        return true;
186      }
187    
188      /**
189       * Remove a record from the entry database.
190       *
191       * @param txn The database transaction or null if none.
192       * @param id The entry ID which forms the key.
193       * @return true if the entry was removed, false if it was not.
194       * @throws DatabaseException If an error occurs in the JE database.
195       */
196      public boolean remove(Transaction txn, EntryID id)
197           throws DatabaseException
198      {
199        DatabaseEntry key = id.getDatabaseEntry();
200    
201        OperationStatus status = delete(txn, key);
202        if (status != OperationStatus.SUCCESS)
203        {
204          return false;
205        }
206        return true;
207      }
208    
209      /**
210       * Fetch a record from the entry database.
211       *
212       * @param txn The database transaction or null if none.
213       * @param id The desired entry ID which forms the key.
214       * @param lockMode The JE locking mode to be used for the read.
215       * @return The requested entry, or null if there is no such record.
216       * @throws JebException If an error occurs in the JE backend.
217       * @throws DatabaseException If an error occurs in the JE database.
218       */
219      public Entry get(Transaction txn, EntryID id, LockMode lockMode)
220           throws JebException, DatabaseException
221      {
222        DatabaseEntry key = id.getDatabaseEntry();
223        DatabaseEntry data = new DatabaseEntry();
224    
225        OperationStatus status;
226        status = read(txn, key, data,
227                                     LockMode.DEFAULT);
228    
229        if (status != OperationStatus.SUCCESS)
230        {
231          return null;
232        }
233    
234        byte[] entryBytes = data.getData();
235        byte entryVersion = JebFormat.getEntryVersion(entryBytes);
236    
237        //Try to decode the entry based on the version number. On later versions,
238        //a case could be written to upgrade entries if it is not the current
239        //version
240        Entry entry = null;
241        switch(entryVersion)
242        {
243          case JebFormat.FORMAT_VERSION :
244            try
245            {
246              entry = JebFormat.entryFromDatabase(entryBytes,
247                           entryContainer.getRootContainer().getCompressedSchema());
248            }
249            catch (Exception e)
250            {
251              Message message = ERR_JEB_ENTRY_DATABASE_CORRUPT.get(id.toString());
252              throw new JebException(message);
253            }
254            break;
255    
256          //case 0x00                     :
257          //  Call upgrade method? Call 0x00 decode method?
258          default   :
259            Message message =
260                ERR_JEB_INCOMPATIBLE_ENTRY_VERSION.get(id.toString(), entryVersion);
261            throw new JebException(message);
262        }
263    
264        if (entry != null)
265        {
266          entry.processVirtualAttributes();
267        }
268    
269        return entry;
270      }
271    
272      /**
273       * Set the desired compression and encryption options for data
274       * stored in the entry database.
275       *
276       * @param dataConfig The desired compression and encryption options for data
277       * stored in the entry database.
278       */
279      public void setDataConfig(DataConfig dataConfig)
280      {
281        this.dataConfig = dataConfig;
282      }
283    }