1 /*
2 * $Id: UrlDefinitionsFactory.java 822631 2009-10-07 09:21:12Z 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 package org.apache.tiles.definition;
22
23 import java.net.URL;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.Locale;
27 import java.util.Map;
28 import java.util.StringTokenizer;
29
30 import org.apache.tiles.Definition;
31 import org.apache.tiles.context.TilesRequestContext;
32 import org.apache.tiles.definition.dao.DefinitionDAO;
33 import org.apache.tiles.definition.dao.ResolvingLocaleUrlDefinitionDAO;
34 import org.apache.tiles.definition.dao.URLReader;
35 import org.apache.tiles.impl.BasicTilesContainer;
36 import org.apache.tiles.util.LocaleUtil;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41 * {@link DefinitionsFactory DefinitionsFactory} implementation that manages
42 * Definitions configuration data from URLs, resolving inheritance when the URL
43 * is loaded.
44 * <p/>
45 * <p>
46 * The Definition objects are read from the
47 * {@link org.apache.tiles.definition.digester.DigesterDefinitionsReader
48 * DigesterDefinitionsReader} class unless another implementation is specified.
49 * </p>
50 *
51 * @version $Rev: 822631 $ $Date: 2009-10-07 11:21:12 +0200 (mer, 07 ott 2009) $
52 * @deprecated Use {@link UnresolvingLocaleDefinitionsFactory} and using
53 * {@link ResolvingLocaleUrlDefinitionDAO} as Tiles DAO.
54 */
55 public class UrlDefinitionsFactory extends UnresolvingLocaleDefinitionsFactory
56 implements Refreshable {
57
58 /**
59 * Compatibility constant.
60 *
61 * @deprecated use {@link DefinitionsFactory#DEFINITIONS_CONFIG} to avoid
62 * namespace collisions.
63 */
64 private static final String LEGACY_DEFINITIONS_CONFIG = "definitions-config";
65
66 /**
67 * LOG instance for all UrlDefinitionsFactory instances.
68 */
69 private final Logger log = LoggerFactory
70 .getLogger(UrlDefinitionsFactory.class);
71
72 /**
73 * Contains the URL objects identifying where configuration data is found.
74 *
75 * @deprecated Use {@link URLReader#addSourceURL(URL)}.
76 */
77 protected List<Object> sources;
78
79 /**
80 * Reader used to get definitions from the sources.
81 *
82 * @deprecated No more used.
83 */
84 protected DefinitionsReader reader;
85
86 /**
87 * Contains the dates that the URL sources were last modified.
88 *
89 * @deprecated No more used.
90 */
91 protected Map<String, Long> lastModifiedDates;
92
93 /** {@inheritDoc} */
94 public synchronized void refresh() {
95 log.debug("Updating Tiles definitions. . .");
96 if (definitionDao instanceof Refreshable) {
97 ((Refreshable) definitionDao).refresh();
98 }
99 }
100
101
102 /**
103 * Indicates whether the DefinitionsFactory is out of date and needs to be
104 * reloaded.
105 *
106 * @return If the factory needs refresh.
107 */
108 public boolean refreshRequired() {
109 return (definitionDao instanceof RefreshMonitor)
110 && ((RefreshMonitor) definitionDao).refreshRequired();
111 }
112
113 /**
114 * Indicates whether a given context has been processed or not.
115 * <p/>
116 * This method can be used to avoid unnecessary synchronization of the
117 * DefinitionsFactory in multi-threaded situations. Check the return of
118 * isContextProcessed before synchronizing the object and reading
119 * locale-specific definitions.
120 *
121 * @param tilesContext The Tiles context to check.
122 * @return true if the given context has been processed and false otherwise.
123 * @deprecated It always return <code>true</code>.
124 */
125 @Deprecated
126 protected boolean isContextProcessed(TilesRequestContext tilesContext) {
127 return true;
128 }
129
130 /**
131 * Adds a source where Definition objects are stored.
132 * <p/>
133 * Implementations should publish what type of source object they expect.
134 * The source should contain enough information to resolve a configuration
135 * source containing definitions. The source should be a "base" source for
136 * configurations. Internationalization and Localization properties will be
137 * applied by implementations to discriminate the correct data sources based
138 * on locale.
139 *
140 * @param source The configuration source for definitions.
141 * @throws DefinitionsFactoryException if an invalid source is passed in or
142 * an error occurs resolving the source to an actual data store.
143 * @deprecated Use {@link URLReader#addSourceURL(URL)}.
144 */
145 public void addSource(Object source) {
146 if (source == null) {
147 throw new DefinitionsFactoryException(
148 "Source object must not be null");
149 }
150
151 if (!(source instanceof URL)) {
152 throw new DefinitionsFactoryException(
153 "Source object must be an URL");
154 }
155
156 if (definitionDao instanceof URLReader) {
157 ((URLReader) definitionDao).addSourceURL((URL) source);
158 }
159 }
160
161 /**
162 * Creates the default definition DAO, if it has not been specified outside.
163 *
164 * @return The default definition DAO.
165 * @since 2.1.0
166 */
167 protected DefinitionDAO<Locale> createDefaultDefinitionDAO() {
168 return new ResolvingLocaleUrlDefinitionDAO();
169 }
170
171 /**
172 * Creates and returns a {@link Definitions} set by reading
173 * configuration data from the applied sources.
174 *
175 * @return The definitions holder object, filled with base definitions.
176 * @throws DefinitionsFactoryException if an error occurs reading the
177 * sources.
178 * @deprecated Let the Definitions Factory use it.
179 */
180 @Deprecated
181 public Definitions readDefinitions() {
182 return new CompatibilityDefinitionsImpl(definitionDao);
183 }
184
185 /**
186 * Returns the definitions holder object.
187 *
188 * @return The definitions holder.
189 * @deprecated Do not use! Deprecated with no replacement.
190 */
191 @Deprecated
192 protected Definitions getDefinitions() {
193 return new CompatibilityDefinitionsImpl(definitionDao);
194 }
195
196 /**
197 * Appends locale-specific {@link Definition} objects to an existing
198 * {@link Definitions} set by reading locale-specific versions of
199 * the applied sources.
200 *
201 * @param definitions The Definitions object to append to.
202 * @param tilesContext The requested locale.
203 * @throws DefinitionsFactoryException if an error occurs reading definitions.
204 * @deprecated Let the definitions be loaded by a {@link DefinitionDAO}.
205 */
206 @Deprecated
207 protected void addDefinitions(Definitions definitions,
208 TilesRequestContext tilesContext) {
209 Locale locale = localeResolver.resolveLocale(tilesContext);
210 Map<String, Definition> defsMap = definitionDao.getDefinitions(locale);
211 if (defsMap == null) {
212 throw new NullPointerException(
213 "There are no definitions mapped to locale '"
214 + locale.toString() + "'");
215 }
216 }
217
218 /**
219 * Creates a new instance of <code>Definitions</code>. Override this method
220 * to provide your custom instance of Definitions.
221 *
222 * @return A new instance of <code>Definitions</code>.
223 * @deprecated Do not use! Deprecated with no replacement.
224 */
225 @Deprecated
226 protected Definitions createDefinitions() {
227 return new CompatibilityDefinitionsImpl(definitionDao);
228 }
229
230 /**
231 * Concat postfix to the name. Take care of existing filename extension.
232 * Transform the given name "name.ext" to have "name" + "postfix" + "ext".
233 * If there is no ext, return "name" + "postfix".
234 *
235 * @param name Filename.
236 * @param postfix Postfix to add.
237 * @return Concatenated filename.
238 * @deprecated Use {@link LocaleUtil#concatPostfix(String,String)} instead
239 */
240 protected static String concatPostfix(String name, String postfix) {
241 return LocaleUtil.concatPostfix(name, postfix);
242 }
243
244 /**
245 * Calculate the postfixes along the search path from the base bundle to the
246 * bundle specified by baseName and locale.
247 * Method copied from java.util.ResourceBundle
248 *
249 * @param locale the locale
250 * @return a list of
251 * @deprecated Use {@link LocaleUtil#calculatePostfixes(Locale)} instead.
252 */
253 protected static List<String> calculatePostfixes(Locale locale) {
254 return LocaleUtil.calculatePostfixes(locale);
255 }
256
257 /**
258 * Derive the resource string from the initialization parameters. If no
259 * parameter {@link DefinitionsFactory#DEFINITIONS_CONFIG} is available,
260 * attempts to retrieve {@link BasicTilesContainer#DEFINITIONS_CONFIG} and
261 * {@link UrlDefinitionsFactory#LEGACY_DEFINITIONS_CONFIG}. If neither are
262 * available, returns "/WEB-INF/tiles.xml".
263 *
264 * @param parms The initialization parameters.
265 * @return resource string to be parsed.
266 * @deprecated Deprecated without replacement.
267 */
268 @Deprecated
269 protected String getResourceString(Map<String, String> parms) {
270 String resourceStr = parms.get(DefinitionsFactory.DEFINITIONS_CONFIG);
271 if (resourceStr == null) {
272 resourceStr = parms.get(BasicTilesContainer.DEFINITIONS_CONFIG);
273 }
274 if (resourceStr == null) {
275 resourceStr = parms.get(UrlDefinitionsFactory.LEGACY_DEFINITIONS_CONFIG);
276 }
277 if (resourceStr == null) {
278 resourceStr = "/WEB-INF/tiles.xml";
279 }
280 return resourceStr;
281 }
282
283 /**
284 * Parse the resourceString into a list of resource paths
285 * which can be loaded by the application context.
286 *
287 * @param resourceString comma seperated resources
288 * @return parsed resources
289 * @deprecated Deprecated without replacement.
290 */
291 @Deprecated
292 protected List<String> getResourceNames(String resourceString) {
293 StringTokenizer tokenizer = new StringTokenizer(resourceString, ",");
294 List<String> filenames = new ArrayList<String>(tokenizer.countTokens());
295 while (tokenizer.hasMoreTokens()) {
296 filenames.add(tokenizer.nextToken().trim());
297 }
298 return filenames;
299 }
300
301 /**
302 * {@link Definitions} implementation that uses a {@link DefinitionDAO}.
303 *
304 * @since 2.1.0
305 * @deprecated Here only for compatibility reasons.
306 */
307 @Deprecated
308 private static final class CompatibilityDefinitionsImpl implements Definitions {
309
310 /**
311 * The definition DAO to use.
312 *
313 * @since 2.1.0
314 */
315 private DefinitionDAO<Locale> definitionDao;
316
317 /**
318 * Constructor.
319 *
320 * @param definitionDao The definition DAO to use.
321 * @since 2.1.0
322 */
323 public CompatibilityDefinitionsImpl(DefinitionDAO<Locale> definitionDao) {
324 this.definitionDao = definitionDao;
325 }
326
327 /** {@inheritDoc} */
328 public void addDefinitions(Map<String, Definition> defsMap) {
329 Map<String, Definition> definitions = definitionDao
330 .getDefinitions(null);
331 if (definitions == null) {
332 throw new NullPointerException(
333 "No definitions loaded for default locale");
334 }
335 definitions.putAll(defsMap);
336 }
337
338 /** {@inheritDoc} */
339 public void addDefinitions(Map<String, Definition> defsMap,
340 Locale locale) {
341 Map<String, Definition> definitions = definitionDao
342 .getDefinitions(locale);
343 if (definitions == null) {
344 throw new NullPointerException(
345 "No definitions loaded for locale '"
346 + locale.toString() + "'");
347 }
348 definitions.putAll(defsMap);
349 }
350
351 /** {@inheritDoc} */
352 public Map<String, Definition> getBaseDefinitions() {
353 return definitionDao.getDefinitions(null);
354 }
355
356 /** {@inheritDoc} */
357 public Definition getDefinition(String name) {
358 return definitionDao.getDefinition(name, null);
359 }
360
361 /** {@inheritDoc} */
362 public Definition getDefinition(String name, Locale locale) {
363 return definitionDao.getDefinition(name, locale);
364 }
365
366 /** {@inheritDoc} */
367 public void reset() {
368 if (definitionDao instanceof Refreshable) {
369 ((Refreshable) definitionDao).refresh();
370 }
371 }
372
373 /** {@inheritDoc} */
374 public void resolveInheritances() {
375 // Does nothing.
376 }
377
378 /** {@inheritDoc} */
379 public void resolveInheritances(Locale locale) {
380 // Does nothing.
381 }
382 }
383 }