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.core.entry.DefaultServerEntry;
034 import org.apache.directory.server.i18n.I18n;
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: 918774 $, $Date: 2010-03-04 00:33:13 +0100 (Jeu, 04 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 }