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   *    http://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.server.schema.registries;
21  
22  
23  import java.util.Map;
24  import java.util.Properties;
25  import java.util.Stack;
26  
27  import javax.naming.NamingException;
28  
29  import org.apache.directory.server.schema.bootstrap.Schema;
30  import org.slf4j.Logger;
31  import org.slf4j.LoggerFactory;
32  
33  
34  /**
35   * An abstract class with a utility method and setListener() implemented.
36   *
37   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
38   * @version $Rev$
39   */
40  public abstract class AbstractSchemaLoader implements SchemaLoader
41  {
42      /** static class logger */
43      private static final Logger LOG = LoggerFactory.getLogger( AbstractSchemaLoader.class );
44      
45      protected SchemaLoaderListener listener;
46      
47      
48      public void setListener( SchemaLoaderListener listener )
49      {
50          this.listener = listener;
51      }
52      
53      
54      protected final void notifyListenerOrRegistries( Schema schema, Registries registries )
55      {
56          if ( listener != null )
57          {
58              listener.schemaLoaded( schema );
59          }
60          
61          if ( registries instanceof SchemaLoaderListener )
62          {
63              if ( registries != listener )
64              {
65                  SchemaLoaderListener listener = ( SchemaLoaderListener ) registries;
66                  listener.schemaLoaded( schema );
67              }
68          }
69      }
70      
71      
72      /**
73       * Recursive method which loads schema's with their dependent schemas first
74       * and tracks what schemas it has seen so the recursion does not go out of
75       * control with depenency cycle detection.
76       *
77       * @param rootAncestor the triggering schema load request: the root ancestor of dependency chain
78       * @param beenthere stack of schema names we have visited and have yet to load
79       * @param notLoaded hash of schemas keyed by name which have yet to be loaded
80       * @param schema the current schema we are attempting to load
81       * @param registries the set of registries to use while loading
82       * @param props to use while trying to resolve other schemas
83       * @throws NamingException if there is a cycle detected and/or another
84       * failure results while loading, producing and or registering schema objects
85       */
86      protected final void loadDepsFirst( Schema rootAncestor, Stack<String> beenthere, Map<String,Schema> notLoaded, Schema schema,
87          Registries registries, Properties props ) throws Exception
88      {
89          if ( registries.getLoadedSchemas().containsKey( schema.getSchemaName() ) )
90          {
91              LOG.warn( "{} schema has already been loaded" + schema.getSchemaName() );
92              return;
93          }
94          
95          beenthere.push( schema.getSchemaName() );
96          String[] deps = schema.getDependencies();
97  
98          // if no deps then load this guy and return
99          if ( deps == null || deps.length == 0 )
100         {
101             if ( rootAncestor == schema )
102             {
103                 load( schema, registries, false );
104             }
105             else
106             {
107                 load( schema, registries, true );
108             }
109             
110             notLoaded.remove( schema.getSchemaName() );
111             beenthere.pop();
112             return;
113         }
114 
115         /*
116          * We got deps and need to load them before this schema.  We go through
117          * all deps loading them with their deps first if they have not been
118          * loaded.
119          */
120         for ( String depName : deps )
121         {
122             // @todo if a dependency is not loaded it's not in this list
123             // @todo why is it not in this list?  Without being in this list
124             // @todo this for loop is absolutely useless - we will not load
125             // @todo any disabled dependencies at all.  I'm shocked that the
126             // @todo samba schema is actually loading when the nis dependency
127             // @todo is not loaded.
128 
129             if ( !notLoaded.containsKey( depName ) )
130             {
131                 continue;
132             }
133 
134             Schema dep = notLoaded.get( depName );
135 
136             // dep is not in the set of schema objects we need to try to resolve it
137             if ( dep == null )
138             {
139                 // try to load dependency with the provided properties default
140                 dep = getSchema( depName, props );
141             }
142 
143             if ( beenthere.contains( dep.getSchemaName() ) )
144             {
145                 // push again so we show the cycle in output
146                 beenthere.push( dep.getSchemaName() );
147                 throw new NamingException( "schema dependency cycle detected: " + beenthere );
148             }
149 
150             loadDepsFirst( rootAncestor, beenthere, notLoaded, dep, registries, props );
151         }
152 
153         // We have loaded all our deps so we can load this schema
154         if ( rootAncestor == schema )
155         {
156             load( schema, registries, false );
157         }
158         else
159         {
160             load( schema, registries, true );
161         }
162         
163         notLoaded.remove( schema.getSchemaName() );
164         beenthere.pop();
165     }
166 }