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.HashMap;
21  import java.util.Map;
22  
23  import javax.annotation.CheckForNull;
24  import javax.annotation.concurrent.NotThreadSafe;
25  
26  import de.smartics.properties.api.config.domain.ConfigurationException;
27  import de.smartics.properties.api.config.domain.PropertyProvider;
28  import de.smartics.properties.api.config.domain.key.ConfigurationKey;
29  import de.smartics.properties.api.core.domain.ConfigException;
30  import de.smartics.properties.spi.config.definition.DefinitionConfigParser;
31  import de.smartics.properties.spi.config.definition.DefinitionKeyHelper;
32  import de.smartics.properties.spi.config.definition.PropertiesDefinitionContext;
33  import de.smartics.util.lang.ClassPathContext;
34  
35  /**
36   * Helper to provide multiple sources for any configurations found.
37   */
38  @NotThreadSafe
39  public final class MultiSourcePropertiesManager
40  {
41    // ********************************* Fields *********************************
42  
43    // --- constants ------------------------------------------------------------
44  
45    // --- members --------------------------------------------------------------
46  
47    /**
48     * The additional properties added by other means than loading them from the
49     * class path.
50     */
51    private final Collection<PropertyProvider> rootPropertyProviders;
52  
53    /**
54     * The flag indicates that configuration problems are not signaled by
55     * exceptions.
56     */
57    private final boolean lenient;
58  
59    /**
60     * The dictionary to map a configuration key to a properties collection.
61     */
62    private final Map<ConfigurationKey, MultiSourceProperties> dictionary =
63        new HashMap<ConfigurationKey, MultiSourceProperties>();
64  
65    /**
66     * The cache for property definition information loaded from
67     * {@value de.smartics.properties.api.core.domain.PropertiesContext#DEFINITION_FILE}
68     * or the default (which may be <code>null</code> if
69     * {@value de.smartics.properties.api.core.domain.PropertiesContext#META_INF_HOME}
70     * is absent).
71     * <p>
72     * The key is the path to the root folder that contains the
73     * <code>META-INF</code> folder for a given resource in form of a
74     * {@link ClassPathContext} instance.
75     * </p>
76     */
77    private final Map<ClassPathContext, DefinitionKeyHelper> definitionCache =
78        new HashMap<ClassPathContext, DefinitionKeyHelper>();
79  
80    // ****************************** Initializer *******************************
81  
82    // ****************************** Constructors ******************************
83  
84    MultiSourcePropertiesManager(final boolean lenient,
85        final Collection<PropertyProvider> rootPropertyProviders)
86    {
87      this.lenient = lenient;
88      this.rootPropertyProviders = rootPropertyProviders;
89    }
90  
91    // ****************************** Inner Classes *****************************
92  
93    // ********************************* Methods ********************************
94  
95    // --- init -----------------------------------------------------------------
96  
97    // --- get&set --------------------------------------------------------------
98  
99    // --- business -------------------------------------------------------------
100 
101   MultiSourceProperties create(final ConfigurationKey key)
102   {
103     MultiSourceProperties allProperties = dictionary.get(key);
104     if (allProperties == null)
105     {
106       allProperties =
107           new MultiSourceProperties(key, lenient ? null
108               : new ArrayList<ConfigurationException>());
109       allProperties.addProviders(rootPropertyProviders);
110       dictionary.put(key, allProperties);
111     }
112 
113     return allProperties;
114   }
115 
116   void create()
117   {
118     for (final PropertyProvider provider : rootPropertyProviders)
119     {
120       final ConfigurationKey key = provider.getConfigurationKey();
121       MultiSourceProperties allProperties = dictionary.get(key);
122       if (allProperties == null)
123       {
124         allProperties =
125             new MultiSourceProperties(key, lenient ? null
126                 : new ArrayList<ConfigurationException>());
127         allProperties.addProvider(provider);
128         dictionary.put(key, allProperties);
129       }
130     }
131   }
132 
133   /**
134    * Returns the definition information for the given class loader.
135    *
136    * @param context the class loader and the root folder to read the
137    *          <code>{@value de.smartics.properties.api.core.domain.PropertiesContext#DEFINITION_FILE_NAME}</code>
138    *          .
139    * @return the definition helper if there is a
140    *         <code>{@value de.smartics.properties.api.core.domain.PropertiesContext#DEFINITION_FILE_NAME}</code>
141    *         or at least
142    *         {@value de.smartics.properties.api.core.domain.PropertiesContext#META_INF_HOME}
143    *         , <code>null</code> otherwise.
144    */
145   @CheckForNull
146   DefinitionKeyHelper getDefinition(final ClassPathContext context)
147   {
148     DefinitionKeyHelper definition = definitionCache.get(context);
149     if (definition == null)
150     {
151       final DefinitionConfigParser parser = new DefinitionConfigParser();
152       try
153       {
154         final PropertiesDefinitionContext definitionContext =
155             parser.parse(context);
156         definition = new DefinitionKeyHelper(definitionContext);
157       }
158       catch (final ConfigException e)
159       {
160         definition = new DefinitionKeyHelper();
161       }
162 
163       definitionCache.put(context, definition);
164     }
165 
166     return definition;
167   }
168 
169   Collection<MultiSourceProperties> getProperties()
170   {
171     return dictionary.values();
172   }
173 
174   // --- object basics --------------------------------------------------------
175 
176 }