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.File;
024    import java.io.FileInputStream;
025    import java.io.FileNotFoundException;
026    import java.io.InputStream;
027    import java.util.Collections;
028    import java.util.List;
029    
030    import javax.naming.NamingException;
031    
032    import org.apache.directory.server.core.CoreSession;
033    import org.apache.directory.server.i18n.I18n;
034    import org.apache.directory.shared.ldap.entry.DefaultServerEntry;
035    import org.apache.directory.shared.ldap.entry.Entry;
036    import org.apache.directory.shared.ldap.entry.Modification;
037    import org.apache.directory.shared.ldap.ldif.LdifEntry;
038    import org.apache.directory.shared.ldap.ldif.LdifReader;
039    import org.apache.directory.shared.ldap.name.DN;
040    import org.slf4j.Logger;
041    import org.slf4j.LoggerFactory;
042    
043    
044    /**
045     * Support for commands to load an LDIF file into a DirContext.
046     *
047     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
048     * @version $Rev: 927404 $, $Date: 2010-03-25 14:55:18 +0100 (Thu, 25 Mar 2010) $
049     */
050    public class LdifFileLoader
051    {
052        /**
053         * the log for this class
054         */
055        private static final Logger log = LoggerFactory.getLogger( LdifFileLoader.class );
056    
057        /**
058         * a handle on the top core session
059         */
060        protected CoreSession coreSession;
061        /**
062         * the LDIF file or directory containing LDIFs to load
063         */
064        protected File ldif;
065        /**
066         * the filters to use while loading entries into the server
067         */
068        protected final List<LdifLoadFilter> filters;
069        /**
070         * the class loader to use if we cannot file the file as a path
071         */
072        protected final ClassLoader loader;
073        /**
074         * the total count of entries loaded
075         */
076        private int count;
077    
078    
079        /**
080         * Creates a new instance of LdifFileLoader.
081         *
082         * @param ctx  the context to load the entries into.
083         * @param ldif the file of LDIF entries to load.
084         */
085        public LdifFileLoader( CoreSession coreSession, String ldif )
086        {
087            this( coreSession, new File( ldif ), null );
088        }
089    
090    
091        /**
092         * Creates a new instance of LdifFileLoader.
093         *
094         * @param ctx
095         * @param ldif
096         * @param filters
097         */
098        public LdifFileLoader( CoreSession coreSession, File ldif, List<? extends LdifLoadFilter> filters )
099        {
100            this( coreSession, ldif, filters, null );
101        }
102    
103    
104        /**
105         * Creates a new instance of LdifFileLoader.
106         *
107         * @param ctx
108         * @param ldif
109         * @param filters
110         * @param loader
111         */
112        public LdifFileLoader( CoreSession coreSession, File ldif, List<? extends LdifLoadFilter> filters, 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            } else
122            {
123                this.filters = Collections.unmodifiableList( filters );
124            }
125        }
126    
127    
128        /**
129         * Applies filters making sure failures in one filter do not effect another.
130         *
131         * @param dn    the DN of the entry
132         * @param entry the attributes of the entry
133         * @return true if all filters passed the entry, false otherwise
134         */
135        private boolean applyFilters( DN dn, Entry entry )
136        {
137            boolean accept = true;
138            final int limit = filters.size();
139    
140            if ( limit == 0 )
141            {
142                return true;
143            } // don't waste time with loop
144    
145            for ( int ii = 0; ii < limit; ii++ )
146            {
147                try
148                {
149                    accept &= ( filters.get( ii ) ).filter( ldif, dn, entry, coreSession );
150                }
151                catch ( NamingException e )
152                {
153                    log.warn( "filter " + filters.get( ii ) + " was bypassed due to failures", e );
154                }
155    
156                // early bypass if entry is rejected
157                if ( !accept )
158                {
159                    return false;
160                }
161            }
162            return true;
163        }
164    
165    
166        /**
167         * Opens the LDIF file and loads the entries into the context.
168         *
169         * @return The count of entries created.
170         */
171        public int execute()
172        {
173            DN rdn = null;
174            InputStream in = null;
175    
176            try
177            {
178                in = getLdifStream();
179    
180                for ( LdifEntry ldifEntry:new LdifReader( in ) )
181                {
182                    DN dn = ldifEntry.getDn();
183    
184                    if ( ldifEntry.isEntry() )
185                    {
186                        Entry entry = ldifEntry.getEntry();
187                        boolean filterAccepted = applyFilters( dn, entry );
188    
189                        if ( !filterAccepted )
190                        {
191                            continue;
192                        }
193    
194                        try
195                        {
196                            coreSession.lookup( dn );
197                            log.info( "Found {}, will not create.", rdn );
198                        }
199                        catch ( Exception e )
200                        {
201                            try
202                            {
203                                coreSession.add( 
204                                    new DefaultServerEntry( 
205                                        coreSession.getDirectoryService().getSchemaManager(), entry ) ); 
206                               count++;
207                                log.info( "Created {}.", rdn );
208                            } 
209                            catch ( NamingException e1 )
210                            {
211                                log.info( "Could not create entry " + entry, e1 );
212                            }
213                        }
214                    } else
215                    {
216                        //modify
217                        List<Modification> items = ldifEntry.getModificationItems();
218                        
219                        try
220                        {
221                            coreSession.modify( dn, items );
222                            log.info( "Modified: " + dn + " with modificationItems: " + items );
223                        }
224                        catch ( NamingException e )
225                        {
226                            log.info( "Could not modify: " + dn + " with modificationItems: " + items, e );
227                        }
228                    }
229                }
230            }
231            catch ( FileNotFoundException fnfe )
232            {
233                log.error( I18n.err( I18n.ERR_173 ) );
234            }
235            catch ( Exception ioe )
236            {
237                log.error( I18n.err( I18n.ERR_174 ), ioe );
238            }
239            finally
240            {
241                if ( in != null )
242                {
243                    try
244                    {
245                        in.close();
246                    }
247                    catch ( Exception e )
248                    {
249                        log.error( I18n.err( I18n.ERR_175 ), e );
250                    }
251                }
252            }
253    
254            return count;
255        }
256    
257    
258        /**
259         * Tries to find an LDIF file either on the file system or packaged within a jar.
260         *
261         * @return the input stream to the ldif file.
262         * @throws FileNotFoundException if the file cannot be found.
263         */
264        private InputStream getLdifStream() throws FileNotFoundException
265        {
266            InputStream in;
267    
268            if ( ldif.exists() )
269            {
270                in = new FileInputStream( ldif );
271            } else
272            {
273                if ( loader != null && ( in = loader.getResourceAsStream( ldif.getName() ) ) != null )
274                {
275                    return in;
276                }
277    
278                // if file not on system see if something is bundled with the jar ...
279                in = getClass().getResourceAsStream( ldif.getName() );
280                if ( in != null )
281                {
282                    return in;
283                }
284    
285                in = ClassLoader.getSystemResourceAsStream( ldif.getName() );
286                if ( in != null )
287                {
288                    return in;
289                }
290    
291                throw new FileNotFoundException( I18n.err( I18n.ERR_173 ) );
292            }
293    
294            return in;
295        }
296    }