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.shared.ldap.schemaextractor.impl;
021
022
023import java.io.BufferedReader;
024import java.io.File;
025import java.io.IOException;
026import java.io.InputStream;
027import java.io.InputStreamReader;
028import java.net.URL;
029import java.util.Enumeration;
030import java.util.HashMap;
031import java.util.Map;
032import java.util.regex.Pattern;
033import java.util.zip.ZipEntry;
034import java.util.zip.ZipException;
035import java.util.zip.ZipFile;
036
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039
040
041/**
042 * Lists LDIF resources available from the classpath.
043 *
044 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
045 */
046public final class ResourceMap
047{
048    /** the system property which can be used to load schema from a user specified
049     *  resource like a absolute path to a directory or jar file.
050     *  This is useful to start embedded DirectoryService in a servlet container environment
051     *
052     *  usage: -Dschema.resource.location=/tmp/schema
053     *                OR
054     *         -Dschema.resource.location=/tmp/shared-ldap-schema-0.9.18.jar
055     *  */
056    private static final String SCHEMA_RESOURCE_LOCATION = "schema.resource.location";
057
058    /** The logger. */
059    private static final Logger LOG = LoggerFactory.getLogger( ResourceMap.class );
060
061
062    /**
063     * Private contstructor.
064     */
065    private ResourceMap()
066    {
067    }
068
069
070    /**
071     * For all elements of java.class.path OR from the resource name set in the
072     * system property 'schema.resource.location' get a Map of resources
073     * Pattern pattern = Pattern.compile(".*").
074     * The keys represent resource names and the boolean parameter indicates
075     * whether or not the resource is in a Jar file.
076     *
077     * @param pattern the pattern to match
078     * @return the resources with markers - true if resource is in Jar
079     */
080    public static Map<String, Boolean> getResources( Pattern pattern )
081    {
082        HashMap<String, Boolean> retval = new HashMap<String, Boolean>();
083
084        String schemaResourceLoc = System.getProperty( SCHEMA_RESOURCE_LOCATION, "" );
085
086        if ( schemaResourceLoc.trim().length() > 0 )
087        {
088            LOG.debug( "loading from the user provider schema resource {}", schemaResourceLoc );
089
090            File file = new File( schemaResourceLoc );
091            if ( file.exists() )
092            {
093                getResources( retval, schemaResourceLoc, pattern );
094            }
095            else
096            {
097                LOG.error( "unable to load schema from the given resource value {}", schemaResourceLoc );
098            }
099        }
100        else
101        {
102            getResourcesFromClassloader( retval, pattern );
103        }
104
105        return retval;
106    }
107
108
109    private static void getResources( HashMap<String, Boolean> map,
110        String element, Pattern pattern )
111    {
112        File file = new File( element );
113        if ( !file.exists() )
114        {
115            // this may happen if the class path contains an element that doesn't exist
116            LOG.debug( "element {} does not exist", element );
117            return;
118        }
119
120        if ( file.isDirectory() )
121        {
122            getResourcesFromDirectory( map, file, pattern );
123        }
124        else
125        {
126            getResourcesFromJarFile( map, file, pattern );
127        }
128    }
129
130
131    private static void getResourcesFromJarFile( HashMap<String, Boolean> map,
132        File file, Pattern pattern )
133    {
134        ZipFile zf;
135
136        try
137        {
138            zf = new ZipFile( file );
139        }
140        catch ( ZipException e )
141        {
142            throw new Error( e );
143        }
144        catch ( IOException e )
145        {
146            throw new Error( e );
147        }
148
149        Enumeration<? extends ZipEntry> e = zf.entries();
150
151        while ( e.hasMoreElements() )
152        {
153            ZipEntry ze = e.nextElement();
154            String fileName = ze.getName();
155            boolean accept = pattern.matcher( fileName ).matches();
156
157            if ( accept )
158            {
159                map.put( fileName, Boolean.TRUE );
160            }
161        }
162        try
163        {
164            zf.close();
165        }
166        catch ( IOException e1 )
167        {
168            throw new Error( e1 );
169        }
170    }
171
172
173    private static void getResourcesFromDirectory(
174        HashMap<String, Boolean> map, File directory, Pattern pattern )
175    {
176        File[] fileList = directory.listFiles();
177
178        for ( File file : fileList )
179        {
180            if ( file.isDirectory() )
181            {
182                getResourcesFromDirectory( map, file, pattern );
183            }
184            else
185            {
186                try
187                {
188                    String fileName = file.getCanonicalPath();
189                    boolean accept = pattern.matcher( fileName ).matches();
190
191                    if ( accept )
192                    {
193                        map.put( fileName, Boolean.FALSE );
194                    }
195                }
196                catch ( IOException e )
197                {
198                    throw new Error( e );
199                }
200            }
201        }
202    }
203
204
205    private static void getResourcesFromClassloader( HashMap<String, Boolean> map, Pattern pattern )
206    {
207        try
208        {
209            ClassLoader cl = ResourceMap.class.getClassLoader();
210            Enumeration<URL> indexes = cl.getResources( "META-INF/apacheds-schema.index" );
211            while(indexes.hasMoreElements()) {
212                URL index = indexes.nextElement();
213                InputStream in = index.openStream();
214                BufferedReader reader = new BufferedReader( new InputStreamReader( in, "UTF-8" ) );
215                String line = reader.readLine();
216                while ( line != null )
217                {
218                    boolean accept = pattern.matcher( line ).matches();
219                    if ( accept )
220                    {
221                        map.put( line, Boolean.TRUE );
222                    }
223                    line = reader.readLine();
224                }
225                reader.close();
226            }
227        }
228        catch ( IOException e )
229        {
230            throw new Error( e );
231        }
232    }
233
234}