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 */ 020package org.apache.directory.server.protocol.shared.store; 021 022 023import java.io.File; 024import java.io.FileNotFoundException; 025import java.io.IOException; 026import java.io.InputStream; 027import java.nio.file.Files; 028import java.util.Collections; 029import java.util.List; 030 031import org.apache.directory.api.ldap.model.entry.DefaultEntry; 032import org.apache.directory.api.ldap.model.entry.Entry; 033import org.apache.directory.api.ldap.model.entry.Modification; 034import org.apache.directory.api.ldap.model.exception.LdapException; 035import org.apache.directory.api.ldap.model.ldif.LdifEntry; 036import org.apache.directory.api.ldap.model.ldif.LdifReader; 037import org.apache.directory.api.ldap.model.name.Dn; 038import org.apache.directory.server.core.api.CoreSession; 039import org.apache.directory.server.i18n.I18n; 040import org.slf4j.Logger; 041import 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 */ 049public class LdifFileLoader 050{ 051 /** 052 * the log for this class 053 */ 054 private static final Logger LOG = LoggerFactory.getLogger( LdifFileLoader.class ); 055 056 /** 057 * a handle on the top core session 058 */ 059 protected CoreSession coreSession; 060 /** 061 * the LDIF file or directory containing LDIFs to load 062 */ 063 protected File ldif; 064 /** 065 * the filters to use while loading entries into the server 066 */ 067 protected final List<LdifLoadFilter> filters; 068 /** 069 * the class loader to use if we cannot file the file as a path 070 */ 071 protected final ClassLoader loader; 072 /** 073 * the total count of entries loaded 074 */ 075 private int count; 076 077 078 /** 079 * Creates a new instance of LdifFileLoader. 080 * 081 * @param coreSession the context to load the entries into. 082 * @param ldif the file of LDIF entries to load. 083 */ 084 public LdifFileLoader( CoreSession coreSession, String ldif ) 085 { 086 this( coreSession, new File( ldif ), null ); 087 } 088 089 090 /** 091 * Creates a new instance of LdifFileLoader. 092 * 093 * @param coreSession The CoreSession instance 094 * @param ldif The ldif file to load 095 * @param filters The search filter to use 096 */ 097 public LdifFileLoader( CoreSession coreSession, File ldif, List<? extends LdifLoadFilter> filters ) 098 { 099 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 InputStream in = null; 175 176 try 177 { 178 in = getLdifStream(); 179 180 try 181 { 182 for ( LdifEntry ldifEntry : new LdifReader( in ) ) 183 { 184 Dn dn = ldifEntry.getDn(); 185 186 if ( ldifEntry.isEntry() ) 187 { 188 Entry entry = ldifEntry.getEntry(); 189 boolean filterAccepted = applyFilters( dn, entry ); 190 191 if ( !filterAccepted ) 192 { 193 continue; 194 } 195 196 try 197 { 198 coreSession.lookup( dn ); 199 LOG.info( "Found {}, will not create.", dn ); 200 } 201 catch ( Exception e ) 202 { 203 try 204 { 205 coreSession.add( 206 new DefaultEntry( 207 coreSession.getDirectoryService().getSchemaManager(), entry ) ); 208 count++; 209 LOG.info( "Created {}.", dn ); 210 } 211 catch ( LdapException e1 ) 212 { 213 LOG.info( "Could not create entry " + entry, e1 ); 214 } 215 } 216 } 217 else 218 { 219 //modify 220 List<Modification> items = ldifEntry.getModifications(); 221 222 try 223 { 224 coreSession.modify( dn, items ); 225 LOG.info( "Modified: " + dn + " with modificationItems: " + items ); 226 } 227 catch ( LdapException e ) 228 { 229 LOG.info( "Could not modify: " + dn + " with modificationItems: " + items, e ); 230 } 231 } 232 } 233 } 234 finally 235 { 236 if ( in != null ) 237 { 238 try 239 { 240 in.close(); 241 } 242 catch ( Exception e ) 243 { 244 LOG.error( I18n.err( I18n.ERR_175 ), e ); 245 } 246 } 247 } 248 } 249 catch ( FileNotFoundException fnfe ) 250 { 251 LOG.error( I18n.err( I18n.ERR_173 ) ); 252 } 253 catch ( Exception ioe ) 254 { 255 LOG.error( I18n.err( I18n.ERR_174 ), ioe ); 256 } 257 258 return count; 259 } 260 261 262 /** 263 * Tries to find an LDIF file either on the file system or packaged within a jar. 264 * 265 * @return the input stream to the ldif file. 266 * @throws FileNotFoundException if the file cannot be found. 267 */ 268 private InputStream getLdifStream() throws FileNotFoundException, IOException 269 { 270 if ( ldif.exists() ) 271 { 272 return Files.newInputStream( ldif.toPath() ); 273 } 274 else 275 { 276 InputStream in; 277 278 // use ldif.getPath() to resolve the relative paths 279 if ( loader != null ) 280 { 281 in = loader.getResourceAsStream( ldif.getPath() ); 282 if ( in != null ) 283 { 284 return in; 285 } 286 } 287 288 // if file not on system see if something is bundled with the jar ... 289 in = getClass().getResourceAsStream( ldif.getPath() ); 290 if ( in != null ) 291 { 292 return in; 293 } 294 295 in = ClassLoader.getSystemResourceAsStream( ldif.getPath() ); 296 if ( in != null ) 297 { 298 return in; 299 } 300 301 throw new FileNotFoundException( I18n.err( I18n.ERR_173 ) ); 302 } 303 } 304}