KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > nl > hippo > cms > sitesdirectory > SitesDirectoryImpl


1 /*
2  * Copyright 2004 Hippo Webworks.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package nl.hippo.cms.sitesdirectory;
17
18 import java.io.InputStream JavaDoc;
19 import java.util.ArrayList JavaDoc;
20 import java.util.Enumeration JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.Properties JavaDoc;
26 import java.util.StringTokenizer JavaDoc;
27 import java.util.regex.Pattern JavaDoc;
28 import nl.hippo.cms.repositorylocation.RepositoryInformation;
29 import org.apache.avalon.framework.activity.Initializable;
30 import org.apache.avalon.framework.logger.AbstractLogEnabled;
31 import org.apache.avalon.framework.parameters.ParameterException;
32 import org.apache.avalon.framework.parameters.Parameterizable;
33 import org.apache.avalon.framework.parameters.Parameters;
34 import org.apache.avalon.framework.service.ServiceException;
35 import org.apache.avalon.framework.service.ServiceManager;
36 import org.apache.avalon.framework.service.Serviceable;
37 import org.apache.excalibur.source.Source;
38 import org.apache.excalibur.source.SourceResolver;
39
40 /**
41  * <p>
42  * A directory of sites to which the content in the CMS can be deployed.
43  * </p>
44  *
45  * <p>
46  * This component is configured using a properties file. The URI can be set
47  * using the parameter named <code>configurationUri</code> .The following
48  * property must be present:
49  * </p>
50  * <ul>
51  * <li><code>siteList</code>: comma-separated list of site
52  * IDs. Do not use spaces surrounding the commas. An empty list is allowed.
53  * </li>
54  * </ul>
55  *
56  * <p>
57  * Each site can have multiple natural language names. The names are determined
58  * from properties using the following format: <code>(site ID).name.(2-character
59  * language code)</code>.
60  * For example: <code>intranet.name.en=intranet</code>.
61  * </p>
62  *
63  * <p>
64  * To be able to determine whether a person is an editor for the site a marker
65  * privilege is used. For each site set the following two properties:
66  * </p>
67  * <ul>
68  * <li><code>(site ID).editorMarkerPrivilege.namespaceUri</code>;</li>
69  * <li><code>(site ID).editorMarkerPrivilege.name</code>.</li>
70  * </ul>
71  *
72  * <p>
73  * Each site has two repositories: a preview and a live one. For each repository
74  * the following properties must be set. The prefix of the properties is:
75  * <code>(site
76  * ID).repository.(repository role).</code>:
77  * </p>
78  * <ul>
79  * <li>host;</li>
80  * <li>port;</li>
81  * <li>realm;</li>
82  * <li>username;</li>
83  * <li>password;</li>
84  * <li>rootUri;</li>
85  * <li>baseUri.</li>
86  * </ul>
87  *
88  * @author Johan Stuyts
89  */

90 public class SitesDirectoryImpl extends AbstractLogEnabled
91         implements SitesDirectory, Serviceable, Parameterizable, Initializable
92 {
93     private static final String JavaDoc CONFIGURATION_URI_PARAMETER_NAME = "configurationUri";
94
95     private static final String JavaDoc DEFAULT_CONFIGURATION_URI = "context://noSites.properties";
96
97     private static final String JavaDoc SITE_LIST_PROPERTY_NAME = "siteList";
98
99     private static final String JavaDoc VALID_SITE_ID_REGEX = "^[a-zA-Z]+$";
100
101     private static final String JavaDoc EDITOR_MARKER_PRIVILEGE_NAMESPACE_URI_PROPERTY_SUFFIX = ".editorMarkerPrivilege.namespaceUri";
102
103     private static final String JavaDoc EDITOR_MARKER_PRIVILEGE_NAME_PROPERTY_SUFFIX = ".editorMarkerPrivilege.name";
104
105     private static final String JavaDoc PREVIEW_REPOSITORY_ROLE_NAME = "preview";
106
107     private static final String JavaDoc LIVE_REPOSITORY_ROLE_NAME = "live";
108
109     private static final String JavaDoc SITE_NAME_REGEX_PREFIX = "^";
110
111     private static final String JavaDoc SITE_NAME_REGEX_SUFFIX = "\\.name\\.[a-z][a-z]$";
112
113     private static final String JavaDoc REPOSITORY_PROPERTY_NAME_PART = ".repository.";
114
115     private static final String JavaDoc HOST_PROPERTY_SUFFIX = "host";
116
117     private static final String JavaDoc PORT_PROPERTY_SUFFIX = "port";
118
119     private static final String JavaDoc REALM_PROPERTY_SUFFIX = "realm";
120
121     private static final String JavaDoc USERNAME_PROPERTY_SUFFIX = "username";
122
123     private static final String JavaDoc PASSWORD_PROPERTY_SUFFIX = "password";
124
125     private static final String JavaDoc ROOT_URI_PROPERTY_SUFFIX = "rootUri";
126
127     private static final String JavaDoc BASE_URI_PROPERTY_SUFFIX = "baseUri";
128
129     /**
130      * <p>
131      * The service manager.
132      * </p>
133      */

134     private ServiceManager m_serviceManager;
135
136     /**
137      * <p>
138      * The SourceResolver URI to the properties file with the sites
139      * configuration.
140      * </p>
141      */

142     private String JavaDoc m_configurationUri;
143
144     /**
145      * <p>
146      * The sites listed in this directory.
147      * </p>
148      */

149     private Map JavaDoc m_sites = new HashMap JavaDoc();
150
151     /**
152      * <p>
153      * The order in which the sites were in the configuration file. The site
154      * IDs iterator will return the site IDs in this order.
155      * </p>
156      */

157     private List JavaDoc m_siteIdsOrder = new ArrayList JavaDoc();
158
159     /**
160      * <p>
161      * Create an instance of this class.
162      * </p>
163      */

164     public SitesDirectoryImpl()
165     {
166         super();
167     }
168
169     /**
170      * <p>
171      * Servicing handler. Called by the service manager so this object can
172      * obtain a reference to it.
173      * </p>
174      *
175      * @param serviceManager
176      * The service manager.
177      */

178     public void service(ServiceManager serviceManager) throws ServiceException
179     {
180         m_serviceManager = serviceManager;
181     }
182
183     /**
184      * <p>
185      * Read the configuration of this component.
186      * </p>
187      *
188      * @param params
189      * The parameters set for this component.
190      */

191     public void parameterize(Parameters params) throws ParameterException
192     {
193         m_configurationUri = params.getParameter(CONFIGURATION_URI_PARAMETER_NAME,
194                 DEFAULT_CONFIGURATION_URI);
195     }
196
197     /**
198      * <p>
199      * Initialize this component.
200      * </p>
201      */

202     public void initialize() throws Exception JavaDoc
203     {
204         Properties JavaDoc properties = new Properties JavaDoc();
205         Object JavaDoc sourceResolverAsObject = m_serviceManager.lookup(SourceResolver.ROLE);
206         try
207         {
208             if (sourceResolverAsObject instanceof SourceResolver)
209             {
210                 SourceResolver sourceResolver = (SourceResolver) sourceResolverAsObject;
211                 Source source = sourceResolver.resolveURI(m_configurationUri);
212                 try
213                 {
214                     if (source.exists())
215                     {
216                         InputStream JavaDoc input = source.getInputStream();
217                         try
218                         {
219                             properties.load(input);
220                         }
221                         finally
222                         {
223                             input.close();
224                         }
225                     }
226                     else
227                     {
228                         throw new IllegalArgumentException JavaDoc("The properties file specified by '"
229                                 + m_configurationUri + "' must exist.");
230                     }
231                 }
232                 finally
233                 {
234                     sourceResolver.release(source);
235                 }
236             }
237         }
238         finally
239         {
240             m_serviceManager.release(sourceResolverAsObject);
241         }
242         String JavaDoc siteList = properties.getProperty(SITE_LIST_PROPERTY_NAME);
243         if (siteList != null && !siteList.equals(""))
244         {
245             StringTokenizer JavaDoc siteListTokenizer = new StringTokenizer JavaDoc(siteList, ",");
246             while (siteListTokenizer.hasMoreTokens())
247             {
248                 String JavaDoc siteId = siteListTokenizer.nextToken();
249                 if (!isValidSiteId(siteId))
250                 {
251                     throw new IllegalArgumentException JavaDoc("Site ID '" + siteId + "' is not valid.");
252                 }
253                 SiteInformation siteInfo = retrieveSite(properties, siteId);
254                 m_sites.put(siteId, siteInfo);
255                 m_siteIdsOrder.add(siteId);
256             }
257         }
258     }
259
260     /**
261      * <p>
262      * Get the number of sites known by this directory.
263      * </p>
264      *
265      * @return The number of known sites.
266      */

267     public int getNumberOfSites()
268     {
269         return m_sites.size();
270     }
271
272     /**
273      * <p>
274      * Get an <code>Iterator</code> over the site IDs.
275      * </p>
276      *
277      * @return An <code>Iterator</code> over the site IDs.
278      */

279     public Iterator JavaDoc siteIdsIterator()
280     {
281         return m_siteIdsOrder.iterator();
282     }
283
284     /**
285      * <p>
286      * Get the site information associated with <code>siteId</code>.
287      * </p>
288      *
289      * @param siteId
290      * The site ID for which to retrieve the site information.
291      * @return The site information associated with <code>siteId</code>, or
292      * <code>null</code> if there is no information for
293      * <code>siteId</code>.
294      */

295     public SiteInformation getSite(String JavaDoc siteId)
296     {
297         return (SiteInformation) m_sites.get(siteId);
298     }
299
300     /**
301      * <p>
302      * Test whether <code>text</code> is a valid site ID.
303      * </p>
304      *
305      * @param text
306      * The text for which to determine that it is a valid site ID.
307      * @return <code>true</code> if <code>text</code> is a site ID,
308      * <code>false</code> otherwise.
309      */

310     private boolean isValidSiteId(String JavaDoc text)
311     {
312         return Pattern.matches(VALID_SITE_ID_REGEX, text);
313     }
314
315     /**
316      * <p>
317      * Retrieve the configuration information for a site.
318      * </p>
319      *
320      * @param properties
321      * The properties from which to read the configuration.
322      * @param siteId
323      * The site ID of the site for which to retrieve the
324      * configuration.
325      * @return A <code>SiteInformation</code> object with the site
326      * configuration associated with <code>siteId</code>.
327      */

328     private SiteInformation retrieveSite(Properties JavaDoc properties, String JavaDoc siteId)
329     {
330         SiteInformation result;
331
332         String JavaDoc editorMarkerPrivilegeNamespace = getRequiredProperty(properties, siteId
333                 + EDITOR_MARKER_PRIVILEGE_NAMESPACE_URI_PROPERTY_SUFFIX);
334         String JavaDoc editorMarkerPrivilegeName = getRequiredProperty(properties, siteId
335                 + EDITOR_MARKER_PRIVILEGE_NAME_PROPERTY_SUFFIX);
336         result = new SiteInformation(siteId, editorMarkerPrivilegeNamespace,
337                 editorMarkerPrivilegeName);
338         retrieveSiteNames(properties, result);
339         RepositoryInformation previewRepoInfo = retrieveRepositoryInformation(properties, result,
340                 PREVIEW_REPOSITORY_ROLE_NAME);
341         result.setPreviewRepository(previewRepoInfo);
342         RepositoryInformation liveRepoInfo = retrieveRepositoryInformation(properties, result,
343                 LIVE_REPOSITORY_ROLE_NAME);
344         result.setLiveRepository(liveRepoInfo);
345
346         return result;
347     }
348
349     /**
350      * <p>
351      * Retrieve the localized names of a site from the configuration.
352      * </p>
353      *
354      * @param properties
355      * The properties containing the configuration.
356      * @param siteInfo
357      * The <code>SiteInformation</code> for which the localized
358      * names must be retrieved.
359      */

360     private void retrieveSiteNames(Properties JavaDoc properties, SiteInformation siteInfo)
361     {
362         Pattern JavaDoc siteNamePattern = Pattern.compile(SITE_NAME_REGEX_PREFIX + siteInfo.getId()
363                 + SITE_NAME_REGEX_SUFFIX);
364         Enumeration JavaDoc keysEnum = properties.keys();
365         while (keysEnum.hasMoreElements())
366         {
367             String JavaDoc key = (String JavaDoc) keysEnum.nextElement();
368             if (siteNamePattern.matcher(key).matches())
369             {
370                 siteInfo.addName(key.substring(key.length() - 2), properties.getProperty(key));
371             }
372         }
373     }
374
375     /**
376      * <p>
377      * Retrieve the configuration information for a repository.
378      * </p>
379      *
380      * @param properties
381      * The properties containing the configuration.
382      * @param siteInfo
383      * The <code>SiteInformation</code> of the site to which the
384      * repository belongs.
385      * @param repositoryRole
386      * The role of the repository for the site.
387      * @return A <code>RepositoryInformation</code> object with the repository
388      * configuration belonging to the site of <code>siteInfo</code>
389      * and with role <code>repositoryRole</code>.
390      */

391     private RepositoryInformation retrieveRepositoryInformation(Properties JavaDoc properties,
392             SiteInformation siteInfo, String JavaDoc repositoryRole)
393     {
394         RepositoryInformation result;
395
396         String JavaDoc propertyPrefix = siteInfo.getId() + REPOSITORY_PROPERTY_NAME_PART + repositoryRole
397                 + '.';
398         String JavaDoc host = getRequiredProperty(properties, propertyPrefix + HOST_PROPERTY_SUFFIX);
399         int port = getRequiredIntegerProperty(properties, propertyPrefix + PORT_PROPERTY_SUFFIX, 1,
400                 65535);
401         String JavaDoc realm = getRequiredProperty(properties, propertyPrefix + REALM_PROPERTY_SUFFIX);
402         String JavaDoc username = getRequiredProperty(properties, propertyPrefix + USERNAME_PROPERTY_SUFFIX);
403         String JavaDoc password = getRequiredProperty(properties, propertyPrefix + PASSWORD_PROPERTY_SUFFIX);
404         String JavaDoc rootUri = getRequiredProperty(properties, propertyPrefix + ROOT_URI_PROPERTY_SUFFIX);
405         String JavaDoc baseUri = getRequiredProperty(properties, propertyPrefix + BASE_URI_PROPERTY_SUFFIX);
406         result = new RepositoryInformation(host, port, realm, username, password, rootUri, baseUri);
407
408         return result;
409     }
410
411     /**
412      * Get a property from <code>properties</code>. If it does not exist or
413      * is equal to the emtpy string, an
414      * {@link java.lang.IllegalArgumentException}is thrown.
415      *
416      * @param properties
417      * The {@link java.util.Properties}from which to retrieve the
418      * property.
419      * @param propertyKey
420      * The key of the property to retrieve.
421      * @return The value of the property associated with
422      * <code>propertyKey</code>.
423      */

424     public static String JavaDoc getRequiredProperty(Properties JavaDoc properties, String JavaDoc propertyKey)
425     {
426         String JavaDoc result = properties.getProperty(propertyKey);
427         if (result == null || result.equals(""))
428         {
429             throw new IllegalArgumentException JavaDoc("Property '" + propertyKey + "' is required.");
430         }
431         return result;
432     }
433
434     /**
435      * Get an integer property from <code>properties</code>. If it does not
436      * exist, is not an integer or is not in de range [
437      * <code>minimumValue</code>,<code>maximumValue</code>] an
438      * {@link IllegalArgumentException}is thrown.
439      *
440      * @param properties
441      * The {@link java.util.Properties}from which to retrieve the
442      * property.
443      * @param propertyKey
444      * The key of the property to retrieve.
445      * @param minimumValue
446      * The minimum value the property may have.
447      * @param maximumValue
448      * The maximum value the property may have.
449      * @return The value of the property associated with
450      * <code>propertyKey</code>.
451      */

452     public static int getRequiredIntegerProperty(Properties JavaDoc properties, String JavaDoc propertyKey,
453             int minimumValue, int maximumValue)
454     {
455         int result;
456
457         String JavaDoc integerAsString = properties.getProperty(propertyKey);
458         if (integerAsString == null || integerAsString.equals(""))
459         {
460             throw new IllegalArgumentException JavaDoc("Property '" + propertyKey
461                     + "' is required and must be an integer in the range [" + minimumValue + ", "
462                     + maximumValue + "].");
463         }
464         try
465         {
466             result = Integer.parseInt(integerAsString);
467         }
468         catch (NumberFormatException JavaDoc e)
469         {
470             throw new IllegalArgumentException JavaDoc(createInvalidIntegerMessage(propertyKey,
471                     minimumValue, maximumValue));
472         }
473         if (!(result >= minimumValue && result <= maximumValue))
474         {
475             throw new IllegalArgumentException JavaDoc(createInvalidIntegerMessage(propertyKey,
476                     minimumValue, maximumValue));
477         }
478
479         return result;
480     }
481
482     /**
483      * Factory method for messages about invalid integer values.
484      *
485      * @param propertyKey
486      * The property key of the property with the invalid value.
487      * @param minimumValue
488      * The minimum value the property may have.
489      * @param maximumValue
490      * The maximum value the property may have.
491      * @return An English message stating that the property associated with
492      * <code>propertyKey</code> is invalid.
493      */

494     private static String JavaDoc createInvalidIntegerMessage(String JavaDoc propertyKey, int minimumValue,
495             int maximumValue)
496     {
497         return "Property '" + propertyKey + "' must be an integer in the range [" + minimumValue
498                 + ", " + maximumValue + "].";
499     }
500 }
501
Popular Tags