KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > base > modules > AbstractModule


1 /* ========================================================================
2  * JCommon : a free general purpose class library for the Java(tm) platform
3  * ========================================================================
4  *
5  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
6  *
7  * Project Info: http://www.jfree.org/jcommon/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA.
23  *
24  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
25  * in the United States and other countries.]
26  *
27  * -------------------
28  * AbstractModule.java
29  * -------------------
30  * (C)opyright 2003, 2004, by Thomas Morgner and Contributors.
31  *
32  * Original Author: Thomas Morgner;
33  * Contributor(s): David Gilbert (for Object Refinery Limited);
34  *
35  * $Id: AbstractModule.java,v 1.3 2005/10/18 13:14:50 mungady Exp $
36  *
37  * Changes
38  * -------
39  * 05-Jul-2003 : Initial version
40  * 07-Jun-2004 : Added JCommon header (DG);
41  *
42  */

43
44 package org.jfree.base.modules;
45
46 import java.io.BufferedReader JavaDoc;
47 import java.io.IOException JavaDoc;
48 import java.io.InputStream JavaDoc;
49 import java.io.InputStreamReader JavaDoc;
50 import java.util.ArrayList JavaDoc;
51
52 import org.jfree.util.ObjectUtilities;
53
54
55 /**
56  * The abstract module provides a default implementation of the module interface.
57  * <p>
58  * The module can be specified in an external property file. The file name of this
59  * specification defaults to "module.properties". This file is no real property file,
60  * it follows a more complex rule set.
61  * <p>
62  * Lines starting with '#' are considered comments.
63  * Section headers start at the beginning of the line, section properties
64  * are indented with at least one whitespace.
65  * <p>
66  * The first section is always the module info and contains the basic module
67  * properties like name, version and a short description.
68  * <p>
69  * <pre>
70  * module-info:
71  * name: xls-export-gui
72  * producer: The JFreeReport project - www.jfree.org/jfreereport
73  * description: A dialog component for the Excel table export.
74  * version.major: 0
75  * version.minor: 84
76  * version.patchlevel: 0
77  * </pre>
78  * The properties name, producer and description are simple strings. They may
79  * span multiple lines, but may not contain a colon (':').
80  * The version properties are integer values.
81  * <p>
82  * This section may be followed by one or more "depends" sections. These
83  * sections describe the base modules that are required to be active to make this
84  * module work. The package manager will enforce this policy and will deactivate this
85  * module if one of the base modules is missing.
86  * <p>
87  * <pre>
88  * depends:
89  * module: org.jfree.report.modules.output.table.xls.XLSTableModule
90  * version.major: 0
91  * version.minor: 84
92  * </pre>
93  * <p>
94  * The property module references to the module implementation of the module package.
95  *
96  * @author Thomas Morgner
97  */

98 public abstract class AbstractModule extends DefaultModuleInfo implements Module
99 {
100   /**
101    * The reader helper provides a pushback interface for the reader to read and
102    * buffer complete lines.
103    * @author Thomas Morgner
104    */

105   private static class ReaderHelper
106   {
107     /** The line buffer containing the last line read. */
108     private String JavaDoc buffer;
109     /** The reader from which to read the text. */
110     private final BufferedReader JavaDoc reader;
111
112     /**
113      * Creates a new reader helper for the given buffered reader.
114      *
115      * @param reader the buffered reader that is the source of the text.
116      */

117     public ReaderHelper(final BufferedReader JavaDoc reader)
118     {
119       this.reader = reader;
120     }
121
122     /**
123      * Checks, whether the reader contains a next line. Returns false if the end
124      * of the stream has been reached.
125      *
126      * @return true, if there is a next line to read, false otherwise.
127      * @throws IOException if an error occures.
128      */

129     public boolean hasNext() throws IOException JavaDoc
130     {
131       if (this.buffer == null)
132       {
133         this.buffer = readLine();
134       }
135       return this.buffer != null;
136     }
137
138     /**
139      * Returns the next line.
140      *
141      * @return the next line.
142      */

143     public String JavaDoc next()
144     {
145       final String JavaDoc line = this.buffer;
146       this.buffer = null;
147       return line;
148     }
149
150     /**
151      * Pushes the given line back into the buffer. Only one line can be contained in
152      * the buffer at one time.
153      *
154      * @param line the line that should be pushed back into the buffer.
155      */

156     public void pushBack(final String JavaDoc line)
157     {
158       this.buffer = line;
159     }
160
161     /**
162      * Reads the next line skipping all comment lines.
163      *
164      * @return the next line, or null if no line can be read.
165      * @throws IOException if an IO error occures.
166      */

167     protected String JavaDoc readLine() throws IOException JavaDoc
168     {
169       String JavaDoc line = this.reader.readLine();
170       while (line != null && (line.length() == 0 || line.startsWith("#")))
171       {
172         // empty line or comment is ignored
173
line = this.reader.readLine();
174       }
175       return line;
176     }
177
178     /**
179      * Closes the reader.
180      *
181      * @throws IOException if an IOError occurs.
182      */

183     public void close() throws IOException JavaDoc
184     {
185       this.reader.close();
186     }
187   }
188
189   /** The list of required modules. */
190   private ModuleInfo[] requiredModules;
191   /** The list of optional modules. */
192   private ModuleInfo[] optionalModules;
193
194   /** The name of the module. */
195   private String JavaDoc name;
196   /** A short description of the module. */
197   private String JavaDoc description;
198   /** The name of the module producer. */
199   private String JavaDoc producer;
200   /** The modules subsystem. */
201   private String JavaDoc subsystem;
202
203   /**
204    * Default Constructor.
205    */

206   public AbstractModule()
207   {
208     setModuleClass(this.getClass().getName());
209   }
210
211   /**
212    * Loads the default module description from the file "module.properties". This file
213    * must be in the same package as the implementing class.
214    *
215    * @throws ModuleInitializeException if an error occurs.
216    */

217   protected void loadModuleInfo() throws ModuleInitializeException
218   {
219     final InputStream JavaDoc in = ObjectUtilities.getResourceRelativeAsStream
220             ("module.properties", getClass());
221     if (in == null)
222     {
223       throw new ModuleInitializeException
224           ("File 'module.properties' not found in module package.");
225     }
226     loadModuleInfo(in);
227   }
228
229   /**
230    * Loads the module descriptiong from the given input stream. The module description
231    * must conform to the rules define in the class description. The file must be encoded
232    * with "ISO-8859-1" (like property files).
233    *
234    * @param in the input stream from where to read the file
235    * @throws ModuleInitializeException if an error occurs.
236    */

237   protected void loadModuleInfo(final InputStream JavaDoc in) throws ModuleInitializeException
238   {
239     try
240     {
241       if (in == null)
242       {
243         throw new NullPointerException JavaDoc
244             ("Given InputStream is null.");
245       }
246       final ReaderHelper rh = new ReaderHelper(new BufferedReader JavaDoc
247           (new InputStreamReader JavaDoc(in, "ISO-8859-1")));
248
249       final ArrayList JavaDoc optionalModules = new ArrayList JavaDoc();
250       final ArrayList JavaDoc dependendModules = new ArrayList JavaDoc();
251
252       while (rh.hasNext())
253       {
254         final String JavaDoc lastLineRead = rh.next();
255         if (lastLineRead.startsWith("module-info:"))
256         {
257           readModuleInfo(rh);
258         }
259         else if (lastLineRead.startsWith("depends:"))
260         {
261           dependendModules.add(readExternalModule(rh));
262         }
263         else if (lastLineRead.startsWith("optional:"))
264         {
265           optionalModules.add(readExternalModule(rh));
266         }
267         else
268         {
269           // we dont understand the current line, so we skip it ...
270
// should we throw a parse exception instead?
271
}
272       }
273       rh.close();
274
275       this.optionalModules = (ModuleInfo[])
276           optionalModules.toArray(new ModuleInfo[optionalModules.size()]);
277
278       this.requiredModules = (ModuleInfo[])
279           dependendModules.toArray(new ModuleInfo[dependendModules.size()]);
280     }
281     catch (IOException JavaDoc ioe)
282     {
283       throw new ModuleInitializeException("Failed to load properties", ioe);
284     }
285   }
286
287   /**
288    * Reads a multiline value the stream. This will read the stream until
289    * a new key is found or the end of the file is reached.
290    *
291    * @param reader the reader from where to read.
292    * @param firstLine the first line (which was read elsewhere).
293    * @return the complete value, never null
294    * @throws IOException if an IO error occurs.
295    */

296   private String JavaDoc readValue(final ReaderHelper reader, String JavaDoc firstLine) throws IOException JavaDoc
297   {
298     final StringBuffer JavaDoc b = new StringBuffer JavaDoc(firstLine.trim());
299     boolean newLine = true;
300     while (isNextLineValueLine(reader))
301     {
302       firstLine = reader.next();
303       final String JavaDoc trimedLine = firstLine.trim();
304       if (trimedLine.length() == 0 && (newLine == false))
305       {
306         b.append ("\n");
307         newLine = true;
308       }
309       else
310       {
311         if (newLine == false)
312         {
313           b.append(" ");
314         }
315         b.append(parseValue(trimedLine));
316         newLine = false;
317       }
318     }
319     return b.toString();
320   }
321
322   /**
323    * Checks, whether the next line in the reader is a value line.
324    *
325    * @param reader from where to read the lines.
326    * @return true, if the next line is a value line, false otherwise.
327    * @throws IOException if an IO error occurs.
328    */

329   private boolean isNextLineValueLine (final ReaderHelper reader) throws IOException JavaDoc
330   {
331     if (reader.hasNext() == false)
332     {
333       return false;
334     }
335     final String JavaDoc firstLine = reader.next();
336     if (firstLine == null)
337     {
338       return false;
339     }
340     if (parseKey(firstLine) != null)
341     {
342       reader.pushBack(firstLine);
343       return false;
344     }
345     reader.pushBack(firstLine);
346     return true;
347   }
348
349   /**
350    * Reads the module definition header. This header contains information about
351    * the module itself.
352    *
353    * @param reader the reader from where to read the content.
354    * @throws IOException if an error occures
355    */

356   private void readModuleInfo(final ReaderHelper reader) throws IOException JavaDoc
357   {
358     while (reader.hasNext())
359     {
360       final String JavaDoc lastLineRead = reader.next();
361
362       if (Character.isWhitespace(lastLineRead.charAt(0)) == false)
363       {
364         // break if the current character is no whitespace ...
365
reader.pushBack(lastLineRead);
366         return;
367       }
368
369       final String JavaDoc line = lastLineRead.trim();
370       final String JavaDoc key = parseKey(line);
371       if (key != null)
372       {
373         // parse error: Non data line does not contain a colon
374
final String JavaDoc b = readValue(reader, parseValue(line.trim()));
375
376         if (key.equals("name"))
377         {
378           setName(b);
379         }
380         else if (key.equals("producer"))
381         {
382           setProducer(b);
383         }
384         else if (key.equals("description"))
385         {
386           setDescription(b);
387         }
388         else if (key.equals("subsystem"))
389         {
390           setSubSystem(b);
391         }
392         else if (key.equals("version.major"))
393         {
394           setMajorVersion(b);
395         }
396         else if (key.equals("version.minor"))
397         {
398           setMinorVersion(b);
399         }
400         else if (key.equals("version.patchlevel"))
401         {
402           setPatchLevel(b);
403         }
404       }
405     }
406   }
407
408   /**
409    * Parses an string to find the key section of the line. This section ends with
410    * an colon.
411    *
412    * @param line the line which to parse
413    * @return the key or null if no key is found.
414    */

415   private String JavaDoc parseKey(final String JavaDoc line)
416   {
417     final int idx = line.indexOf(':');
418     if (idx == -1)
419     {
420       return null;
421     }
422     return line.substring(0, idx);
423   }
424
425   /**
426    * Parses the value section of the given line.
427    *
428    * @param line the line that should be parsed
429    * @return the value, never null
430    */

431   private String JavaDoc parseValue(final String JavaDoc line)
432   {
433     final int idx = line.indexOf(':');
434     if (idx == -1)
435     {
436       return line;
437     }
438     if ((idx + 1) == line.length())
439     {
440       return "";
441     }
442     return line.substring(idx + 1);
443   }
444
445   /**
446    * Reads an external module description. This describes either an optional or
447    * a required module.
448    *
449    * @param reader the reader from where to read the module
450    * @return the read module, never null
451    * @throws IOException if an error occures.
452    */

453   private DefaultModuleInfo readExternalModule(final ReaderHelper reader)
454       throws IOException JavaDoc
455   {
456     final DefaultModuleInfo mi = new DefaultModuleInfo();
457
458     while (reader.hasNext())
459     {
460       final String JavaDoc lastLineRead = reader.next();
461
462       if (Character.isWhitespace(lastLineRead.charAt(0)) == false)
463       {
464         // break if the current character is no whitespace ...
465
reader.pushBack(lastLineRead);
466         return mi;
467       }
468
469       final String JavaDoc line = lastLineRead.trim();
470       final String JavaDoc key = parseKey(line);
471       if (key != null)
472       {
473         final String JavaDoc b = readValue(reader, parseValue(line));
474         if (key.equals("module"))
475         {
476           mi.setModuleClass(b);
477         }
478         else if (key.equals("version.major"))
479         {
480           mi.setMajorVersion(b);
481         }
482         else if (key.equals("version.minor"))
483         {
484           mi.setMinorVersion(b);
485         }
486         else if (key.equals("version.patchlevel"))
487         {
488           mi.setPatchLevel(b);
489         }
490       }
491     }
492     return mi;
493   }
494
495   /**
496    * Returns the name of this module.
497    *
498    * @see Module#getName()
499    *
500    * @return the module name
501    */

502   public String JavaDoc getName()
503   {
504     return this.name;
505   }
506
507   /**
508    * Defines the name of the module.
509    *
510    * @param name the module name.
511    */

512   protected void setName(final String JavaDoc name)
513   {
514     this.name = name;
515   }
516
517   /**
518    * Returns the module description.
519    * @see Module#getDescription()
520    *
521    * @return the description of the module.
522    */

523   public String JavaDoc getDescription()
524   {
525     return this.description;
526   }
527
528   /**
529    * Defines the description of the module.
530    *
531    * @param description the module's desciption.
532    */

533   protected void setDescription(final String JavaDoc description)
534   {
535     this.description = description;
536   }
537
538   /**
539    * Returns the producer of the module.
540    *
541    * @see Module#getProducer()
542    *
543    * @return the producer.
544    */

545   public String JavaDoc getProducer()
546   {
547     return this.producer;
548   }
549
550   /**
551    * Defines the producer of the module.
552    *
553    * @param producer the producer.
554    */

555   protected void setProducer(final String JavaDoc producer)
556   {
557     this.producer = producer;
558   }
559
560   /**
561    * Returns a copy of the required modules array. This array contains all
562    * description of the modules that need to be present to make this module work.
563    * @see Module#getRequiredModules()
564    *
565    * @return an array of all required modules.
566    */

567   public ModuleInfo[] getRequiredModules()
568   {
569     final ModuleInfo[] retval = new ModuleInfo[this.requiredModules.length];
570     System.arraycopy(this.requiredModules, 0, retval, 0, this.requiredModules.length);
571     return retval;
572   }
573
574   /**
575    * Returns a copy of the required modules array. This array contains all
576    * description of the optional modules that may improve the modules functonality.
577    * @see Module#getRequiredModules()
578    *
579    * @return an array of all required modules.
580    */

581   public ModuleInfo[] getOptionalModules()
582   {
583     final ModuleInfo[] retval = new ModuleInfo[this.optionalModules.length];
584     System.arraycopy(this.optionalModules, 0, retval, 0, this.optionalModules.length);
585     return retval;
586   }
587
588   /**
589    * Defines the required module descriptions for this module.
590    *
591    * @param requiredModules the required modules.
592    */

593   protected void setRequiredModules(final ModuleInfo[] requiredModules)
594   {
595     this.requiredModules = new ModuleInfo[requiredModules.length];
596     System.arraycopy(requiredModules, 0, this.requiredModules, 0, requiredModules.length);
597   }
598
599   /**
600    * Defines the optional module descriptions for this module.
601    *
602    * @param optionalModules the optional modules.
603    */

604   public void setOptionalModules(final ModuleInfo[] optionalModules)
605   {
606     this.optionalModules = new ModuleInfo[optionalModules.length];
607     System.arraycopy(optionalModules, 0, this.optionalModules, 0, optionalModules.length);
608   }
609
610   /**
611    * Returns a string representation of this module.
612    * @see java.lang.Object#toString()
613    *
614    * @return the string representation of this module for debugging purposes.
615    */

616   public String JavaDoc toString()
617   {
618     final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
619     buffer.append("Module : ");
620     buffer.append(getName());
621     buffer.append("\n");
622     buffer.append("ModuleClass : ");
623     buffer.append(getModuleClass());
624     buffer.append("\n");
625     buffer.append("Version: ");
626     buffer.append(getMajorVersion());
627     buffer.append(".");
628     buffer.append(getMinorVersion());
629     buffer.append(".");
630     buffer.append(getPatchLevel());
631     buffer.append("\n");
632     buffer.append("Producer: ");
633     buffer.append(getProducer());
634     buffer.append("\n");
635     buffer.append("Description: ");
636     buffer.append(getDescription());
637     buffer.append("\n");
638     return buffer.toString();
639   }
640
641   /**
642    * Tries to load a class to indirectly check for the existence
643    * of a certain library.
644    *
645    * @param name the name of the library class.
646    * @return true, if the class could be loaded, false otherwise.
647    */

648   protected static boolean isClassLoadable(final String JavaDoc name)
649   {
650     try
651     {
652       Thread.currentThread().getContextClassLoader().loadClass(name);
653       return true;
654     }
655     catch (Exception JavaDoc e)
656     {
657       return false;
658     }
659   }
660
661   /**
662    * Configures the module by loading the configuration properties and
663    * adding them to the package configuration.
664    *
665    * @param subSystem the subsystem.
666    */

667   public void configure(final SubSystem subSystem)
668   {
669     final InputStream JavaDoc in = ObjectUtilities.getResourceRelativeAsStream
670             ("configuration.properties", getClass());
671     if (in == null)
672     {
673       return;
674     }
675     subSystem.getPackageManager().getPackageConfiguration().load(in);
676   }
677
678   /**
679    * Tries to load an module initializer and uses this initializer to initialize
680    * the module.
681    *
682    * @param classname the class name of the initializer.
683    * @throws ModuleInitializeException if an error occures
684    */

685   protected void performExternalInitialize(final String JavaDoc classname)
686       throws ModuleInitializeException
687   {
688     try
689     {
690       final Class JavaDoc c = Thread.currentThread().getContextClassLoader().loadClass(classname);
691       final ModuleInitializer mi = (ModuleInitializer) c.newInstance();
692       mi.performInit();
693     }
694     catch (ModuleInitializeException mie)
695     {
696       throw mie;
697     }
698     catch (Exception JavaDoc e)
699     {
700       throw new ModuleInitializeException("Failed to load specified initializer class.", e);
701     }
702   }
703
704   /**
705    * Returns the modules subsystem. If this module is not part of an subsystem
706    * then return the modules name, but never null.
707    *
708    * @return the name of the subsystem.
709    */

710   public String JavaDoc getSubSystem()
711   {
712     if (this.subsystem == null)
713     {
714       return getName();
715     }
716     return this.subsystem;
717   }
718
719   /**
720    * Defines the subsystem name for this module.
721    *
722    * @param name the new name of the subsystem.
723    */

724   protected void setSubSystem (final String JavaDoc name)
725   {
726     this.subsystem = name;
727   }
728 }
729
Popular Tags