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 try ( InputStream in = getLdifStream() ) 175 { 176 for ( LdifEntry ldifEntry : new LdifReader( in ) ) 177 { 178 Dn dn = ldifEntry.getDn(); 179 180 if ( ldifEntry.isEntry() ) 181 { 182 Entry entry = ldifEntry.getEntry(); 183 boolean filterAccepted = applyFilters( dn, entry ); 184 185 if ( !filterAccepted ) 186 { 187 continue; 188 } 189 190 try 191 { 192 coreSession.lookup( dn ); 193 LOG.info( "Found {}, will not create.", dn ); 194 } 195 catch ( Exception e ) 196 { 197 try 198 { 199 coreSession.add( 200 new DefaultEntry( 201 coreSession.getDirectoryService().getSchemaManager(), entry ) ); 202 count++; 203 LOG.info( "Created {}.", dn ); 204 } 205 catch ( LdapException e1 ) 206 { 207 LOG.info( "Could not create entry " + entry, e1 ); 208 } 209 } 210 } 211 else 212 { 213 //modify 214 List<Modification> items = ldifEntry.getModifications(); 215 216 try 217 { 218 coreSession.modify( dn, items ); 219 LOG.info( "Modified: {} with modificationItems: {}", dn, items ); 220 } 221 catch ( LdapException e ) 222 { 223 LOG.info( "Could not modify: {} with modificationItems: {}", dn, items, e ); 224 } 225 } 226 } 227 } 228 catch ( FileNotFoundException fnfe ) 229 { 230 LOG.error( I18n.err( I18n.ERR_173 ) ); 231 } 232 catch ( Exception ioe ) 233 { 234 LOG.error( I18n.err( I18n.ERR_174 ), ioe ); 235 } 236 237 return count; 238 } 239 240 241 /** 242 * Tries to find an LDIF file either on the file system or packaged within a jar. 243 * 244 * @return the input stream to the ldif file. 245 * @throws FileNotFoundException if the file cannot be found. 246 */ 247 private InputStream getLdifStream() throws IOException 248 { 249 if ( ldif.exists() ) 250 { 251 return Files.newInputStream( ldif.toPath() ); 252 } 253 else 254 { 255 InputStream in; 256 257 // use ldif.getPath() to resolve the relative paths 258 if ( loader != null ) 259 { 260 in = loader.getResourceAsStream( ldif.getPath() ); 261 if ( in != null ) 262 { 263 return in; 264 } 265 } 266 267 // if file not on system see if something is bundled with the jar ... 268 in = getClass().getResourceAsStream( ldif.getPath() ); 269 if ( in != null ) 270 { 271 return in; 272 } 273 274 in = ClassLoader.getSystemResourceAsStream( ldif.getPath() ); 275 if ( in != null ) 276 { 277 return in; 278 } 279 280 throw new FileNotFoundException( I18n.err( I18n.ERR_173 ) ); 281 } 282 } 283}