View Javadoc

1   /*
2    * $Id: ContextImpl.java 118 2004-10-23 18:45:01Z josem $
3    *
4    * Tarsis
5    * Copyright (C) 2002 Talika Open Source Group
6    *
7    * This program is free software; you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation; either version 2 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with this program; if not, write to the Free Software
19   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20   *
21   */
22  
23  package org.talika.tarsis.context;
24  
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.net.MalformedURLException;
28  import java.net.URL;
29  import java.util.Collections;
30  import java.util.HashMap;
31  import java.util.Iterator;
32  import java.util.Map;
33  
34  import javax.servlet.ServletContext;
35  import javax.xml.parsers.ParserConfigurationException;
36  import javax.xml.parsers.SAXParserFactory;
37  
38  import org.talika.tarsis.Globals;
39  import org.talika.tarsis.command.factory.CommandFactory;
40  import org.talika.tarsis.command.factory.CommandFactoryService;
41  import org.talika.tarsis.factory.Factory;
42  import org.talika.tarsis.factory.FactoryService;
43  import org.talika.tarsis.log.Logger;
44  import org.talika.tarsis.log.LoggerHandler;
45  import org.talika.tarsis.security.Authenticator;
46  import org.talika.tarsis.security.AuthenticatorService;
47  import org.talika.tarsis.security.Authorizator;
48  import org.talika.tarsis.security.AuthorizatorService;
49  import org.talika.tarsis.service.ServiceException;
50  import org.xml.sax.InputSource;
51  import org.xml.sax.SAXException;
52  import org.xml.sax.SAXParseException;
53  import org.xml.sax.XMLReader;
54  
55  /**
56   * Implementation of <code>Context</code> interface.
57   *
58   * @author  Jose M. Palomar
59   * @version $Revision: 118 $
60   */
61  public final class ContextImpl implements Context {
62  
63      // Fields
64      /**
65       * Singleton instance.
66       */
67      private static ContextImpl context;
68  
69      /**
70       * Init parameters map of this context.
71       */
72      private Map initParameters;
73  
74      /**
75       * <code>Authenticator</code> defined for this context.
76       */
77      private AuthenticatorService authc;
78  
79      /**
80       * <code>Authorizator</code> defined for this context.
81       */
82      private AuthorizatorService authz;
83  
84      /**
85       * <code>Logger</code> defined for this context.
86       */
87      private LoggerHandler logger;
88  
89      /**
90       * <code>CommandFactory</code> defined for this context.
91       */
92      private CommandFactoryService commandFactory;
93  
94      /**
95       * Map of <code>Factory</code> objects defined for this context.
96       */
97      private Map factories;
98  
99      /**
100      * <code>ServletContext</code> of web application.
101      */
102     private ServletContext ctx;
103 
104     /**
105      * Is context loaded?
106      */
107     private boolean loaded;
108 
109     /**
110      * Is context initialized?
111      */
112     private boolean initialized;
113 
114     // Constructors
115     /**
116      * Creates a new <code>ContextImpl</code> object.
117      */
118     private ContextImpl() {
119         this.initParameters = new HashMap();
120         this.factories = new HashMap();
121         this.logger = new LoggerHandler();
122     }
123 
124     // Methods
125     /**
126      * Returns singleton <code>ContextImpl</code> instance.
127      *
128      * @return Context singleton <code>ContextImpl</code> instance.
129      */
130     public static ContextImpl getInstance() {
131 
132         if (context == null) {
133             context = new ContextImpl();
134         }
135 
136         return context;
137     }
138 
139     // Life cycle
140     /**
141      * Called on starts up of the Tarsis MVC Framework and put all components in
142      * service.<br>
143      * <br>
144      * Initializing sequence is:
145      * <ol>
146      * <li>Loads context configuration file.</li>
147      * <li>Initializes loggers.</li>
148      * <li>Initializes command factory.</li>
149      * <li>Initializes authenticator and authorizator if any are configured.</li>
150      * <li>Initializes factories if any are configured.</li>
151      * </ol>
152      *
153      * @param ctx ServletContext the <code>ServletContext</code> of web application
154      * where Tarsis MVC Framework is contained.
155      * @throws ConfigException if there is any problem loading configuration.
156      * @throws ServiceException if there is any problem initializing services.
157      */
158     public void init(ServletContext ctx) throws ConfigException, ServiceException {
159 
160         if (this.initialized) {
161             return;
162         }
163 
164         // Set Context
165         this.ctx = ctx;
166 
167         // Load context File
168         loadConfig();
169 
170         // Init Services
171         this.logger.init(this);
172 
173         this.commandFactory.init(this);
174 
175         if (this.authc != null) {
176             this.authc.init(this);
177         }
178 
179         if (this.authz != null) {
180             this.authz.init(this);
181         }
182 
183         Iterator factoryIterator = this.factories.values().iterator();
184         while (factoryIterator.hasNext()) {
185             FactoryService service = (FactoryService) factoryIterator.next();
186             service.init(this);
187         }
188 
189         this.initialized = true;
190 
191     }
192 
193     /**
194      * Called on shutdown of the Tarsis MVC Framework and put all components out of
195      * service.
196      */
197     public void destroy() {
198 
199         if (!this.initialized) {
200             return;
201         }
202 
203         // Destroy Services
204         this.commandFactory.destroy();
205 
206         Iterator factoryIterator = this.factories.values().iterator();
207         while (factoryIterator.hasNext()) {
208             FactoryService service = (FactoryService) factoryIterator.next();
209             service.destroy();
210         }
211         this.factories.clear();
212 
213         if (this.authc != null) {
214             this.authc.destroy();
215             this.authc = null;
216         }
217 
218         if (this.authz != null) {
219             this.authz.destroy();
220             this.authz = null;
221         }
222 
223         this.initParameters.clear();
224 
225         this.logger.destroy();
226 
227         this.ctx = null;
228         this.initialized = false;
229     }
230 
231     /**
232      * Load context configuration from an XML file. The Tarsis MVC Framework
233      * configuration file is <code>/WEB-INF/tarsis-config.xml</code>.
234      *
235      * @throws ConfigException if there is any problems or errors loading config file.
236      */
237     private void loadConfig() throws ConfigException {
238 
239         if (this.loaded) {
240             return;
241         }
242 
243         try {
244 
245             InputStream contextStream = ctx.getResourceAsStream(Globals.CONFIG_FILE);
246             if (contextStream == null) {
247                 throw new ConfigException("Config file not found");
248             }
249 
250             InputSource input = new InputSource(contextStream);
251 
252             SAXParserFactory spf = SAXParserFactory.newInstance();
253             spf.setValidating(true);
254             spf.setNamespaceAware(false);
255 
256             XMLReader parser = null;
257             parser = spf.newSAXParser().getXMLReader();
258             XmlConfigHandler handler = new XmlConfigHandler();
259             parser.setContentHandler(handler);
260             parser.setErrorHandler(handler);
261             parser.setEntityResolver(handler);
262             parser.parse(input);
263 
264             this.initParameters.putAll(handler.getInitParameters());
265             this.authc = handler.getAuthenticathor();
266             this.authz = handler.getAuthorizator();
267             this.factories.putAll(handler.getFactories());
268             this.logger.addLoggers(handler.getLoggers());
269             this.commandFactory = handler.getCommandFactory();
270 
271         }
272         catch (SAXParseException spe) {
273             throw new ConfigException("Error parsing context: " + spe.getMessage());
274         }
275         catch (SAXException se) {
276             if (se.getException() != null) {
277                 throw new ConfigException("Error parsing context: " +
278                                             se.getException().getMessage());
279             }
280             else {
281                 throw new ConfigException("Error parsing context: " + se.getMessage());
282             }
283         }
284         catch (ParserConfigurationException pce) {
285             throw new ConfigException("Error parsing context: " + pce.getMessage());
286         }
287         catch (IOException ioe) {
288             throw new ConfigException("Error parsing context: " + ioe.getMessage());
289         }
290 
291         this.loaded = true;
292 
293     }
294 
295     // Accesors
296     /**
297      * Returns default <code>Authenticator</code> for this context.
298      *
299      * @return Authenticator default <code>Authenticator</code> for this context.
300      * @see org.talika.tarsis.context.Context#getAuthenticator()
301      */
302     public Authenticator getAuthenticator() {
303         return authc;
304     }
305 
306     /**
307      * Returns default <code>Authorizator</code> for this context.
308      *
309      * @return Authorizator default <code>Authorizator</code> for this context.
310      * @see org.talika.tarsis.context.Context#getAuthorizator()
311      */
312     public Authorizator getAuthorizator() {
313         return authz;
314     }
315 
316     /**
317      * Returns an init parameter of this context.
318      *
319      * @param name String name of parameter.
320      * @return String value of parameter or <code>null</code> if parameter does not
321      * exist.
322      * @see org.talika.tarsis.context.Context#getInitParameter(String)
323      */
324     public String getInitParameter(String name) {
325         return (String) initParameters.get(name);
326     }
327 
328     /**
329      * Returns a map with all the init parameters of this context.
330      *
331      * @return Map map with all the init parameters of this context.
332      * @see org.talika.tarsis.context.Context#getInitParameters()
333      */
334     public Map getInitParameters() {
335         return Collections.unmodifiableMap(initParameters);
336     }
337 
338     /**
339      * Returns <code>Logger</code> of this context.
340      *
341      * @return Logger <code>Logger</code> of this context.
342      * @see org.talika.tarsis.context.Context#getLogger()
343      */
344     public Logger getLogger() {
345         return logger;
346     }
347 
348     /**
349      * Returns default <code>CommandFactory</code> for this context.
350      *
351      * @return CommandFactory default <code>CommandFactory</code> for this context.
352      * @see org.talika.tarsis.context.Context#getCommandFactory()
353      */
354     public CommandFactory getCommandFactory() {
355         return commandFactory;
356     }
357 
358     /**
359      * Returns an object <code>Factory</code> for given name in this context.
360      *
361      * @param name String name of factory.
362      * @return Factory object <code>Factory</code> for given name in this context or
363      * <code>null</code> if does not exist.
364      * @see org.talika.tarsis.context.Context#getFactory(String)
365      */
366     public Factory getFactory(String name) {
367         return (Factory) factories.get(name);
368     }
369 
370     /**
371      * Returns a URL to the resource that is mapped to a specified path.
372      *
373      * @param path String a <code>String</code> specifying the path to the resource.
374      * @return URL the resource located at the named path, or <code>null</code> if
375      * there is no resource at that path.
376      * @throws MalformedURLException if the pathname is not given in the correct form.
377      * @see javax.servlet.ServletContext#getResource(java.lang.String)
378      * @see org.talika.tarsis.context.Context#getResource(String)
379      */
380     public URL getResource(String path) throws MalformedURLException {
381         return ctx.getResource(path);
382     }
383 
384     /**
385      * Returns the resource located at the named path as an <code>InputStream</code>
386      * object.
387      *
388      * @param path String a <code>String</code> specifying the path to the resource.
389      * @return InputStream the <code>InputStream</code> returned to the servlet, or
390      * <code>null</code> if no resource exists at the specified path.
391      * @see javax.servlet.ServletContext#getResourceAsStream(java.lang.String)
392      * @see org.talika.tarsis.context.Context#getResourceAsStream(String)
393      */
394     public InputStream getResourceAsStream(String path) {
395         return ctx.getResourceAsStream(path);
396     }
397 
398     /**
399      * Returns a String containing the real path for a given virtual path.
400      *
401      * @param path String a <code>String</code> specifying the path to the resource.
402      * @return String a <code>String</code> specifying the real path, or
403      * <code>null</code> if the translation cannot be performed
404      * @see javax.servlet.ServletContext#getRealPath(java.lang.String)
405      * @see org.talika.tarsis.context.Context#getRealPath(String)
406      */
407     public String getRealPath(String path) {
408         return ctx.getRealPath(path);
409     }
410 
411 }