View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.protocol.shared.store;
21  
22  
23  import java.io.File;
24  import java.io.FileNotFoundException;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.nio.file.Files;
28  import java.util.Collections;
29  import java.util.List;
30  
31  import org.apache.directory.api.ldap.model.entry.DefaultEntry;
32  import org.apache.directory.api.ldap.model.entry.Entry;
33  import org.apache.directory.api.ldap.model.entry.Modification;
34  import org.apache.directory.api.ldap.model.exception.LdapException;
35  import org.apache.directory.api.ldap.model.ldif.LdifEntry;
36  import org.apache.directory.api.ldap.model.ldif.LdifReader;
37  import org.apache.directory.api.ldap.model.name.Dn;
38  import org.apache.directory.server.core.api.CoreSession;
39  import org.apache.directory.server.i18n.I18n;
40  import org.slf4j.Logger;
41  import org.slf4j.LoggerFactory;
42  
43  
44  /**
45   * Support for commands to load an LDIF file into a DirContext.
46   *
47   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
48   */
49  public class LdifFileLoader
50  {
51      /**
52       * the log for this class
53       */
54      private static final Logger LOG = LoggerFactory.getLogger( LdifFileLoader.class );
55  
56      /**
57       * a handle on the top core session
58       */
59      protected CoreSession coreSession;
60      /**
61       * the LDIF file or directory containing LDIFs to load
62       */
63      protected File ldif;
64      /**
65       * the filters to use while loading entries into the server
66       */
67      protected final List<LdifLoadFilter> filters;
68      /**
69       * the class loader to use if we cannot file the file as a path
70       */
71      protected final ClassLoader loader;
72      /**
73       * the total count of entries loaded
74       */
75      private int count;
76  
77  
78      /**
79       * Creates a new instance of LdifFileLoader.
80       *
81       * @param coreSession  the context to load the entries into.
82       * @param ldif the file of LDIF entries to load.
83       */
84      public LdifFileLoader( CoreSession coreSession, String ldif )
85      {
86          this( coreSession, new File( ldif ), null );
87      }
88  
89  
90      /**
91       * Creates a new instance of LdifFileLoader.
92       *
93       * @param coreSession The CoreSession instance
94       * @param ldif The ldif file to load
95       * @param filters The search filter to use
96       */
97      public LdifFileLoader( CoreSession coreSession, File ldif, List<? extends LdifLoadFilter> filters )
98      {
99          this( coreSession, ldif, filters, null );
100     }
101 
102 
103     /**
104      * Creates a new instance of LdifFileLoader.
105      *
106      * @param coreSession The CoreSession instance
107      * @param ldif The ldif file to load
108      * @param filters The search filter to use
109      * @param loader The LdifLoader to use
110      */
111     public LdifFileLoader( CoreSession coreSession, File ldif, List<? extends LdifLoadFilter> filters,
112         ClassLoader loader )
113     {
114         this.coreSession = coreSession;
115         this.ldif = ldif;
116         this.loader = loader;
117 
118         if ( filters == null )
119         {
120             this.filters = Collections.emptyList();
121         }
122         else
123         {
124             this.filters = Collections.unmodifiableList( filters );
125         }
126     }
127 
128 
129     /**
130      * Applies filters making sure failures in one filter do not effect another.
131      *
132      * @param dn the Dn of the entry
133      * @param entry the attributes of the entry
134      * @return true if all filters passed the entry, false otherwise
135      */
136     private boolean applyFilters( Dn dn, Entry entry )
137     {
138         boolean accept = true;
139         final int limit = filters.size();
140 
141         if ( limit == 0 )
142         {
143             return true;
144         } // don't waste time with loop
145 
146         for ( int ii = 0; ii < limit; ii++ )
147         {
148             try
149             {
150                 accept &= ( filters.get( ii ) ).filter( ldif, dn, entry, coreSession );
151             }
152             catch ( LdapException e )
153             {
154                 LOG.warn( "filter " + filters.get( ii ) + " was bypassed due to failures", e );
155             }
156 
157             // early bypass if entry is rejected
158             if ( !accept )
159             {
160                 return false;
161             }
162         }
163         return true;
164     }
165 
166 
167     /**
168      * Opens the LDIF file and loads the entries into the context.
169      *
170      * @return The count of entries created.
171      */
172     public int execute()
173     {
174         try ( InputStream in = getLdifStream() )
175         {
176             for ( LdifEntry ldifEntry : new LdifReader( in ) )
177             {
178                 Dn dn = ldifEntry.getDn();
179 
180                 if ( ldifEntry.isEntry() )
181                 {
182                     Entry entry = ldifEntry.getEntry();
183                     boolean filterAccepted = applyFilters( dn, entry );
184 
185                     if ( !filterAccepted )
186                     {
187                         continue;
188                     }
189 
190                     try
191                     {
192                         coreSession.lookup( dn );
193                         LOG.info( "Found {}, will not create.", dn );
194                     }
195                     catch ( Exception e )
196                     {
197                         try
198                         {
199                             coreSession.add(
200                                 new DefaultEntry(
201                                     coreSession.getDirectoryService().getSchemaManager(), entry ) );
202                             count++;
203                             LOG.info( "Created {}.", dn );
204                         }
205                         catch ( LdapException e1 )
206                         {
207                             LOG.info( "Could not create entry " + entry, e1 );
208                         }
209                     }
210                 }
211                 else
212                 {
213                     //modify
214                     List<Modification> items = ldifEntry.getModifications();
215 
216                     try
217                     {
218                         coreSession.modify( dn, items );
219                         LOG.info( "Modified: {} with modificationItems: {}", dn, items );
220                     }
221                     catch ( LdapException e )
222                     {
223                         LOG.info( "Could not modify: {} with modificationItems: {}", dn, items, e );
224                     }
225                 }
226             }
227         }
228         catch ( FileNotFoundException fnfe )
229         {
230             LOG.error( I18n.err( I18n.ERR_173 ) );
231         }
232         catch ( Exception ioe )
233         {
234             LOG.error( I18n.err( I18n.ERR_174 ), ioe );
235         }
236 
237         return count;
238     }
239 
240 
241     /**
242      * Tries to find an LDIF file either on the file system or packaged within a jar.
243      *
244      * @return the input stream to the ldif file.
245      * @throws FileNotFoundException if the file cannot be found.
246      */
247     private InputStream getLdifStream() throws IOException
248     {
249         if ( ldif.exists() )
250         {
251             return Files.newInputStream( ldif.toPath() );
252         }
253         else
254         {
255             InputStream in;
256 
257             // use ldif.getPath() to resolve the relative paths
258             if ( loader != null )
259             {
260                 in = loader.getResourceAsStream( ldif.getPath() );
261                 if ( in != null )
262                 {
263                     return in;
264                 }
265             }
266 
267             // if file not on system see if something is bundled with the jar ...
268             in = getClass().getResourceAsStream( ldif.getPath() );
269             if ( in != null )
270             {
271                 return in;
272             }
273 
274             in = ClassLoader.getSystemResourceAsStream( ldif.getPath() );
275             if ( in != null )
276             {
277                 return in;
278             }
279 
280             throw new FileNotFoundException( I18n.err( I18n.ERR_173 ) );
281         }
282     }
283 }