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.importLDIF;
028    
029    import org.opends.server.types.DN;
030    import org.opends.server.types.LDIFImportConfig;
031    import org.opends.server.types.AttributeType;
032    import org.opends.server.util.LDIFReader;
033    import org.opends.server.admin.std.server.LocalDBBackendCfg;
034    import org.opends.server.backends.jeb.*;
035    
036    import com.sleepycat.je.DatabaseException;
037    import com.sleepycat.je.Transaction;
038    import com.sleepycat.je.LockMode;
039    
040    import java.util.concurrent.BlockingQueue;
041    import java.util.concurrent.ConcurrentHashMap;
042    import java.util.concurrent.atomic.AtomicLong;
043    import java.util.*;
044    
045    /**
046     * This class represents the import context for a destination base DN.
047     */
048    public class DNContext {
049    
050      /**
051       * The destination base DN.
052       */
053      private DN baseDN;
054    
055      /**
056       * The include branches below the base DN.
057       */
058      private List<DN> includeBranches;
059    
060      /**
061       * The exclude branches below the base DN.
062       */
063      private List<DN> excludeBranches;
064    
065      /**
066       * The configuration of the destination backend.
067       */
068      private LocalDBBackendCfg config;
069    
070      /**
071       * The requested LDIF import configuration.
072       */
073      private LDIFImportConfig ldifImportConfig;
074    
075      /**
076       * A reader for the source LDIF file.
077       */
078      private LDIFReader ldifReader;
079    
080      /**
081       * The entry entryContainer for the destination base DN.
082       */
083      private EntryContainer entryContainer;
084    
085      /**
086       * The source entryContainer if this is a partial import of a base DN.
087       */
088      private EntryContainer srcEntryContainer;
089    
090      /**
091       * A queue of elements that have been read from the LDIF and are ready
092       * to be imported.
093       */
094    
095      private BlockingQueue<WorkElement> workQueue;
096    
097    
098      //This currently isn't used.
099      private ArrayList<VLVIndex> vlvIndexes = new ArrayList<VLVIndex>();
100    
101      /**
102       * The maximum number of parent ID values that we will remember.
103       */
104      private static final int PARENT_ID_MAP_SIZE = 100;
105    
106      /**
107       * Map of likely parent entry DNs to their entry IDs.
108       */
109      private HashMap<DN,EntryID> parentIDMap =
110           new HashMap<DN,EntryID>(PARENT_ID_MAP_SIZE);
111    
112      //Map of pending DNs added to the work queue. Used to check if a parent
113      //entry has been added, but isn't in the dn2id DB.
114      private ConcurrentHashMap<DN,DN> pendingMap =
115                                                  new ConcurrentHashMap<DN, DN>() ;
116    
117      //Used to synchronize the parent ID map, since multiple worker threads
118      //can be accessing it.
119      private Object synchObject = new Object();
120    
121      /**
122       * The number of LDAP entries added to the database, used to update the
123       * entry database record count after import.  The value is not updated
124       * for replaced entries.  Multiple threads may be updating this value.
125       */
126      private AtomicLong entryInsertCount = new AtomicLong(0);
127    
128      /**
129       * The parent DN of the previous imported entry.
130       */
131      private DN parentDN;
132    
133      /**
134       * The superior IDs, in order from the parent up to the base DN, of the
135       * previous imported entry. This is used together with the previous parent DN
136       * to save time constructing the subtree index, in the typical case where many
137       * contiguous entries from the LDIF file have the same parent.
138       */
139      private ArrayList<EntryID> IDs;
140    
141      //The buffer manager used to hold the substring cache.
142      private BufferManager bufferManager;
143    
144    
145      /**
146       * Get the work queue.
147       *
148       * @return  The work queue.
149       */
150      public BlockingQueue<WorkElement> getWorkQueue() {
151          return workQueue;
152        }
153    
154    
155      /**
156       * Set the work queue to the specified work queue.
157       *
158       * @param workQueue The work queue.
159       */
160      public void
161       setWorkQueue(BlockingQueue<WorkElement> workQueue) {
162        this.workQueue = workQueue;
163      }
164    
165      /**
166       * Set the destination base DN.
167       * @param baseDN The destination base DN.
168       */
169      public void setBaseDN(DN baseDN)
170      {
171        this.baseDN = baseDN;
172      }
173    
174      /**
175       * Get the destination base DN.
176       * @return The destination base DN.
177       */
178      public DN getBaseDN()
179      {
180        return baseDN;
181      }
182    
183      /**
184       * Set the configuration of the destination backend.
185       * @param config The destination backend configuration.
186       */
187      public void setConfig(LocalDBBackendCfg config)
188      {
189        this.config = config;
190      }
191    
192      /**
193       * Get the configuration of the destination backend.
194       * @return The destination backend configuration.
195       */
196      public LocalDBBackendCfg getConfig()
197      {
198        return config;
199      }
200    
201      /**
202       * Set the requested LDIF import configuration.
203       * @param ldifImportConfig The LDIF import configuration.
204       */
205      public void setLDIFImportConfig(LDIFImportConfig ldifImportConfig)
206      {
207        this.ldifImportConfig = ldifImportConfig;
208      }
209    
210      /**
211       * Get the requested LDIF import configuration.
212       * @return The requested LDIF import configuration.
213       */
214      public LDIFImportConfig getLDIFImportConfig()
215      {
216        return ldifImportConfig;
217      }
218    
219      /**
220       * Set the source LDIF reader.
221       * @param ldifReader The source LDIF reader.
222       */
223      public void setLDIFReader(LDIFReader ldifReader)
224      {
225        this.ldifReader = ldifReader;
226      }
227    
228      /**
229       * Get the source LDIF reader.
230       * @return The source LDIF reader.
231       */
232      public LDIFReader getLDIFReader()
233      {
234        return ldifReader;
235      }
236    
237      /**
238       * Set the entry entryContainer for the destination base DN.
239       * @param entryContainer The entry entryContainer for the destination base DN.
240       */
241      public void setEntryContainer(EntryContainer entryContainer)
242      {
243        this.entryContainer = entryContainer;
244      }
245    
246      /**
247       * Get the entry entryContainer for the destination base DN.
248       * @return The entry entryContainer for the destination base DN.
249       */
250      public EntryContainer getEntryContainer()
251      {
252        return entryContainer;
253      }
254    
255      /**
256       * Set the source entry entryContainer for the destination base DN.
257       * @param srcEntryContainer The entry source entryContainer for the
258       * destination base DN.
259       */
260      public void setSrcEntryContainer(EntryContainer srcEntryContainer)
261      {
262        this.srcEntryContainer = srcEntryContainer;
263      }
264    
265      /**
266       * Get the source entry entryContainer for the destination base DN.
267       * @return The source entry entryContainer for the destination base DN.
268       */
269      public EntryContainer getSrcEntryContainer()
270      {
271        return srcEntryContainer;
272      }
273    
274      /**
275       * Get the number of new LDAP entries imported into the entry database.
276       * @return The number of new LDAP entries imported into the entry database.
277       */
278      public long getEntryInsertCount()
279      {
280        return entryInsertCount.get();
281      }
282    
283      /**
284       * Increment the number of new LDAP entries imported into the entry database
285       * by the given amount.
286       * @param delta The amount to add.
287       */
288      public void incrEntryInsertCount(long delta)
289      {
290        entryInsertCount.getAndAdd(delta);
291      }
292    
293      /**
294       * Get the parent DN of the previous imported entry.
295       * @return The parent DN of the previous imported entry.
296       */
297      public DN getParentDN()
298      {
299        return parentDN;
300      }
301    
302      /**
303       * Set the parent DN of the previous imported entry.
304       * @param parentDN The parent DN of the previous imported entry.
305       */
306      public void setParentDN(DN parentDN)
307      {
308        this.parentDN = parentDN;
309      }
310    
311      /**
312       * Get the superior IDs of the previous imported entry.
313       * @return The superior IDs of the previous imported entry.
314       */
315      public ArrayList<EntryID> getIDs()
316      {
317        return IDs;
318      }
319    
320      /**
321       * Set the superior IDs of the previous imported entry.
322       * @param IDs The superior IDs of the previous imported entry.
323       */
324      public void setIDs(ArrayList<EntryID> IDs)
325      {
326        this.IDs = IDs;
327      }
328    
329      /**
330         * Retrieves the set of base DNs that specify the set of entries to
331         * exclude from the import.  The contents of the returned list may
332         * be altered by the caller.
333         *
334         * @return  The set of base DNs that specify the set of entries to
335         *          exclude from the import.
336         */
337        public List<DN> getExcludeBranches()
338        {
339          return excludeBranches;
340        }
341    
342    
343    
344        /**
345         * Specifies the set of base DNs that specify the set of entries to
346         * exclude from the import.
347         *
348         * @param  excludeBranches  The set of base DNs that specify the set
349         *                          of entries to exclude from the import.
350         */
351        public void setExcludeBranches(List<DN> excludeBranches)
352        {
353          if (excludeBranches == null)
354          {
355            this.excludeBranches = new ArrayList<DN>(0);
356          }
357          else
358          {
359            this.excludeBranches = excludeBranches;
360          }
361        }
362    
363    
364    
365        /**
366         * Retrieves the set of base DNs that specify the set of entries to
367         * include in the import.  The contents of the returned list may be
368         * altered by the caller.
369         *
370         * @return  The set of base DNs that specify the set of entries to
371         *          include in the import.
372         */
373        public List<DN> getIncludeBranches()
374        {
375          return includeBranches;
376        }
377    
378    
379    
380        /**
381         * Specifies the set of base DNs that specify the set of entries to
382         * include in the import.
383         *
384         * @param  includeBranches  The set of base DNs that specify the set
385         *                          of entries to include in the import.
386         */
387        public void setIncludeBranches(List<DN> includeBranches)
388        {
389          if (includeBranches == null)
390          {
391            this.includeBranches = new ArrayList<DN>(0);
392          }
393          else
394          {
395            this.includeBranches = includeBranches;
396          }
397        }
398    
399    
400        /**
401         * Return the attribute type attribute index map.
402         *
403         * @return The attribute type attribute index map.
404         */
405        public Map<AttributeType, AttributeIndex> getAttrIndexMap() {
406          return entryContainer.getAttributeIndexMap();
407        }
408    
409        /**
410         * Set all the indexes to trusted.
411         *
412         * @throws DatabaseException If the trusted value cannot be updated in the
413         * index DB.
414         */
415        public void setIndexesTrusted() throws DatabaseException {
416          entryContainer.getID2Children().setTrusted(null,true);
417          entryContainer.getID2Subtree().setTrusted(null, true);
418          for(AttributeIndex attributeIndex :
419              entryContainer.getAttributeIndexes()) {
420            Index index;
421            if((index = attributeIndex.getEqualityIndex()) != null) {
422              index.setTrusted(null, true);
423            }
424            if((index=attributeIndex.getPresenceIndex()) != null) {
425              index.setTrusted(null, true);
426            }
427            if((index=attributeIndex.getSubstringIndex()) != null) {
428              index.setTrusted(null, true);
429            }
430            if((index=attributeIndex.getOrderingIndex()) != null) {
431              index.setTrusted(null, true);
432            }
433            if((index=attributeIndex.getApproximateIndex()) != null) {
434              index.setTrusted(null, true);
435            }
436          }
437        }
438    
439    
440        /**
441         * Get the Entry ID of the parent entry.
442         * @param parentDN  The parent DN.
443         * @param dn2id The DN2ID DB.
444         * @param txn A database transaction,
445         * @return The entry ID of the parent entry.
446         * @throws DatabaseException If a DB error occurs.
447         */
448        public
449        EntryID getParentID(DN parentDN, DN2ID dn2id, Transaction txn)
450                throws DatabaseException {
451          EntryID parentID;
452          synchronized(synchObject) {
453            parentID = parentIDMap.get(parentDN);
454            if (parentID != null) {
455              return parentID;
456            }
457          }
458          int i=0;
459          //If the parent is in the pending map, another thread is working on the
460          //parent entry; wait until that thread is done with the parent.
461          while(isPending(parentDN)) {
462            try {
463              Thread.sleep(50);
464              if(i == 3) {
465                return null;
466              }
467              i++;
468            } catch (Exception e) {
469              return null;
470            }
471          }
472          parentID = dn2id.get(txn, parentDN, LockMode.DEFAULT);
473          //If the parent is in dn2id, add it to the cache.
474          if (parentID != null) {
475            synchronized(synchObject) {
476              if (parentIDMap.size() >= PARENT_ID_MAP_SIZE) {
477                Iterator<DN> iterator = parentIDMap.keySet().iterator();
478                iterator.next();
479                iterator.remove();
480              }
481              parentIDMap.put(parentDN, parentID);
482            }
483          }
484          return parentID;
485        }
486    
487        /**
488         * Check if the parent DN is in the pending map.
489         *
490         * @param parentDN The DN of the parent.
491         * @return <CODE>True</CODE> if the parent is in the pending map.
492         */
493        private boolean isPending(DN parentDN) {
494          boolean ret = false;
495          if(pendingMap.containsKey(parentDN)) {
496            ret = true;
497          }
498          return ret;
499        }
500    
501        /**
502         * Add specified DN to the pending map.
503         *
504         * @param dn The DN to add to the map.
505         */
506        public void addPending(DN dn) {
507          pendingMap.putIfAbsent(dn, dn);
508        }
509    
510        /**
511         * Remove the specified DN from the pending map.
512         *
513         * @param dn The DN to remove from the map.
514         */
515        public void removePending(DN dn) {
516          pendingMap.remove(dn);
517        }
518    
519        /**
520         * Set the substring buffer manager to the specified buffer manager.
521         *
522         * @param bufferManager The buffer manager.
523         */
524        public void setBufferManager(BufferManager bufferManager) {
525          this.bufferManager = bufferManager;
526        }
527    
528        /**
529         * Return the buffer manager.
530         *
531         * @return The buffer manager.
532         */
533        public BufferManager getBufferManager() {
534          return bufferManager;
535        }
536      }