001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.server.protocol.shared.store;
021    
022    
023    import java.io.BufferedReader;
024    import java.io.File;
025    import java.io.FileInputStream;
026    import java.io.FileNotFoundException;
027    import java.io.InputStream;
028    import java.io.InputStreamReader;
029    import java.util.Collections;
030    import java.util.List;
031    
032    import javax.naming.NamingException;
033    
034    import org.apache.directory.server.core.CoreSession;
035    import org.apache.directory.server.core.entry.DefaultServerEntry;
036    import org.apache.directory.shared.ldap.entry.Entry;
037    import org.apache.directory.shared.ldap.entry.Modification;
038    import org.apache.directory.shared.ldap.ldif.LdifEntry;
039    import org.apache.directory.shared.ldap.ldif.LdifReader;
040    import org.apache.directory.shared.ldap.name.LdapDN;
041    import org.slf4j.Logger;
042    import org.slf4j.LoggerFactory;
043    
044    
045    /**
046     * Support for commands to load an LDIF file into a DirContext.
047     *
048     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
049     * @version $Rev: 686082 $, $Date: 2008-08-15 02:12:09 +0300 (Fri, 15 Aug 2008) $
050     */
051    public class LdifFileLoader
052    {
053        /**
054         * the log for this class
055         */
056        private static final Logger log = LoggerFactory.getLogger( LdifFileLoader.class );
057    
058        /**
059         * a handle on the top core session
060         */
061        protected CoreSession coreSession;
062        /**
063         * the LDIF file or directory containing LDIFs to load
064         */
065        protected File ldif;
066        /**
067         * the filters to use while loading entries into the server
068         */
069        protected final List<LdifLoadFilter> filters;
070        /**
071         * the class loader to use if we cannot file the file as a path
072         */
073        protected final ClassLoader loader;
074        /**
075         * the total count of entries loaded
076         */
077        private int count;
078    
079    
080        /**
081         * Creates a new instance of LdifFileLoader.
082         *
083         * @param ctx  the context to load the entries into.
084         * @param ldif the file of LDIF entries to load.
085         */
086        public LdifFileLoader( CoreSession coreSession, String ldif )
087        {
088            this( coreSession, new File( ldif ), null );
089        }
090    
091    
092        /**
093         * Creates a new instance of LdifFileLoader.
094         *
095         * @param ctx
096         * @param ldif
097         * @param filters
098         */
099        public LdifFileLoader( CoreSession coreSession, File ldif, List<? extends LdifLoadFilter> filters )
100        {
101            this( coreSession, ldif, filters, null );
102        }
103    
104    
105        /**
106         * Creates a new instance of LdifFileLoader.
107         *
108         * @param ctx
109         * @param ldif
110         * @param filters
111         * @param loader
112         */
113        public LdifFileLoader( CoreSession coreSession, File ldif, List<? extends LdifLoadFilter> filters, ClassLoader loader )
114        {
115            this.coreSession = coreSession;
116            this.ldif = ldif;
117            this.loader = loader;
118    
119            if ( filters == null )
120            {
121                this.filters = Collections.emptyList();
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( LdapDN 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 ( NamingException 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            LdapDN rdn = null;
175            InputStream in = null;
176    
177            try
178            {
179                in = getLdifStream();
180    
181                for ( LdifEntry ldifEntry:new LdifReader( new BufferedReader( new InputStreamReader( in ) ) ) )
182                {
183                    LdapDN dn = ldifEntry.getDn();
184    
185                    if ( ldifEntry.isEntry() )
186                    {
187                        Entry entry = ldifEntry.getEntry();
188                        boolean filterAccepted = applyFilters( dn, entry );
189    
190                        if ( !filterAccepted )
191                        {
192                            continue;
193                        }
194    
195                        try
196                        {
197                            coreSession.lookup( dn );
198                            log.info( "Found {}, will not create.", rdn );
199                        }
200                        catch ( Exception e )
201                        {
202                            try
203                            {
204                                coreSession.add( 
205                                    new DefaultServerEntry( 
206                                        coreSession.getDirectoryService().getRegistries(), entry ) ); 
207                               count++;
208                                log.info( "Created {}.", rdn );
209                            } 
210                            catch ( NamingException e1 )
211                            {
212                                log.info( "Could not create entry " + entry, e1 );
213                            }
214                        }
215                    } else
216                    {
217                        //modify
218                        List<Modification> items = ldifEntry.getModificationItems();
219                        
220                        try
221                        {
222                            coreSession.modify( dn, items );
223                            log.info( "Modified: " + dn + " with modificationItems: " + items );
224                        }
225                        catch ( NamingException e )
226                        {
227                            log.info( "Could not modify: " + dn + " with modificationItems: " + items, e );
228                        }
229                    }
230                }
231            }
232            catch ( FileNotFoundException fnfe )
233            {
234                log.error( "LDIF file does not exist." );
235            }
236            catch ( Exception ioe )
237            {
238                log.error( "Failed to import LDIF into backing store.", ioe );
239            }
240            finally
241            {
242                if ( in != null )
243                {
244                    try
245                    {
246                        in.close();
247                    }
248                    catch ( Exception e )
249                    {
250                        log.error( "failed to close stream", e );
251                    }
252                }
253            }
254    
255            return count;
256        }
257    
258    
259        /**
260         * Tries to find an LDIF file either on the file system or packaged within a jar.
261         *
262         * @return the input stream to the ldif file.
263         * @throws FileNotFoundException if the file cannot be found.
264         */
265        private InputStream getLdifStream() throws FileNotFoundException
266        {
267            InputStream in;
268    
269            if ( ldif.exists() )
270            {
271                in = new FileInputStream( ldif );
272            } else
273            {
274                if ( loader != null && ( in = loader.getResourceAsStream( ldif.getName() ) ) != null )
275                {
276                    return in;
277                }
278    
279                // if file not on system see if something is bundled with the jar ...
280                in = getClass().getResourceAsStream( ldif.getName() );
281                if ( in != null )
282                {
283                    return in;
284                }
285    
286                in = ClassLoader.getSystemResourceAsStream( ldif.getName() );
287                if ( in != null )
288                {
289                    return in;
290                }
291    
292                throw new FileNotFoundException( "LDIF file does not exist." );
293            }
294    
295            return in;
296        }
297    }