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