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 021 package org.apache.directory.server.config; 022 023 024 import java.io.BufferedReader; 025 import java.io.File; 026 import java.io.FileNotFoundException; 027 import java.io.FileOutputStream; 028 import java.io.FileReader; 029 import java.io.FileWriter; 030 import java.io.IOException; 031 import java.io.InputStream; 032 import java.util.Map; 033 import java.util.Stack; 034 import java.util.Map.Entry; 035 import java.util.regex.Pattern; 036 037 import org.apache.directory.server.i18n.I18n; 038 import org.apache.directory.shared.ldap.schema.ldif.extractor.impl.DefaultSchemaLdifExtractor; 039 import org.apache.directory.shared.ldap.schema.ldif.extractor.impl.ResourceMap; 040 import org.slf4j.Logger; 041 import org.slf4j.LoggerFactory; 042 043 044 /** 045 * A class to copy the default config to the work directory of a DirectoryService instance. 046 * 047 * NOTE: much of this class code is duplicated from DefaultSchemaLdifExtractor class 048 * We should create a AbstractLdifExtractor class and move the reusable code there 049 * 050 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 051 * @version $Rev$, $Date$ 052 */ 053 public class LdifConfigExtractor 054 { 055 056 private static final String CONFIG_SUBDIR = "config"; 057 058 private static final Logger LOG = LoggerFactory.getLogger( LdifConfigExtractor.class ); 059 060 061 /** 062 * Extracts the LDIF files from a Jar file or copies exploded LDIF resources. 063 * 064 * @param overwrite over write extracted structure if true, false otherwise 065 * @throws IOException if schema already extracted and on IO errors 066 */ 067 public static void extract( File outputDirectory, boolean overwrite ) throws IOException 068 { 069 if ( !outputDirectory.exists() ) 070 { 071 LOG.debug( "creating non existing output directory {}", outputDirectory.getAbsolutePath() ); 072 outputDirectory.mkdir(); 073 } 074 075 File configDirectory = new File( outputDirectory, CONFIG_SUBDIR ); 076 077 if ( !configDirectory.exists() ) 078 { 079 LOG.debug( "creating non existing config directory {}", configDirectory.getAbsolutePath() ); 080 configDirectory.mkdir(); 081 } 082 else if ( !overwrite ) 083 { 084 throw new IOException( I18n.err( I18n.ERR_508, configDirectory.getAbsolutePath() ) ); 085 } 086 087 LOG.info( "extracting the configuration to the directory at {}", configDirectory.getAbsolutePath() ); 088 089 Pattern pattern = Pattern.compile( ".*config/ou=config.*\\.ldif" ); 090 Map<String, Boolean> list = ResourceMap.getResources( pattern ); 091 092 System.out.println( list ); 093 094 for ( Entry<String, Boolean> entry : list.entrySet() ) 095 { 096 if ( entry.getValue() ) 097 { 098 extractFromJar( outputDirectory, entry.getKey() ); 099 } 100 else 101 { 102 File resource = new File( entry.getKey() ); 103 copyFile( resource, getDestinationFile( outputDirectory, resource ) ); 104 } 105 } 106 } 107 108 109 /** 110 * Copies a file line by line from the source file argument to the 111 * destination file argument. 112 * 113 * @param source the source file to copy 114 * @param destination the destination to copy the source to 115 * @throws IOException if there are IO errors or the source does not exist 116 */ 117 private static void copyFile( File source, File destination ) throws IOException 118 { 119 LOG.debug( "copyFile(): source = {}, destination = {}", source, destination ); 120 121 if ( ! destination.getParentFile().exists() ) 122 { 123 destination.getParentFile().mkdirs(); 124 } 125 126 if ( ! source.getParentFile().exists() ) 127 { 128 throw new FileNotFoundException( I18n.err( I18n.ERR_509, source.getAbsolutePath() ) ); 129 } 130 131 FileWriter out = new FileWriter( destination ); 132 BufferedReader in = new BufferedReader( new FileReader( source ) ); 133 String line; 134 while ( null != ( line = in.readLine() ) ) 135 { 136 out.write( line + "\n" ); 137 } 138 139 in.close(); 140 out.flush(); 141 out.close(); 142 } 143 144 /** 145 * Extracts the LDIF schema resource from a Jar. 146 * 147 * @param resource the LDIF schema resource 148 * @throws IOException if there are IO errors 149 */ 150 private static void extractFromJar( File outputDirectory, String resource ) throws IOException 151 { 152 byte[] buf = new byte[512]; 153 InputStream in = DefaultSchemaLdifExtractor.getUniqueResourceAsStream( resource, 154 "LDIF file in config repository" ); 155 156 try 157 { 158 File destination = new File( outputDirectory, resource ); 159 160 /* 161 * Do not overwrite an LDIF file if it has already been extracted. 162 */ 163 if ( destination.exists() ) 164 { 165 return; 166 } 167 168 if ( ! destination.getParentFile().exists() ) 169 { 170 destination.getParentFile().mkdirs(); 171 } 172 173 FileOutputStream out = new FileOutputStream( destination ); 174 try 175 { 176 while ( in.available() > 0 ) 177 { 178 int readCount = in.read( buf ); 179 out.write( buf, 0, readCount ); 180 } 181 out.flush(); 182 } 183 finally 184 { 185 out.close(); 186 } 187 } 188 finally 189 { 190 in.close(); 191 } 192 } 193 194 195 /** 196 * Calculates the destination file. 197 * 198 * @param resource the source file 199 * @return the destination file's parent directory 200 */ 201 private static File getDestinationFile( File outputDirectory, File resource ) 202 { 203 File parent = resource.getParentFile(); 204 Stack<String> fileComponentStack = new Stack<String>(); 205 fileComponentStack.push( resource.getName() ); 206 207 while ( parent != null ) 208 { 209 if ( parent.getName().equals( "config" ) ) 210 { 211 // All LDIF files besides the config.ldif are under the 212 // config/config base path. So we need to add one more 213 // schema component to all LDIF files minus this config.ldif 214 fileComponentStack.push( "config" ); 215 216 return assembleDestinationFile( outputDirectory, fileComponentStack ); 217 } 218 219 fileComponentStack.push( parent.getName() ); 220 221 if ( parent.equals( parent.getParentFile() ) 222 || parent.getParentFile() == null ) 223 { 224 throw new IllegalStateException( I18n.err( I18n.ERR_510 ) ); 225 } 226 227 parent = parent.getParentFile(); 228 } 229 230 throw new IllegalStateException( I18n.err( I18n.ERR_511 ) ); 231 } 232 233 /** 234 * Assembles the destination file by appending file components previously 235 * pushed on the fileComponentStack argument. 236 * 237 * @param fileComponentStack stack containing pushed file components 238 * @return the assembled destination file 239 */ 240 private static File assembleDestinationFile( File outputDirectory, Stack<String> fileComponentStack ) 241 { 242 File destinationFile = outputDirectory.getAbsoluteFile(); 243 244 while ( ! fileComponentStack.isEmpty() ) 245 { 246 destinationFile = new File( destinationFile, fileComponentStack.pop() ); 247 } 248 249 return destinationFile; 250 } 251 252 }