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            .getConfigurationsCache(dictionaryCacheId);
81  
82    /**
83     * The cache for property definition information loaded from
84     * {@value de.smartics.properties.api.core.domain.PropertiesContext#DEFINITION_FILE}
85     * or the default (which may be <code>null</code> if
86     * {@value de.smartics.properties.api.core.domain.PropertiesContext#META_INF_HOME}
87     * is absent).
88     * <p>
89     * The key is the path to the root folder that contains the
90     * <code>META-INF</code> folder for a given resource in form of a
91     * {@link ClassPathContext} instance.
92     * </p>
93     */
94    @SuppressWarnings("unchecked")
95    private final Cache<ClassPathContext, DefinitionKeyHelper> definitionCache =
96        (Cache<ClassPathContext, DefinitionKeyHelper>) CacheManagerFactory
97            .getConfigurationsCache(definitionCacheId);
98  
99    // ****************************** Initializer *******************************
100 
101   // ****************************** Constructors ******************************
102 
103   MultiSourcePropertiesManager(final boolean lenient,
104       final Collection<PropertyProvider> rootPropertyProviders)
105   {
106     this.lenient = lenient;
107     this.rootPropertyProviders = rootPropertyProviders;
108   }
109 
110   // ****************************** Inner Classes *****************************
111 
112   // ********************************* Methods ********************************
113 
114   // --- init -----------------------------------------------------------------
115 
116   private static String createId(final String discriminator)
117   {
118     final UUID uuid = UUID.randomUUID();
119     final String id =
120         "Management:DefinitionKeyHelper:" + discriminator + "/" + uuid;
121     return id;
122   }
123 
124   // --- get&set --------------------------------------------------------------
125 
126   // --- business -------------------------------------------------------------
127 
128   MultiSourceProperties create(final ConfigurationKey<?> key)
129   {
130     MultiSourceProperties allProperties = dictionaryCache.get(key);
131     if (allProperties == null)
132     {
133       allProperties =
134           new MultiSourceProperties(key, lenient ? null
135               : new ArrayList<ConfigurationException>());
136       allProperties.addProviders(rootPropertyProviders);
137       dictionaryCache.put(key, allProperties);
138     }
139 
140     return allProperties;
141   }
142 
143   void create()
144   {
145     for (final PropertyProvider provider : rootPropertyProviders)
146     {
147       final ConfigurationKey<?> key = provider.getConfigurationKey();
148       MultiSourceProperties allProperties = dictionaryCache.get(key);
149       if (allProperties == null)
150       {
151         allProperties =
152             new MultiSourceProperties(key, lenient ? null
153                 : new ArrayList<ConfigurationException>());
154         allProperties.addProvider(provider);
155         dictionaryCache.put(key, allProperties);
156       }
157     }
158   }
159 
160   void release()
161   {
162     CacheManagerFactory.discard(dictionaryCacheId);
163     CacheManagerFactory.discard(definitionCacheId);
164   }
165 
166   /**
167    * Returns the definition information for the given class loader.
168    *
169    * @param context the class loader and the root folder to read the
170    *          <code>{@value de.smartics.properties.api.core.domain.PropertiesContext#DEFINITION_FILE_NAME}</code>
171    *          .
172    * @return the definition helper if there is a
173    *         <code>{@value de.smartics.properties.api.core.domain.PropertiesContext#DEFINITION_FILE_NAME}</code>
174    *         or at least
175    *         {@value de.smartics.properties.api.core.domain.PropertiesContext#META_INF_HOME}
176    *         , <code>null</code> otherwise.
177    */
178   @CheckForNull
179   DefinitionKeyHelper getDefinition(final ClassPathContext context)
180   {
181     DefinitionKeyHelper definition = definitionCache.get(context);
182     if (definition == null)
183     {
184       final DefinitionConfigParser<?> parser =
185           ConfigurationKeyContextManager.INSTANCE.context()
186               .definitionConfigParser();
187 
188       final PropertiesDefinitionContext definitionContext =
189           parser.parse(context);
190       definition =
191           ConfigurationKeyContextManager.INSTANCE.context()
192               .definitionKeyHelper(definitionContext);
193 
194       definitionCache.put(context, definition);
195     }
196 
197     return definition;
198   }
199 
200   Collection<MultiSourceProperties> getProperties()
201   {
202     final List<MultiSourceProperties> propertiesCollection =
203         new LinkedList<MultiSourceProperties>();
204     for (final Iterator<ConfigurationKey<?>> iterator =
205         dictionaryCache.keySet().iterator(); iterator.hasNext();)
206     {
207       final ConfigurationKey<?> configKey = iterator.next();
208       final MultiSourceProperties properties = dictionaryCache.get(configKey);
209       propertiesCollection.add(properties);
210     }
211     return Collections.unmodifiableCollection(propertiesCollection);
212   }
213 
214   // --- object basics --------------------------------------------------------
215 
216 }