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 }