View Javadoc

1   /*
2    * Copyright 2012-2013 smartics, Kronseder & Reiner GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package de.smartics.properties.spi.config.support;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.Collections;
21  import java.util.Iterator;
22  import java.util.LinkedList;
23  import java.util.List;
24  import java.util.UUID;
25  
26  import javax.annotation.CheckForNull;
27  import javax.annotation.concurrent.NotThreadSafe;
28  
29  import de.smartics.properties.api.config.domain.ConfigurationException;
30  import de.smartics.properties.api.config.domain.PropertyProvider;
31  import de.smartics.properties.api.config.domain.key.ConfigurationKey;
32  import de.smartics.properties.spi.config.cache.Cache;
33  import de.smartics.properties.spi.config.cache.CacheManagerFactory;
34  import de.smartics.properties.spi.config.definition.DefinitionConfigParser;
35  import de.smartics.properties.spi.config.definition.DefinitionKeyHelper;
36  import de.smartics.properties.spi.config.definition.PropertiesDefinitionContext;
37  import de.smartics.properties.spi.config.domain.key.ConfigurationKeyContextManager;
38  import de.smartics.util.lang.classpath.ClassPathContext;
39  
40  /**
41   * Helper to provide multiple sources for any configurations found.
42   */
43  @NotThreadSafe
44  public final class MultiSourcePropertiesManager
45  {
46    // ********************************* Fields *********************************
47  
48    // --- constants ------------------------------------------------------------
49  
50    // --- members --------------------------------------------------------------
51  
52    /**
53     * The additional properties added by other means than loading them from the
54     * class path.
55     */
56    private final Collection<PropertyProvider> rootPropertyProviders;
57  
58    /**
59     * The flag indicates that configuration problems are not signaled by
60     * exceptions.
61     */
62    private final boolean lenient;
63  
64    /**
65     * The unique identifier of the definition cache.
66     */
67    private final String definitionCacheId = createId("DefinitionCache");
68  
69    /**
70     * The unique identifier of the dictionary cache.
71     */
72    private final String dictionaryCacheId = createId("Dictionary");
73  
74    /**
75     * The dictionary cache to map a configuration key to a properties collection.
76     */
77    @SuppressWarnings("unchecked")
78    private final Cache<ConfigurationKey<?>, MultiSourceProperties> dictionaryCache =
79        (Cache<ConfigurationKey<?>, MultiSourceProperties>) CacheManagerFactory
80            .getInstance().createManager()
81            .getConfigurationsCache(dictionaryCacheId);
82  
83    /**
84     * The cache for property definition information loaded from
85     * {@value de.smartics.properties.api.core.domain.PropertiesContext#DEFINITION_FILE}
86     * or the default (which may be <code>null</code> if
87     * {@value de.smartics.properties.api.core.domain.PropertiesContext#META_INF_HOME}
88     * is absent).
89     * <p>
90     * The key is the path to the root folder that contains the
91     * <code>META-INF</code> folder for a given resource in form of a
92     * {@link ClassPathContext} instance.
93     * </p>
94     */
95    @SuppressWarnings("unchecked")
96    private final Cache<ClassPathContext, DefinitionKeyHelper> definitionCache =
97        (Cache<ClassPathContext, DefinitionKeyHelper>) CacheManagerFactory
98            .getInstance().createManager()
99            .getConfigurationsCache(definitionCacheId);
100 
101   // ****************************** Initializer *******************************
102 
103   // ****************************** Constructors ******************************
104 
105   MultiSourcePropertiesManager(final boolean lenient,
106       final Collection<PropertyProvider> rootPropertyProviders)
107   {
108     this.lenient = lenient;
109     this.rootPropertyProviders = rootPropertyProviders;
110   }
111 
112   // ****************************** Inner Classes *****************************
113 
114   // ********************************* Methods ********************************
115 
116   // --- init -----------------------------------------------------------------
117 
118   private static String createId(final String discriminator)
119   {
120     final UUID uuid = UUID.randomUUID();
121     final String id =
122         "Management:DefinitionKeyHelper:" + discriminator + "/" + uuid;
123     return id;
124   }
125 
126   // --- get&set --------------------------------------------------------------
127 
128   // --- business -------------------------------------------------------------
129 
130   MultiSourceProperties create(final ConfigurationKey<?> key)
131   {
132     MultiSourceProperties allProperties = dictionaryCache.get(key);
133     if (allProperties == null)
134     {
135       allProperties =
136           new MultiSourceProperties(key, lenient ? null
137               : new ArrayList<ConfigurationException>());
138       allProperties.addProviders(rootPropertyProviders);
139       dictionaryCache.put(key, allProperties);
140     }
141 
142     return allProperties;
143   }
144 
145   void create()
146   {
147     for (final PropertyProvider provider : rootPropertyProviders)
148     {
149       final ConfigurationKey<?> key = provider.getConfigurationKey();
150       MultiSourceProperties allProperties = dictionaryCache.get(key);
151       if (allProperties == null)
152       {
153         allProperties =
154             new MultiSourceProperties(key, lenient ? null
155                 : new ArrayList<ConfigurationException>());
156         allProperties.addProvider(provider);
157         dictionaryCache.put(key, allProperties);
158       }
159     }
160   }
161 
162   void release()
163   {
164     CacheManagerFactory.getInstance().createManager()
165         .discard(dictionaryCacheId);
166     CacheManagerFactory.getInstance().createManager()
167         .discard(definitionCacheId);
168   }
169 
170   /**
171    * Returns the definition information for the given class loader.
172    *
173    * @param context the class loader and the root folder to read the
174    *          <code>{@value de.smartics.properties.api.core.domain.PropertiesContext#DEFINITION_FILE_NAME}</code>
175    *          .
176    * @return the definition helper if there is a
177    *         <code>{@value de.smartics.properties.api.core.domain.PropertiesContext#DEFINITION_FILE_NAME}</code>
178    *         or at least
179    *         {@value de.smartics.properties.api.core.domain.PropertiesContext#META_INF_HOME}
180    *         , <code>null</code> otherwise.
181    */
182   @CheckForNull
183   DefinitionKeyHelper getDefinition(final ClassPathContext context)
184   {
185     DefinitionKeyHelper definition = definitionCache.get(context);
186     if (definition == null)
187     {
188       final DefinitionConfigParser<?> parser =
189           ConfigurationKeyContextManager.INSTANCE.context()
190               .definitionConfigParser();
191 
192       final PropertiesDefinitionContext definitionContext =
193           parser.parse(context);
194       definition =
195           ConfigurationKeyContextManager.INSTANCE.context()
196               .definitionKeyHelper(definitionContext);
197 
198       definitionCache.put(context, definition);
199     }
200 
201     return definition;
202   }
203 
204   Collection<MultiSourceProperties> getProperties()
205   {
206     final List<MultiSourceProperties> propertiesCollection =
207         new LinkedList<MultiSourceProperties>();
208     for (final Iterator<ConfigurationKey<?>> iterator =
209         dictionaryCache.keySet().iterator(); iterator.hasNext();)
210     {
211       final ConfigurationKey<?> configKey = iterator.next();
212       final MultiSourceProperties properties = dictionaryCache.get(configKey);
213       propertiesCollection.add(properties);
214     }
215     return Collections.unmodifiableCollection(propertiesCollection);
216   }
217 
218   // --- object basics --------------------------------------------------------
219 
220 }