View Javadoc
1   /*
2    *   Licensed to the Apache Software Foundation (ASF) under one
3    *   or more contributor license agreements.  See the NOTICE file
4    *   distributed with this work for additional information
5    *   regarding copyright ownership.  The ASF licenses this file
6    *   to you under the Apache License, Version 2.0 (the
7    *   "License"); you may not use this file except in compliance
8    *   with the License.  You may obtain a copy of the License at
9    *
10   *     https://www.apache.org/licenses/LICENSE-2.0
11   *
12   *   Unless required by applicable law or agreed to in writing,
13   *   software distributed under the License is distributed on an
14   *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *   KIND, either express or implied.  See the License for the
16   *   specific language governing permissions and limitations
17   *   under the License.
18   *
19   */
20  package org.apache.directory.api.ldap.schema.extractor.impl;
21  
22  
23  import java.io.BufferedReader;
24  import java.io.File;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.io.InputStreamReader;
28  import java.net.URL;
29  import java.nio.charset.StandardCharsets;
30  import java.util.Enumeration;
31  import java.util.HashMap;
32  import java.util.Map;
33  import java.util.regex.Pattern;
34  import java.util.zip.ZipEntry;
35  import java.util.zip.ZipFile;
36  
37  import org.apache.directory.api.i18n.I18n;
38  import org.slf4j.Logger;
39  import org.slf4j.LoggerFactory;
40  
41  
42  /**
43   * Lists LDIF resources available from the classpath.
44   *
45   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
46   */
47  public final class ResourceMap
48  {
49      /** the system property which can be used to load schema from a user specified
50       *  resource like a absolute path to a directory or jar file.
51       *  This is useful to start embedded DirectoryService in a servlet container environment
52       *
53       *  usage: -Dschema.resource.location=/tmp/schema
54       *                OR
55       *         -Dschema.resource.location=/tmp/api-ldap-schema-1.0.0-M13.jar
56       *  */
57      private static final String SCHEMA_RESOURCE_LOCATION = "schema.resource.location";
58  
59      /** The logger. */
60      private static final Logger LOG = LoggerFactory.getLogger( ResourceMap.class );
61  
62  
63      /**
64       * Private constructor.
65       */
66      private ResourceMap()
67      {
68      }
69  
70  
71      /**
72       * For all elements of java.class.path OR from the resource name set in the
73       * system property 'schema.resource.location' get a Map of resources
74       * Pattern pattern = Pattern.compile(".*").
75       * The keys represent resource names and the boolean parameter indicates
76       * whether or not the resource is in a Jar file.
77       *
78       * @param pattern the pattern to match
79       * @return the resources with markers - true if resource is in Jar
80       */
81      public static Map<String, Boolean> getResources( Pattern pattern )
82      {
83          HashMap<String, Boolean> retval = new HashMap<>();
84  
85          String schemaResourceLoc = System.getProperty( SCHEMA_RESOURCE_LOCATION, "" );
86  
87          if ( schemaResourceLoc.trim().length() > 0 )
88          {
89              if ( LOG.isDebugEnabled() )
90              {
91                  LOG.debug( I18n.msg( I18n.MSG_16008_LOADING_FROM_USER_SCHEMA, schemaResourceLoc ) );
92              }
93  
94              File file = new File( schemaResourceLoc );
95  
96              if ( file.exists() )
97              {
98                  getResources( retval, schemaResourceLoc, pattern );
99              }
100             else
101             {
102                 LOG.error( I18n.err( I18n.ERR_16043_CANOT_LOAD_SCHEMA, schemaResourceLoc ) );
103             }
104         }
105         else
106         {
107             getResourcesFromClassloader( retval, pattern );
108         }
109 
110         return retval;
111     }
112 
113 
114     private static void getResources( HashMap<String, Boolean> map,
115         String element, Pattern pattern )
116     {
117         File file = new File( element );
118 
119         if ( !file.exists() )
120         {
121             // this may happen if the class path contains an element that doesn't exist
122             if ( LOG.isDebugEnabled() )
123             {
124                 LOG.debug( I18n.msg( I18n.MSG_16009_ELEMENT_DOES_NOT_EXIST, element ) );
125             }
126 
127             return;
128         }
129 
130         if ( file.isDirectory() )
131         {
132             getResourcesFromDirectory( map, file, pattern );
133         }
134         else
135         {
136             getResourcesFromJarFile( map, file, pattern );
137         }
138     }
139 
140 
141     private static void getResourcesFromJarFile( HashMap<String, Boolean> map,
142         File file, Pattern pattern )
143     {
144         ZipFile zf;
145 
146         try
147         {
148             zf = new ZipFile( file );
149         }
150         catch ( IOException e )
151         {
152             throw new Error( e );
153         }
154 
155         Enumeration<? extends ZipEntry> e = zf.entries();
156 
157         while ( e.hasMoreElements() )
158         {
159             ZipEntry ze = e.nextElement();
160             String fileName = ze.getName();
161             boolean accept = pattern.matcher( fileName ).matches();
162 
163             if ( accept )
164             {
165                 map.put( fileName, Boolean.TRUE );
166             }
167         }
168         try
169         {
170             zf.close();
171         }
172         catch ( IOException e1 )
173         {
174             throw new Error( e1 );
175         }
176     }
177 
178 
179     private static void getResourcesFromDirectory(
180         HashMap<String, Boolean> map, File directory, Pattern pattern )
181     {
182         File[] fileList = directory.listFiles();
183 
184         if ( fileList != null )
185         {
186             for ( File file : fileList )
187             {
188                 if ( file.isDirectory() )
189                 {
190                     getResourcesFromDirectory( map, file, pattern );
191                 }
192                 else
193                 {
194                     try
195                     {
196                         String fileName = file.getCanonicalPath();
197                         boolean accept = pattern.matcher( fileName ).matches();
198     
199                         if ( accept )
200                         {
201                             map.put( fileName, Boolean.FALSE );
202                         }
203                     }
204                     catch ( IOException e )
205                     {
206                         LOG.error( I18n.err( I18n.ERR_16044_CANNOT_LOAD_FILE, file.getAbsolutePath(), e.getMessage() ) );
207     
208                         // Continue...
209                     }
210                 }
211             }
212         }
213     }
214 
215 
216     private static void getResourcesFromClassloader( HashMap<String, Boolean> map, Pattern pattern )
217     {
218         try
219         {
220             ClassLoader cl = ResourceMap.class.getClassLoader();
221             Enumeration<URL> indexes = cl.getResources( "META-INF/apacheds-schema.index" );
222 
223             while ( indexes.hasMoreElements() )
224             {
225                 URL index = null;
226 
227                 try
228                 {
229                     index = indexes.nextElement();
230                     
231                     try ( InputStream in = index.openStream() )
232                     {
233                         try ( BufferedReader reader = new BufferedReader( new InputStreamReader( in, StandardCharsets.UTF_8 ) ) )
234                         {
235                             String line = reader.readLine();
236             
237                             while ( line != null )
238                             {
239                                 boolean accept = pattern.matcher( line ).matches();
240             
241                                 if ( accept )
242                                 {
243                                     map.put( line, Boolean.TRUE );
244                                 }
245             
246                                 line = reader.readLine();
247                             }
248                         }        
249                     }
250                 }
251                 catch ( IOException ioe )
252                 {
253                     LOG.error( I18n.err( I18n.ERR_16047_CANNOT_LOAD_RESOURCE, index, ioe.getMessage() ) );
254                     // Continue...
255                 }
256             }
257         }
258         catch ( IOException e )
259         {
260             LOG.error( I18n.err( I18n.ERR_16045_ERROR_LOADING_RESOURCE, e.getMessage() ) );
261             throw new Error( e );
262         }
263     }
264 }