This project has retired. For details please refer to its Attic page.
BaseLocaleUrlDefinitionDAO xref
View Javadoc

1   /*
2    * $Id: BaseLocaleUrlDefinitionDAO.java 797540 2009-07-24 15:42:00Z apetrelli $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  package org.apache.tiles.definition.dao;
23  
24  import java.io.FileNotFoundException;
25  import java.io.IOException;
26  import java.net.URL;
27  import java.net.URLConnection;
28  import java.util.ArrayList;
29  import java.util.HashMap;
30  import java.util.List;
31  import java.util.Locale;
32  import java.util.Map;
33  import java.util.Set;
34  
35  import org.apache.tiles.Definition;
36  import org.apache.tiles.Initializable;
37  import org.apache.tiles.TilesApplicationContext;
38  import org.apache.tiles.awareness.TilesApplicationContextAware;
39  import org.apache.tiles.definition.DefinitionsFactory;
40  import org.apache.tiles.definition.DefinitionsFactoryException;
41  import org.apache.tiles.definition.DefinitionsReader;
42  import org.apache.tiles.definition.RefreshMonitor;
43  import org.apache.tiles.definition.digester.DigesterDefinitionsReader;
44  import org.apache.tiles.impl.BasicTilesContainer;
45  import org.apache.tiles.reflect.ClassUtil;
46  import org.slf4j.Logger;
47  import org.slf4j.LoggerFactory;
48  
49  /***
50   * Base abstract class for a DAO that is based on URLs and locale as a
51   * customization key.
52   *
53   * @version $Rev: 797540 $ $Date: 2009-07-24 17:42:00 +0200 (ven, 24 lug 2009) $
54   * @since 2.1.0
55   */
56  @SuppressWarnings("deprecation")
57  public abstract class BaseLocaleUrlDefinitionDAO implements
58          DefinitionDAO<Locale>, Initializable, TilesApplicationContextAware,
59          RefreshMonitor, URLReader {
60  
61      /***
62       * The logging object.
63       */
64      private final Logger log = LoggerFactory
65              .getLogger(BaseLocaleUrlDefinitionDAO.class);
66  
67      /***
68       * Compatibility constant.
69       *
70       * @deprecated use {@link DefinitionsFactory#DEFINITIONS_CONFIG} to avoid
71       * namespace collisions.
72       */
73      private static final String LEGACY_DEFINITIONS_CONFIG = "definitions-config";
74  
75      /***
76       * Contains the URL objects identifying where configuration data is found.
77       *
78       * @since 2.1.0
79       */
80      protected List<URL> sourceURLs;
81  
82      /***
83       * Contains the dates that the URL sources were last modified.
84       *
85       * @since 2.1.0
86       */
87      protected Map<String, Long> lastModifiedDates;
88  
89      /***
90       * The application context.
91       *
92       * @since 2.1.0
93       */
94      protected TilesApplicationContext applicationContext;
95  
96      /***
97       * Reader used to get definitions from the sources.
98       *
99       * @since 2.1.0
100      */
101     protected DefinitionsReader reader;
102 
103     /***
104      * Constructor.
105      */
106     public BaseLocaleUrlDefinitionDAO() {
107         sourceURLs = new ArrayList<URL>();
108         lastModifiedDates = new HashMap<String, Long>();
109     }
110 
111     /***  {@inheritDoc}*/
112     public void setSourceURLs(List<URL> sourceURLs) {
113         this.sourceURLs = sourceURLs;
114     }
115 
116     /***  {@inheritDoc}*/
117     public void setReader(DefinitionsReader reader) {
118         this.reader = reader;
119     }
120 
121     /***  {@inheritDoc}*/
122     public void addSourceURL(URL sourceURL) {
123         if (sourceURLs == null) {
124             sourceURLs = new ArrayList<URL>();
125         }
126         sourceURLs.add(sourceURL);
127     }
128 
129     /*** {@inheritDoc} */
130     public void setApplicationContext(TilesApplicationContext applicationContext) {
131         this.applicationContext = applicationContext;
132     }
133 
134     /*** {@inheritDoc} */
135     public void init(Map<String, String> params) {
136         identifySources(params);
137         String readerClassName = params
138                 .get(DefinitionsFactory.READER_IMPL_PROPERTY);
139 
140         if (readerClassName != null) {
141             reader = (DefinitionsReader) ClassUtil.instantiate(readerClassName);
142         } else {
143             reader = new DigesterDefinitionsReader();
144         }
145         reader.init(params);
146     }
147 
148     /*** {@inheritDoc} */
149     public boolean refreshRequired() {
150         boolean status = false;
151 
152         Set<String> urls = lastModifiedDates.keySet();
153 
154         try {
155             for (String urlPath : urls) {
156                 Long lastModifiedDate = lastModifiedDates.get(urlPath);
157                 URL url = new URL(urlPath);
158                 URLConnection connection = url.openConnection();
159                 connection.connect();
160                 long newModDate = connection.getLastModified();
161                 if (newModDate != lastModifiedDate) {
162                     status = true;
163                     break;
164                 }
165             }
166         } catch (Exception e) {
167             log.warn("Exception while monitoring update times.", e);
168             return true;
169         }
170         return status;
171     }
172 
173     /***
174      * Detects the sources to load.
175      *
176      * @param initParameters The initialization parameters.
177      * @since 2.1.0
178      */
179     protected void identifySources(Map<String, String> initParameters) {
180         if (applicationContext == null) {
181             throw new IllegalStateException(
182                     "The TilesApplicationContext cannot be null");
183         }
184 
185         String resourceString = getResourceString(initParameters);
186         String[] resources = getResourceNames(resourceString);
187 
188         try {
189             for (int i = 0; i < resources.length; i++) {
190                 Set<URL> urls = applicationContext.getResources(resources[i]);
191                 if (urls != null && !urls.isEmpty()) {
192                     for (URL resourceUrl : urls) {
193                         if (resourceUrl != null) {
194                             if (log.isDebugEnabled()) {
195                                 log.debug("Adding resource '" + resourceUrl
196                                         + "' to definitions factory.");
197                             }
198                             String externalForm = resourceUrl.toExternalForm();
199                             if (externalForm.indexOf('_', externalForm
200                                     .lastIndexOf("/")) < 0) {
201                                 sourceURLs.add(resourceUrl);
202                             } else if (log.isDebugEnabled()) {
203                                 log.debug("Not adding resource '" + resourceUrl
204                                         + "' to definitions factory because it is "
205                                         + "supposed to be an internationalization.");
206                             }
207 
208                         } else {
209                             log.warn("Unable to find configured definition '"
210                                     + resources[i] + "'");
211                         }
212                     }
213                 } else {
214                     log.warn("Unable to find resources under the name '"
215                             + resources[i] + "'");
216                 }
217             }
218         } catch (IOException e) {
219             throw new DefinitionsFactoryException(
220                     "Unable to parse definitions from " + resourceString, e);
221         }
222     }
223 
224     /***
225      * Derive the resource string from the initialization parameters. If no
226      * parameter {@link DefinitionsFactory#DEFINITIONS_CONFIG} is available,
227      * attempts to retrieve the deprecated
228      * <code>org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG</code>
229      * parameter and {@link #LEGACY_DEFINITIONS_CONFIG}. If neither are
230      * available, returns "/WEB-INF/tiles.xml".
231      *
232      * @param parms The initialization parameters.
233      * @return resource string to be parsed.
234      */
235     protected String getResourceString(Map<String, String> parms) {
236         String resourceStr = parms.get(DefinitionsFactory.DEFINITIONS_CONFIG);
237         if (resourceStr == null) {
238             resourceStr = parms.get(BasicTilesContainer.DEFINITIONS_CONFIG);
239         }
240         if (resourceStr == null) {
241             resourceStr = parms.get(LEGACY_DEFINITIONS_CONFIG);
242         }
243         if (resourceStr == null) {
244             resourceStr = "/WEB-INF/tiles.xml";
245         }
246         return resourceStr;
247     }
248 
249     /***
250      * Parse the resourceString into a list of resource paths which can be
251      * loaded by the application context.
252      *
253      * @param resourceString comma separated resources
254      * @return parsed resources
255      */
256     protected String[] getResourceNames(String resourceString) {
257         return resourceString.split(",");
258     }
259 
260     /***
261      * Loads definitions from an URL without loading from "parent" URLs.
262      *
263      * @param url The URL to read.
264      * @return The definition map that has been read.
265      */
266     protected Map<String, Definition> loadDefinitionsFromURL(URL url) {
267         Map<String, Definition> defsMap = null;
268         try {
269             URLConnection connection = url.openConnection();
270             connection.connect();
271             lastModifiedDates.put(url.toExternalForm(), connection
272                     .getLastModified());
273 
274             // Definition must be collected, starting from the base
275             // source up to the last localized file.
276             defsMap = reader.read(connection.getInputStream());
277         } catch (FileNotFoundException e) {
278             // File not found. continue.
279             if (log.isDebugEnabled()) {
280                 log.debug("File " + null + " not found, continue");
281             }
282         } catch (IOException e) {
283             throw new DefinitionsFactoryException(
284                     "I/O error processing configuration.", e);
285         }
286 
287         return defsMap;
288     }
289 }