KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > bean > CocoonWrapper


1 /*
2  * Copyright 1999-2005 The Apache Software Foundation.
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 org.apache.cocoon.bean;
17
18 import java.io.File JavaDoc;
19 import java.io.FileInputStream JavaDoc;
20 import java.io.FileNotFoundException JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.OutputStream JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Arrays JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.TreeMap JavaDoc;
31
32 import org.apache.avalon.excalibur.component.ExcaliburComponentManager;
33 import org.apache.avalon.excalibur.logger.LogKitLoggerManager;
34
35 import org.apache.avalon.framework.configuration.Configuration;
36 import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
37 import org.apache.avalon.framework.container.ContainerUtil;
38 import org.apache.avalon.framework.context.DefaultContext;
39 import org.apache.avalon.framework.logger.LogKitLogger;
40 import org.apache.avalon.framework.logger.Logger;
41
42 import org.apache.cocoon.Cocoon;
43 import org.apache.cocoon.CocoonAccess;
44 import org.apache.cocoon.Constants;
45 import org.apache.cocoon.ProcessingException;
46 import org.apache.cocoon.components.CocoonComponentManager;
47 import org.apache.cocoon.components.pipeline.ProcessingPipeline;
48 import org.apache.cocoon.environment.Environment;
49 import org.apache.cocoon.environment.commandline.CommandLineContext;
50 import org.apache.cocoon.environment.commandline.FileSavingEnvironment;
51 import org.apache.cocoon.environment.commandline.LinkSamplingEnvironment;
52 import org.apache.cocoon.util.ClassUtils;
53 import org.apache.cocoon.util.IOUtils;
54 import org.apache.cocoon.util.NetUtils;
55 import org.apache.cocoon.xml.ContentHandlerWrapper;
56 import org.apache.cocoon.xml.XMLConsumer;
57 import org.apache.commons.lang.SystemUtils;
58
59 import org.apache.log.Hierarchy;
60 import org.apache.log.Priority;
61 import org.xml.sax.ContentHandler JavaDoc;
62
63 /**
64  * The Cocoon Wrapper simplifies usage of the Cocoon object. Allows to create,
65  * configure Cocoon instance and process single requests.
66  *
67  * @author <a HREF="mailto:stefano@apache.org">Stefano Mazzocchi</a>
68  * @author <a HREF="mailto:nicolaken@apache.org">Nicola Ken Barozzi</a>
69  * @author <a HREF="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
70  * @author <a HREF="mailto:uv@upaya.co.uk">Upayavira</a>
71  * @version $Id: CocoonWrapper.java 231273 2005-08-10 15:54:19Z sylvain $
72  */

73 public class CocoonWrapper {
74
75     protected static final String JavaDoc DEFAULT_USER_AGENT = Constants.COMPLETE_NAME;
76     protected static final String JavaDoc DEFAULT_ACCEPT = "text/html, */*";
77
78     // User Supplied Parameters
79
private String JavaDoc contextDir = Constants.DEFAULT_CONTEXT_DIR;
80     private String JavaDoc configFile = null;
81
82     private String JavaDoc workDir = Constants.DEFAULT_WORK_DIR;
83     private String JavaDoc logKit = null;
84     protected String JavaDoc logger = null;
85     protected String JavaDoc logLevel = "ERROR";
86     private String JavaDoc userAgent = DEFAULT_USER_AGENT;
87     private String JavaDoc accept = DEFAULT_ACCEPT;
88     private List JavaDoc classList = new ArrayList JavaDoc();
89
90     // Objects used alongside User Supplied Parameters
91
private File JavaDoc context;
92     private File JavaDoc work;
93     private File JavaDoc conf;
94
95     // Internal Objects
96
private CommandLineContext cliContext;
97     private LogKitLoggerManager logManager;
98     private Cocoon cocoon;
99     protected Logger log;
100     private HashMap JavaDoc empty = new HashMap JavaDoc();
101
102     private boolean initialized = false;
103     private boolean useExistingCocoon = false;
104
105     //
106
// INITIALISATION METHOD
107
//
108
public void initialize() throws Exception JavaDoc {
109         // @todo@ these should log then throw exceptions back to the caller, not use system.exit()
110

111         // Create a new hierarchy. This is needed when CocoonBean is called from
112
// within a CocoonServlet call, in order not to mix logs
113
final Hierarchy hierarchy = new Hierarchy();
114
115         final Priority priority = Priority.getPriorityForName(logLevel);
116         hierarchy.setDefaultPriority(priority);
117
118         // Install a temporary logger so that getDir() can log if needed
119
this.log = new LogKitLogger(hierarchy.getLoggerFor(""));
120
121         try {
122             // First of all, initialize the logging system
123

124             // Setup the application context with context-dir and work-dir that
125
// can be used in logkit.xconf
126
this.context = getDir(this.contextDir, "context");
127             this.work = getDir(workDir, "working");
128             DefaultContext appContext = new DefaultContext();
129             appContext.put(Constants.CONTEXT_WORK_DIR, work);
130
131             this.logManager = new LogKitLoggerManager(hierarchy);
132             this.logManager.enableLogging(log);
133
134             if (this.logKit != null) {
135                 final FileInputStream JavaDoc fis = new FileInputStream JavaDoc(logKit);
136                 final DefaultConfigurationBuilder builder =
137                     new DefaultConfigurationBuilder();
138                 final Configuration logKitConf = builder.build(fis);
139                 final DefaultContext subcontext = new DefaultContext(appContext);
140                 subcontext.put("context-root", this.contextDir);
141                 subcontext.put("context-work", this.workDir);
142                 this.logManager.contextualize(subcontext);
143                 this.logManager.configure(logKitConf);
144                 if (logger != null) {
145                     log = this.logManager.getLoggerForCategory(logger);
146                 } else {
147                     log = this.logManager.getLoggerForCategory("cocoon");
148                 }
149             }
150
151             this.conf = getConfigurationFile(this.context, this.configFile);
152
153             cliContext = new CommandLineContext(contextDir);
154             cliContext.enableLogging(log);
155
156             appContext.put(Constants.CONTEXT_ENVIRONMENT_CONTEXT, cliContext);
157             appContext.put(Constants.CONTEXT_CLASS_LOADER,
158                     CocoonWrapper.class.getClassLoader());
159             appContext.put(Constants.CONTEXT_CLASSPATH, getClassPath(contextDir));
160             appContext.put(Constants.CONTEXT_UPLOAD_DIR, contextDir + "upload-dir");
161             File JavaDoc cacheDir = getDir(workDir + File.separator + "cache-dir", "cache");
162             appContext.put(Constants.CONTEXT_CACHE_DIR, cacheDir);
163             appContext.put(Constants.CONTEXT_CONFIG_URL, conf.toURL());
164             appContext.put(Constants.CONTEXT_DEFAULT_ENCODING, "ISO-8859-1");
165
166             loadClasses(classList);
167
168             if (this.useExistingCocoon) {
169                 cocoon = getCocoon();
170             }
171             if (cocoon == null) {
172                 cocoon = new Cocoon();
173                 ContainerUtil.enableLogging(cocoon, log);
174                 ContainerUtil.contextualize(cocoon, appContext);
175                 cocoon.setLoggerManager(logManager);
176                 ContainerUtil.initialize(cocoon);
177             }
178         } catch (Exception JavaDoc e) {
179             log.fatalError("Exception caught", e);
180             throw e;
181         }
182         initialized = true;
183     }
184
185     private Cocoon getCocoon() {
186         return new CocoonAccess() {
187             final Cocoon instance() {
188                 return super.getCocoon();
189             }
190         }.instance();
191     }
192     
193     protected ExcaliburComponentManager getComponentManager() {
194         return cocoon.getComponentManager();
195     }
196
197     /**
198      * Look around for the configuration file.
199      *
200      * @param dir a <code>File</code> where to look for configuration files
201      * @return a <code>File</code> representing the configuration
202      * @exception IOException if an error occurs
203      */

204     private File JavaDoc getConfigurationFile(File JavaDoc dir, String JavaDoc configFile)
205         throws IOException JavaDoc {
206         File JavaDoc conf;
207         if (configFile == null) {
208             conf = tryConfigurationFile(dir + File.separator + Constants.DEFAULT_CONF_FILE);
209             if (conf == null) {
210                 conf = tryConfigurationFile(dir
211                             + File.separator
212                             + "WEB-INF"
213                             + File.separator
214                             + Constants.DEFAULT_CONF_FILE);
215             }
216             if (conf == null) {
217                 conf = tryConfigurationFile(
218                         SystemUtils.USER_DIR
219                             + File.separator
220                             + Constants.DEFAULT_CONF_FILE);
221             }
222             if (conf == null) {
223                 conf = tryConfigurationFile(
224                         "/usr/local/etc/" + Constants.DEFAULT_CONF_FILE);
225             }
226         } else {
227             conf = new File JavaDoc(configFile);
228             if (!conf.exists()) {
229                 conf = new File JavaDoc(dir, configFile);
230             }
231         }
232         if (conf == null) {
233             log.error("Could not find the configuration file.");
234             throw new FileNotFoundException JavaDoc("The configuration file could not be found.");
235         }
236         return conf;
237     }
238
239     /**
240      * Try loading the configuration file from a single location
241      */

242     private File JavaDoc tryConfigurationFile(String JavaDoc filename) {
243         if (log.isDebugEnabled()) {
244             log.debug("Trying configuration file at: " + filename);
245         }
246         File JavaDoc conf = new File JavaDoc(filename);
247         if (conf.canRead()) {
248             return conf;
249         } else {
250             return null;
251         }
252     }
253
254     /**
255      * Get a <code>File</code> representing a directory.
256      *
257      * @param dir a <code>String</code> with a directory name
258      * @param type a <code>String</code> describing the type of directory
259      * @return a <code>File</code> value
260      * @exception IOException if an error occurs
261      */

262     private File JavaDoc getDir(String JavaDoc dir, String JavaDoc type) throws IOException JavaDoc {
263         if (log.isDebugEnabled()) {
264             log.debug("Getting handle to " + type + " directory '" + dir + "'");
265         }
266         File JavaDoc d = new File JavaDoc(dir);
267
268         if (!d.exists()) {
269             if (!d.mkdirs()) {
270                 throw new IOException JavaDoc(
271                     "Error creating " + type + " directory '" + d + "'");
272             }
273         }
274
275         if (!d.isDirectory()) {
276             throw new IOException JavaDoc("'" + d + "' is not a directory.");
277         }
278
279         if (!d.canRead()) {
280             throw new IOException JavaDoc(
281                 "Directory '" + d + "' is not readable");
282         }
283
284         if ("working".equals( type ) && !d.canWrite()) {
285             throw new IOException JavaDoc(
286                 "Directory '" + d + "' is not writable");
287         }
288
289         return d;
290     }
291
292     protected void finalize() throws Throwable JavaDoc {
293         dispose();
294         super.finalize();
295     }
296
297     protected void loadClasses(List JavaDoc classList) {
298         if (classList != null) {
299             for (Iterator JavaDoc i = classList.iterator(); i.hasNext();) {
300                 String JavaDoc className = (String JavaDoc) i.next();
301                 try {
302                     if (log.isDebugEnabled()) {
303                         log.debug("Trying to load class: " + className);
304                     }
305                     ClassUtils.loadClass(className).newInstance();
306                 } catch (Exception JavaDoc e) {
307                     if (log.isWarnEnabled()) {
308                         log.warn("Could not force-load class: " + className, e);
309                     }
310                     // Do not throw an exception, because it is not a fatal error.
311
}
312             }
313         }
314     }
315
316     //
317
// GETTERS AND SETTERS FOR CONFIGURATION PROPERTIES
318
//
319

320     /**
321      * Set LogKit configuration file name
322      * @param logKit LogKit configuration file
323      */

324     public void setLogKit(String JavaDoc logKit) {
325         this.logKit = logKit;
326     }
327
328     /**
329      * Set log level. Default is DEBUG.
330      * @param logLevel log level
331      */

332     public void setLogLevel(String JavaDoc logLevel) {
333         this.logLevel = logLevel;
334     }
335
336     /**
337      * Set logger category as default logger for the Cocoon engine
338      * @param logger logger category
339      */

340     public void setLogger(String JavaDoc logger) {
341         this.logger = logger;
342     }
343
344     public String JavaDoc getLoggerName() {
345         return logger;
346     }
347
348     /**
349      * Set context directory
350      * @param contextDir context directory
351      */

352     public void setContextDir(String JavaDoc contextDir) {
353         this.contextDir = contextDir;
354     }
355
356     /**
357      * Set working directory
358      * @param workDir working directory
359      */

360     public void setWorkDir(String JavaDoc workDir) {
361         this.workDir = workDir;
362     }
363
364     public void setConfigFile(String JavaDoc configFile) {
365         this.configFile = configFile;
366     }
367
368     public void setAgentOptions(String JavaDoc userAgent) {
369         this.userAgent = userAgent;
370     }
371
372     public void setAcceptOptions(String JavaDoc accept) {
373         this.accept = accept;
374     }
375
376     public void addLoadedClass(String JavaDoc className) {
377         this.classList.add(className);
378     }
379
380     public void addLoadedClasses(List JavaDoc classList) {
381         this.classList.addAll(classList);
382     }
383
384     public void setUseExistingCocoon(boolean useExistingCocoon) {
385         this.useExistingCocoon = useExistingCocoon;
386     }
387     
388     /**
389      * Process single URI into given output stream.
390      *
391      * @param uri to process
392      * @param outputStream to write generated contents into
393      */

394     public void processURI(String JavaDoc uri, OutputStream JavaDoc outputStream)
395         throws Exception JavaDoc {
396
397         if (!initialized) {
398             initialize();
399         }
400         log.info("Processing URI: " + uri);
401
402         // Get parameters, deparameterized URI and path from URI
403
final TreeMap JavaDoc parameters = new TreeMap JavaDoc();
404         final String JavaDoc deparameterizedURI =
405             NetUtils.deparameterize(uri, parameters);
406         parameters.put("user-agent", userAgent);
407         parameters.put("accept", accept);
408
409         int status =
410             getPage(deparameterizedURI, 0L, parameters, null, null, outputStream);
411
412         if (status >= 400) {
413             throw new ProcessingException("Resource not found: " + status);
414         }
415     }
416
417     /**
418      * Process single URI into given content handler, skipping final
419      * serializer
420      *
421      * @param uri to process
422      * @param handler to write generated contents into
423      */

424     public void processURI(String JavaDoc uri, ContentHandler JavaDoc handler)
425         throws Exception JavaDoc {
426
427         if (!initialized) {
428             initialize();
429         }
430         log.info("Processing URI: " + uri);
431
432         // Get parameters, deparameterized URI and path from URI
433
final TreeMap JavaDoc parameters = new TreeMap JavaDoc();
434         final String JavaDoc deparameterizedURI =
435             NetUtils.deparameterize(uri, parameters);
436         parameters.put("user-agent", userAgent);
437         parameters.put("accept", accept);
438
439         int status =
440             getPage(deparameterizedURI, 0L, parameters, null, null, handler);
441
442         if (status >= 400) {
443             throw new ProcessingException("Resource not found: " + status);
444         }
445     }
446
447     public void dispose() {
448         if (this.initialized) {
449             this.initialized = false;
450             ContainerUtil.dispose(this.cocoon);
451             this.cocoon = null;
452             this.logManager.dispose();
453             if (log.isDebugEnabled()) {
454                 log.debug("Disposed");
455             }
456         }
457     }
458
459     /**
460      * Samples an URI for its links.
461      *
462      * @param deparameterizedURI a <code>String</code> value of an URI to start sampling from
463      * @param parameters a <code>Map</code> value containing request parameters
464      * @return a <code>Collection</code> of links
465      * @exception Exception if an error occurs
466      */

467     protected Collection JavaDoc getLinks(String JavaDoc deparameterizedURI, Map JavaDoc parameters)
468         throws Exception JavaDoc {
469
470         parameters.put("user-agent", userAgent);
471         parameters.put("accept", accept);
472
473         LinkSamplingEnvironment env =
474             new LinkSamplingEnvironment(deparameterizedURI, context, null,
475                                         parameters, cliContext, log);
476         processLenient(env);
477         return env.getLinks();
478     }
479
480     /**
481      * Processes an URI for its content.
482      *
483      * @param deparameterizedURI a <code>String</code> value of an URI to start sampling from
484      * @param parameters a <code>Map</code> value containing request parameters
485      * @param links a <code>Map</code> value
486      * @param stream an <code>OutputStream</code> to write the content to
487      * @return a <code>String</code> value for the content
488      * @exception Exception if an error occurs
489      */

490     protected int getPage(String JavaDoc deparameterizedURI,
491                           long lastModified,
492                           Map JavaDoc parameters,
493                           Map JavaDoc links,
494                           List JavaDoc gatheredLinks,
495                           OutputStream JavaDoc stream)
496     throws Exception JavaDoc {
497
498         parameters.put("user-agent", userAgent);
499         parameters.put("accept", accept);
500
501         FileSavingEnvironment env =
502             new FileSavingEnvironment(deparameterizedURI, lastModified, context,
503                                       null, parameters, links,
504                                       gatheredLinks, cliContext, stream, log);
505
506         // Here Cocoon can throw an exception if there are errors in processing the page
507
cocoon.process(env);
508
509         // if we get here, the page was created :-)
510
int status = env.getStatus();
511         if (!env.isModified()) {
512             status = -1;
513         }
514         return status;
515     }
516
517     /**
518      * Processes an URI for its content.
519      *
520      * @param deparameterizedURI a <code>String</code> value of an URI to start sampling from
521      * @param parameters a <code>Map</code> value containing request parameters
522      * @param links a <code>Map</code> value
523      * @param handler an <code>ContentHandler</code> to send the content to
524      * @return a <code>String</code> value for the content
525      * @exception Exception if an error occurs
526      */

527     protected int getPage(String JavaDoc deparameterizedURI,
528                           long lastModified,
529                           Map JavaDoc parameters,
530                           Map JavaDoc links,
531                           List JavaDoc gatheredLinks,
532                           ContentHandler JavaDoc handler)
533     throws Exception JavaDoc {
534
535         parameters.put("user-agent", userAgent);
536         parameters.put("accept", accept);
537
538         FileSavingEnvironment env =
539             new FileSavingEnvironment(deparameterizedURI, lastModified, context,
540                                       null, parameters, links,
541                                       gatheredLinks, cliContext, null, log);
542
543         XMLConsumer consumer = new ContentHandlerWrapper(handler);
544         ProcessingPipeline pipeline = cocoon.buildPipeline(env);
545         CocoonComponentManager.enterEnvironment(env, cocoon.getComponentManager(), cocoon);
546         try {
547             pipeline.prepareInternal(env);
548             pipeline.process(env, consumer);
549         } finally {
550             CocoonComponentManager.leaveEnvironment();
551         }
552
553         // if we get here, the page was created :-)
554
int status = env.getStatus();
555         if (!env.isModified()) {
556             status = -1;
557         }
558         return status;
559     }
560
561     /** Class <code>NullOutputStream</code> here. */
562     static class NullOutputStream extends OutputStream JavaDoc {
563         public void write(int b) throws IOException JavaDoc {
564         }
565         public void write(byte b[]) throws IOException JavaDoc {
566         }
567         public void write(byte b[], int off, int len) throws IOException JavaDoc {
568         }
569     }
570
571     /**
572      * Analyze the type of content for an URI.
573      *
574      * @param deparameterizedURI a <code>String</code> value to analyze
575      * @param parameters a <code>Map</code> value for the request
576      * @return a <code>String</code> value denoting the type of content
577      * @exception Exception if an error occurs
578      */

579     protected String JavaDoc getType(String JavaDoc deparameterizedURI, Map JavaDoc parameters)
580         throws Exception JavaDoc {
581
582         parameters.put("user-agent", userAgent);
583         parameters.put("accept", accept);
584
585         FileSavingEnvironment env =
586             new FileSavingEnvironment(deparameterizedURI, context, null,
587                                       parameters, empty, null, cliContext,
588                                       new NullOutputStream(), log);
589         processLenient(env);
590         return env.getContentType();
591     }
592
593     /**
594      * Try to process something but don't throw a ProcessingException.
595      *
596      * @param env the <code>Environment</code> to process
597      * @return boolean true if no error were cast, false otherwise
598      * @exception Exception if an error occurs, except RNFE
599      */

600     private boolean processLenient(Environment env) throws Exception JavaDoc {
601         try {
602             this.cocoon.process(env);
603         } catch (ProcessingException pe) {
604             return false;
605         }
606         return true;
607     }
608
609     /**
610      * This builds the important ClassPath used by this class. It
611      * does so in a neutral way.
612      * It iterates in alphabetical order through every file in the
613      * lib directory and adds it to the classpath.
614      *
615      * Also, we add the files to the ClassLoader for the Cocoon system.
616      * In order to protect ourselves from skitzofrantic classloaders,
617      * we need to work with a known one.
618      *
619      * @param context The context path
620      * @return a <code>String</code> value
621      */

622     protected String JavaDoc getClassPath(final String JavaDoc context) {
623         StringBuffer JavaDoc buildClassPath = new StringBuffer JavaDoc();
624
625         String JavaDoc classDir = context + "/WEB-INF/classes";
626         buildClassPath.append(classDir);
627
628         File JavaDoc root = new File JavaDoc(context + "/WEB-INF/lib");
629         if (root.isDirectory()) {
630             File JavaDoc[] libraries = root.listFiles();
631             Arrays.sort(libraries);
632             for (int i = 0; i < libraries.length; i++) {
633                 if (libraries[i].getAbsolutePath().endsWith(".jar")) {
634                     buildClassPath.append(File.pathSeparatorChar).append(
635                         IOUtils.getFullFilename(libraries[i]));
636                 }
637             }
638         }
639
640         buildClassPath.append(File.pathSeparatorChar).append(SystemUtils.JAVA_CLASS_PATH);
641
642         // Extra class path is necessary for non-classloader-aware java compilers to compile XSPs
643
// buildClassPath.append(File.pathSeparatorChar)
644
// .append(getExtraClassPath(context));
645

646         if (log.isDebugEnabled()) {
647             log.debug("Context classpath: " + buildClassPath);
648         }
649         return buildClassPath.toString();
650     }
651 }
652
Popular Tags