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.core.context;
17  
18  import java.io.BufferedInputStream;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.net.URL;
22  import java.util.List;
23  import java.util.Locale;
24  
25  import org.apache.commons.io.IOUtils;
26  import org.apache.commons.lang.StringUtils;
27  import org.jdom.Document;
28  import org.jdom.Element;
29  import org.jdom.JDOMException;
30  import org.jdom.Namespace;
31  import org.jdom.input.SAXBuilder;
32  
33  import de.smartics.properties.api.core.domain.ConfigException;
34  import de.smartics.properties.api.core.domain.PropertiesContext;
35  import de.smartics.properties.api.core.domain.PropertiesContext.Builder;
36  import de.smartics.properties.spi.core.util.ClassLoaderUtils;
37  import de.smartics.util.lang.ClassPathContext;
38  
39  /**
40   * Parses the configuration file for properties.
41   */
42  public final class DeclarationConfigParser
43  {
44    // ********************************* Fields *********************************
45  
46    // --- constants ------------------------------------------------------------
47  
48    /**
49     * The namespace accepted by this parser.
50     */
51    private static final Namespace NS = Namespace
52        .getNamespace("http://smartics.de/properties/declaration/1");
53  
54    // --- members --------------------------------------------------------------
55  
56    /**
57     * Helper to determine the supported locales by analyzing the property set
58     * reports.
59     */
60    private final LocaleFinder localeFinder = new LocaleFinder();
61  
62    // ****************************** Initializer *******************************
63  
64    // ****************************** Constructors ******************************
65  
66    // ****************************** Inner Classes *****************************
67  
68    // ********************************* Methods ********************************
69  
70    // --- init -----------------------------------------------------------------
71  
72    // --- get&set --------------------------------------------------------------
73  
74    // --- business -------------------------------------------------------------
75  
76    /**
77     * Default constructor.
78     */
79    public DeclarationConfigParser()
80    {
81    }
82  
83    // --- object basics --------------------------------------------------------
84  
85    /**
86     * Convenience method using a class' class loader to locate the configuration
87     * file to parse the configuration file at
88     * {@link PropertiesContext#DECLARATION_FILE}.
89     *
90     * @param type the type whose class loader to use to locate the configuration
91     *          file.
92     * @return the read configuration, never <code>null</code>.
93     * @throws ConfigException on any problem loading the file.
94     */
95    public PropertiesContext parse(final Class<?> type) throws ConfigException
96    {
97      final String archivePath = ClassLoaderUtils.calcArchivePath(type);
98      final ClassPathContext context =
99          new ClassPathContext(type.getClassLoader(), archivePath);
100     return parse(context);
101   }
102 
103   /**
104    * Parses the configuration file at {@link PropertiesContext#DECLARATION_FILE}
105    * .
106    *
107    * @param context the context to use to locate the configuration file.
108    * @return the read configuration, never <code>null</code>.
109    * @throws ConfigException on any problem loading the file.
110    */
111   public PropertiesContext parse(final ClassPathContext context)
112     throws ConfigException
113   {
114     final URL url = context.getResource(PropertiesContext.DECLARATION_FILE);
115     if (url != null)
116     {
117       final String systemId = url.toExternalForm();
118       final List<Locale> locales = localeFinder.find(systemId, context);
119 
120       InputStream in = null;
121       try
122       {
123         try
124         {
125           in = new BufferedInputStream(url.openStream());
126         }
127         catch (final IOException e)
128         {
129           throw new ConfigException(PropertiesContext.DECLARATION_FILE, e);
130         }
131         return parse(systemId, locales, in);
132       }
133       finally
134       {
135         IOUtils.closeQuietly(in);
136       }
137     }
138     throw new ConfigException(PropertiesContext.DECLARATION_FILE);
139   }
140 
141   private PropertiesContext parse(final String systemId,
142       final List<Locale> locales, final InputStream input)
143     throws ConfigException
144   {
145     try
146     {
147       final SAXBuilder parser = new SAXBuilder();
148       final Document document = parser.build(input, systemId);
149 
150       final PropertiesContext.Builder builder = new PropertiesContext.Builder();
151       builder.withLocales(locales);
152 
153       final Element rootNode = document.getRootElement();
154       final String homePageUrl = rootNode.getChildText("homepage-url", NS);
155       final String propertiesReportUrl =
156           rootNode.getChildText("properties-report-url", NS);
157       if (StringUtils.isNotBlank(propertiesReportUrl))
158       {
159         builder.withHomePageUrl(homePageUrl).withPropertiesReportUrl(
160             propertiesReportUrl);
161       }
162 
163       handleAliases(rootNode, builder);
164 
165       return builder.build();
166     }
167     catch (final JDOMException e)
168     {
169       throw new ConfigException(systemId, e);
170     }
171     catch (final IOException e)
172     {
173       throw new ConfigException(systemId, e);
174     }
175   }
176 
177   @SuppressWarnings("unchecked")
178   private void handleAliases(final Element rootNode, final Builder builder)
179   {
180     final Element aliases = rootNode.getChild("aliases", NS);
181     if (aliases != null)
182     {
183       final List<Element> aliasElements = aliases.getChildren("alias", NS);
184       for (final Element aliasElement : aliasElements)
185       {
186         final String alias = aliasElement.getTextNormalize();
187         final String physical = aliasElement.getAttributeValue("for", NS);
188         builder.withAlias(alias, physical);
189       }
190     }
191   }
192 }