1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.api.ldap.schema.extractor.impl;
21
22
23 import java.io.File;
24 import java.io.FileNotFoundException;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InvalidObjectException;
28 import java.io.OutputStream;
29 import java.io.OutputStreamWriter;
30 import java.io.Writer;
31 import java.net.URL;
32 import java.nio.charset.Charset;
33 import java.nio.file.Files;
34 import java.nio.file.Paths;
35 import java.util.ArrayDeque;
36 import java.util.Deque;
37 import java.util.Enumeration;
38 import java.util.Map;
39 import java.util.Map.Entry;
40 import java.util.UUID;
41 import java.util.regex.Pattern;
42
43 import org.apache.directory.api.i18n.I18n;
44 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
45 import org.apache.directory.api.ldap.model.exception.LdapException;
46 import org.apache.directory.api.ldap.model.ldif.LdifEntry;
47 import org.apache.directory.api.ldap.model.ldif.LdifReader;
48 import org.apache.directory.api.ldap.schema.extractor.SchemaLdifExtractor;
49 import org.apache.directory.api.ldap.schema.extractor.UniqueResourceException;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53
54
55
56
57
58
59 public class DefaultSchemaLdifExtractor implements SchemaLdifExtractor
60 {
61
62 private static final String BASE_PATH = "";
63
64
65 private static final String SCHEMA_SUBDIR = "schema";
66
67
68 private static final Logger LOG = LoggerFactory.getLogger( DefaultSchemaLdifExtractor.class );
69
70
71
72
73
74 private static final Pattern EXTRACT_PATTERN = Pattern.compile( ".*schema" + "[/\\Q\\\\E]" + "ou=schema.*\\.ldif" );
75
76
77 private boolean extracted;
78
79
80 private File outputDirectory;
81
82
83
84
85
86
87
88
89 public DefaultSchemaLdifExtractor( File outputDirectory )
90 {
91 if ( LOG.isDebugEnabled() )
92 {
93 LOG.debug( I18n.msg( I18n.MSG_16000_BASE_PATH, BASE_PATH, outputDirectory ) );
94 }
95
96 this.outputDirectory = outputDirectory;
97 File schemaDirectory = new File( outputDirectory, SCHEMA_SUBDIR );
98
99 if ( !outputDirectory.exists() )
100 {
101 if ( LOG.isDebugEnabled() )
102 {
103 LOG.debug( I18n.msg( I18n.MSG_16001_CREATING_DIR, outputDirectory ) );
104 }
105
106 if ( !outputDirectory.mkdir() )
107 {
108 LOG.error( I18n.err( I18n.ERR_16042_OUTPUT_DIR_CREATION_FAIL, outputDirectory ) );
109 }
110 }
111 else
112 {
113 if ( LOG.isDebugEnabled() )
114 {
115 LOG.debug( I18n.msg( I18n.MSG_16002_DIR_EXISTS ) );
116 }
117 }
118
119 if ( !schemaDirectory.exists() )
120 {
121 if ( LOG.isInfoEnabled() )
122 {
123 LOG.info( I18n.msg( I18n.MSG_16004_SCHEMA_DIR_ABSENT, schemaDirectory ) );
124 }
125
126 extracted = false;
127 }
128 else
129 {
130 if ( LOG.isInfoEnabled() )
131 {
132 LOG.info( I18n.msg( I18n.MSG_16005_SCHEMA_DIR_PRESENT, schemaDirectory ) );
133 }
134
135 extracted = true;
136 }
137 }
138
139
140
141
142
143
144
145 @Override
146 public boolean isExtracted()
147 {
148 return extracted;
149 }
150
151
152
153
154
155
156
157
158 @Override
159 public void extractOrCopy( boolean overwrite ) throws IOException
160 {
161 if ( !outputDirectory.exists() && !outputDirectory.mkdirs() )
162 {
163 throw new IOException( I18n.err( I18n.ERR_16006_DIRECTORY_CREATION_FAILED, outputDirectory
164 .getAbsolutePath() ) );
165 }
166
167 File schemaDirectory = new File( outputDirectory, SCHEMA_SUBDIR );
168
169 if ( !schemaDirectory.exists() )
170 {
171 if ( !schemaDirectory.mkdirs() )
172 {
173 throw new IOException( I18n.err( I18n.ERR_16006_DIRECTORY_CREATION_FAILED, schemaDirectory
174 .getAbsolutePath() ) );
175 }
176 }
177 else if ( !overwrite )
178 {
179 throw new IOException( I18n.err( I18n.ERR_16000_CANNOT_OVEWRITE_SCHEMA, schemaDirectory.getAbsolutePath() ) );
180 }
181
182 Map<String, Boolean> list = ResourceMap.getResources( EXTRACT_PATTERN );
183
184 for ( Entry<String, Boolean> entry : list.entrySet() )
185 {
186 if ( entry.getValue() )
187 {
188 extractFromClassLoader( entry.getKey() );
189 }
190 else
191 {
192 File resource = new File( entry.getKey() );
193 copyFile( resource, getDestinationFile( resource ) );
194 }
195 }
196 }
197
198
199
200
201
202
203
204
205
206 @Override
207 public void extractOrCopy() throws IOException
208 {
209 extractOrCopy( false );
210 }
211
212
213
214
215
216
217
218
219
220
221 private void copyFile( File source, File destination ) throws IOException
222 {
223 if ( LOG.isDebugEnabled() )
224 {
225 LOG.debug( I18n.msg( I18n.MSG_16003_COPYFILE, source, destination ) );
226 }
227
228 if ( !destination.getParentFile().exists() && !destination.getParentFile().mkdirs() )
229 {
230 throw new IOException( I18n.err( I18n.ERR_16006_DIRECTORY_CREATION_FAILED, destination.getParentFile()
231 .getAbsolutePath() ) );
232 }
233
234 if ( !source.getParentFile().exists() )
235 {
236 throw new FileNotFoundException( I18n.err( I18n.ERR_16001_CANNOT_COPY_NON_EXISTENT, source.getAbsolutePath() ) );
237 }
238
239 try ( Writer out = new OutputStreamWriter( Files.newOutputStream( Paths.get( destination.getPath() ) ),
240 Charset.defaultCharset() );
241 LdifReader ldifReader = new LdifReader( source ) )
242 {
243 boolean first = true;
244 LdifEntry ldifEntry = null;
245
246 while ( ldifReader.hasNext() )
247 {
248 if ( first )
249 {
250 ldifEntry = ldifReader.next();
251
252 if ( ldifEntry.get( SchemaConstants.ENTRY_UUID_AT ) == null )
253 {
254
255 UUID entryUuid = UUID.randomUUID();
256 ldifEntry.addAttribute( SchemaConstants.ENTRY_UUID_AT, entryUuid.toString() );
257 }
258
259 first = false;
260 }
261 else
262 {
263
264 String msg = I18n.err( I18n.ERR_16002_MORE_THAN_ONE_ENTRY, source );
265 LOG.error( msg );
266 throw new InvalidObjectException( msg );
267 }
268 }
269
270
271 String ldifString;
272
273 if ( ldifEntry != null )
274 {
275 ldifString = "version: 1\n" + ldifEntry.toString();
276 }
277 else
278 {
279 ldifString = "version: 1\n";
280 }
281
282 out.write( ldifString );
283 out.flush();
284 }
285 catch ( LdapException le )
286 {
287 String msg = I18n.err( I18n.ERR_16003_ERROR_PARSING_LDIF, source, le.getLocalizedMessage() );
288 LOG.error( msg );
289 throw new InvalidObjectException( msg );
290 }
291 }
292
293
294
295
296
297
298
299
300
301 private File assembleDestinationFile( Deque<String> fileComponentStack )
302 {
303 File destinationFile = outputDirectory.getAbsoluteFile();
304
305 while ( !fileComponentStack.isEmpty() )
306 {
307 destinationFile = new File( destinationFile, fileComponentStack.pop() );
308 }
309
310 return destinationFile;
311 }
312
313
314
315
316
317
318
319
320 private File getDestinationFile( File resource )
321 {
322 File parent = resource.getParentFile();
323 Deque<String> fileComponentStack = new ArrayDeque<>();
324 fileComponentStack.push( resource.getName() );
325
326 while ( parent != null )
327 {
328 if ( "schema".equals( parent.getName() ) )
329 {
330
331
332
333 fileComponentStack.push( "schema" );
334
335 return assembleDestinationFile( fileComponentStack );
336 }
337
338 fileComponentStack.push( parent.getName() );
339
340 if ( parent.equals( parent.getParentFile() ) || parent.getParentFile() == null )
341 {
342 throw new IllegalStateException( I18n.err( I18n.ERR_16004_ROOT_WITHOUT_SCHEMA ) );
343 }
344
345 parent = parent.getParentFile();
346 }
347
348 throw new IllegalStateException( I18n.err( I18n.ERR_16005_PARENT_NULL ) );
349 }
350
351
352
353
354
355
356
357
358
359
360
361
362 public static InputStream getUniqueResourceAsStream( String resourceName, String resourceDescription )
363 throws IOException
364 {
365 URL result = getUniqueResource( BASE_PATH + resourceName, resourceDescription );
366
367 return result.openStream();
368 }
369
370
371
372
373
374
375
376
377
378
379 public static URL getUniqueResource( String resourceName, String resourceDescription ) throws IOException
380 {
381 Enumeration<URL> resources = DefaultSchemaLdifExtractor.class.getClassLoader().getResources( resourceName );
382 if ( !resources.hasMoreElements() )
383 {
384 throw new UniqueResourceException( resourceName, resourceDescription );
385 }
386 URL result = resources.nextElement();
387 if ( resources.hasMoreElements() )
388 {
389 throw new UniqueResourceException( resourceName, result, resources, resourceDescription );
390 }
391 return result;
392 }
393
394
395
396
397
398
399
400
401
402
403
404
405 public static URL getAnyResource( String resourceName, String resourceDescription ) throws IOException
406 {
407 Enumeration<URL> resources = DefaultSchemaLdifExtractor.class.getClassLoader().getResources( resourceName );
408 if ( !resources.hasMoreElements() )
409 {
410 throw new UniqueResourceException( resourceName, resourceDescription );
411 }
412 URL result = resources.nextElement();
413 return result;
414 }
415
416
417
418
419
420
421
422 private void extractFromClassLoader( String resource ) throws IOException
423 {
424 byte[] buf = new byte[512];
425
426 try ( InputStream in = DefaultSchemaLdifExtractor.getUniqueResourceAsStream( resource,
427 "LDIF file in schema repository" ) )
428 {
429 File destination = new File( outputDirectory, resource );
430
431
432
433
434 if ( destination.exists() )
435 {
436 return;
437 }
438
439 if ( !destination.getParentFile().exists() && !destination.getParentFile().mkdirs() )
440 {
441 throw new IOException( I18n.err( I18n.ERR_16006_DIRECTORY_CREATION_FAILED, destination
442 .getParentFile().getAbsolutePath() ) );
443 }
444
445 try ( OutputStream out = Files.newOutputStream( Paths.get( destination.getPath() ) ) )
446
447 {
448 while ( in.available() > 0 )
449 {
450 int readCount = in.read( buf );
451 out.write( buf, 0, readCount );
452 }
453
454 out.flush();
455 }
456 }
457 }
458 }