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    package org.apache.directory.server.schema.bootstrap.partition;
021    
022    
023    import java.io.BufferedReader;
024    import java.io.IOException;
025    import java.io.InputStream;
026    import java.io.InputStreamReader;
027    import java.net.URL;
028    import java.util.Enumeration;
029    import java.util.HashMap;
030    import java.util.HashSet;
031    import java.util.Iterator;
032    import java.util.Map;
033    import java.util.Set;
034    
035    
036    /**
037     * Parses the dbfile listing file within this jar.
038     *
039     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
040     * @version $Rev: 780345 $
041     */
042    public class DbFileListing
043    {
044        Map<String, DbFileType> name2type = new HashMap<String, DbFileType>();
045        private static final String BASE_PATH = DbFileListing.class.getName()
046            .substring( 0, DbFileListing.class.getName().lastIndexOf( "." ) + 1 ).replace( '.', '/' );
047    
048    
049        public DbFileListing() throws IOException
050        {
051            init();
052        }
053    
054    
055        /**
056         * Reads the DBFILES resource within some jar on the classpath that 
057         * has this file and loaded it's db files into the name2type map with
058         * something like the following entries ( key => value ):
059         * <pre>
060         * schema/master.db => MASTER_FILE
061         * schema/apacheOnealias.db => SYSTEM_INDEX
062         * schema/apacheSubalias.db => SYSTEM_INDEX
063         * schema/apacheNdn.db => SYSTEM_INDEX
064         * schema/apacheExistence.db => SYSTEM_INDEX
065         * schema/apacheAlias.db => SYSTEM_INDEX
066         * schema/apacheOneLevel.db => SYSTEM_INDEX
067         * schema/apacheUpdn.db => SYSTEM_INDEX
068         * schema/objectClass.db => USER_INDEX
069         * schema/ou.db => USER_INDEX
070         * schema/cn.db => USER_INDEX
071         * schema/m-oid.db => USER_INDEX
072         * schema/m-disabled.db => USER_INDEX
073         * </pre>
074         *
075         * @throws IOException
076         */
077        private void init() throws IOException
078        {
079    
080            boolean userIndexMode = false;
081            String line = null;
082            BufferedReader in = new BufferedReader( 
083                new InputStreamReader( 
084                    getUniqueResourceAsStream( 
085                        "DBFILES", 
086                        "bootstrap partition database file list. " + 
087                        "Be sure there is exactly one bootstrap partition jar in your classpath." ) ) );
088            try
089            {
090                while ( ( line = in.readLine() ) != null )
091                {
092                    if ( line.indexOf( "master.db" ) != -1 )
093                    {
094                        name2type.put( line.trim(), DbFileType.MASTER_FILE );
095                        continue;
096                    }
097    
098                    if ( line.indexOf( "USER INDICES" ) != -1 )
099                    {
100                        userIndexMode = true;
101                        continue;
102                    }
103    
104                    if ( userIndexMode )
105                    {
106                        name2type.put( line.trim(), DbFileType.USER_INDEX );
107                    } 
108                    else
109                    {
110                        name2type.put( line.trim(), DbFileType.SYSTEM_INDEX );
111                    }
112                }
113            }
114            finally
115            {
116                in.close();
117            }
118        }
119    
120        
121        /**
122         * Gets the DBFILE resource from within a jar off the base path.  If another jar
123         * with such a DBFILE resource exists then an error will result since the resource
124         * is not unique across all the jars.
125         *
126         * @param resourceName the file name of the resource to load
127         * @param resourceDescription
128         * @return the InputStream to read the contents of the resource
129         * @throws IOException if there are problems reading or finding a unique copy of the resource
130         */                                                                                                
131        public static InputStream getUniqueResourceAsStream( String resourceName, String resourceDescription ) throws IOException
132        {
133            resourceName = BASE_PATH + resourceName;
134            URL result = getUniqueResource( resourceName, resourceDescription );
135            return result.openStream();
136        }
137    
138        static URL getUniqueResource( String resourceName, String resourceDescription )
139                throws IOException
140        {
141            Enumeration<URL> resources = DbFileListing.class.getClassLoader().getResources( resourceName );
142            if ( !resources.hasMoreElements() )
143            {
144                throw new UniqueResourceException( resourceName, resourceDescription );
145            }
146            URL result = resources.nextElement();
147            if ( resources.hasMoreElements() )
148            {
149                throw new UniqueResourceException( resourceName, result, resources, resourceDescription);
150            }
151            return result;
152        }
153    
154    
155        public DbFileType getType( String dbfile )
156        {
157            return name2type.get( dbfile );
158        }
159    
160    
161        public Iterator<String> iterator()
162        {
163            return name2type.keySet().iterator();
164        }
165    
166    
167        public String getIndexAttributeName( String dbfile )
168        {
169            if ( dbfile.length() < 10 )
170            {
171                throw new IllegalArgumentException( "db file must have a relative jar path name of over 10 characters" );
172            }
173    
174            // remove 'schema/'
175            String dbfileName = dbfile.substring( 7 );
176            return dbfileName.substring( 0, dbfileName.length() - 3 );
177        }
178    
179    
180        /**
181         * Gets the user indices WITHOUT the system indices.
182         *
183         * @return set of user index names
184         */
185        public Set<String> getIndexedAttributes()
186        {
187            Set<String> attributes = new HashSet<String>();
188            Iterator<String> ii = iterator();
189            while( ii.hasNext() )
190            {
191                String name = ii.next();
192                if ( name2type.get( name ) == DbFileType.USER_INDEX )
193                {
194                    attributes.add( getIndexAttributeName( name ) );
195                }
196            }
197            return attributes;
198        }
199    }