Save This Page
Home » pentaho-reporting-engine-classic-0.8.10 » org » jfree » report » modules » [javadoc | source]
    1   /**
    2    * ========================================
    3    * JFreeReport : a free Java report library
    4    * ========================================
    5    *
    6    * Project Info:  http://www.jfree.org/jfreereport/index.html
    7    * Project Lead:  Thomas Morgner;
    8    *
    9    * (C) Copyright 2000-2003, by Simba Management Limited and Contributors.
   10    *
   11    * This library is free software; you can redistribute it and/or modify it under the terms
   12    * of the GNU Lesser General Public License as published by the Free Software Foundation;
   13    * either version 2.1 of the License, or (at your option) any later version.
   14    *
   15    * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
   16    * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   17    * See the GNU Lesser General Public License for more details.
   18    *
   19    * You should have received a copy of the GNU Lesser General Public License along with this
   20    * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
   21    * Boston, MA 02111-1307, USA.
   22    *
   23    * ------------------------------
   24    * AbstractModule.java
   25    * ------------------------------
   26    * (C)opyright 2003, by Thomas Morgner and Contributors.
   27    *
   28    * Original Author:  Thomas Morgner;
   29    * Contributor(s):   David Gilbert (for Simba Management Limited);
   30    *
   31    * $Id: AbstractModule.java,v 1.11.2.1 2003/12/21 23:28:44 taqua Exp $
   32    *
   33    * Changes
   34    * -------------------------
   35    * 05-Jul-2003 : Initial version
   36    *
   37    */
   38   
   39   package org.jfree.report.modules;
   40   
   41   import java.io.BufferedReader;
   42   import java.io.IOException;
   43   import java.io.InputStream;
   44   import java.io.InputStreamReader;
   45   import java.util.ArrayList;
   46   
   47   /**
   48    * The abstract module provides a default implementation of the module interface.
   49    * <p>
   50    * The module can be specified in an external property file. The file name of this
   51    * specification defaults to "module.properties". This file is no real property file,
   52    * it follows a more complex rule set.
   53    * <p>
   54    * Lines starting with '#' are considered comments.
   55    * Section headers start at the beginning of the line, section properties
   56    * are indented with at least one whitespace.
   57    * <p>
   58    * The first section is always the module info and contains the basic module
   59    * properties like name, version and a short description.
   60    * <p>
   61    * <pre>
   62    * module-info:
   63    *   name: xls-export-gui
   64    *   producer: The JFreeReport project - www.jfree.org/jfreereport
   65    *   description: A dialog component for the Excel table export.
   66    *   version.major: 0
   67    *   version.minor: 84
   68    *   version.patchlevel: 0
   69    * </pre>
   70    * The properties name, producer and description are simple strings. They may
   71    * span multiple lines, but may not contain a colon (':').
   72    * The version properties are integer values.
   73    * <p>
   74    * This section may be followed by one or more "depends" sections. These
   75    * sections describe the base modules that are required to be active to make this
   76    * module work. The package manager will enforce this policy and will deactivate this
   77    * module if one of the base modules is missing.
   78    * <p>
   79    * <pre>
   80    * depends:
   81    *   module: org.jfree.report.modules.output.table.xls.XLSTableModule
   82    *   version.major: 0
   83    *   version.minor: 84
   84    * </pre>
   85    * <p>
   86    * The property module references to the module implementation of the module package.
   87    *
   88    * @author Thomas Morgner
   89    */
   90   public abstract class AbstractModule extends DefaultModuleInfo implements Module
   91   {
   92     /**
   93      * The reader helper provides a pushback interface for the reader to read and
   94      * buffer  complete lines.
   95      * @author Thomas Morgner
   96      */
   97     private static class ReaderHelper
   98     {
   99       /** The line buffer containing the last line read. */
  100       private String buffer;
  101       /** The reader from which to read the text. */
  102       private final BufferedReader reader;
  103   
  104       /**
  105        * Creates a new reader helper for the given buffered reader.
  106        *
  107        * @param reader the buffered reader that is the source of the text.
  108        */
  109       public ReaderHelper(final BufferedReader reader)
  110       {
  111         this.reader = reader;
  112       }
  113   
  114       /**
  115        * Checks, whether the reader contains a next line. Returns false if the end
  116        * of the stream has been reached.
  117        *
  118        * @return true, if there is a next line to read, false otherwise.
  119        * @throws IOException if an error occures.
  120        */
  121       public boolean hasNext() throws IOException
  122       {
  123         if (buffer == null)
  124         {
  125           buffer = readLine();
  126         }
  127         return buffer != null;
  128       }
  129   
  130       /**
  131        * Returns the next line.
  132        *
  133        * @return the next line.
  134        */
  135       public String next()
  136       {
  137         final String line = buffer;
  138         buffer = null;
  139         return line;
  140       }
  141   
  142       /**
  143        * Pushes the given line back into the buffer. Only one line can be contained in
  144        * the buffer at one time.
  145        *
  146        * @param line the line that should be pushed back into the buffer.
  147        */
  148       public void pushBack(final String line)
  149       {
  150         buffer = line;
  151       }
  152   
  153       /**
  154        * Reads the next line skipping all comment lines.
  155        *
  156        * @return the next line, or null if no line can be read.
  157        * @throws IOException if an IO error occures.
  158        */
  159       protected String readLine() throws IOException
  160       {
  161         String line = reader.readLine();
  162         while (line != null && (line.length() == 0 || line.startsWith("#")))
  163         {
  164           // empty line or comment is ignored
  165           line = reader.readLine();
  166         }
  167         return line;
  168       }
  169   
  170       /**
  171        * Closes the reader.
  172        *
  173        * @throws IOException if an IOError occurs.
  174        */
  175       public void close() throws IOException
  176       {
  177         reader.close();
  178       }
  179     }
  180   
  181     /** The list of required modules. */
  182     private ModuleInfo[] requiredModules;
  183     /** The list of optional modules. */
  184     private ModuleInfo[] optionalModules;
  185   
  186     /** The name of the module. */
  187     private String name;
  188     /** A short description of the module. */
  189     private String description;
  190     /** The name of the module producer. */
  191     private String producer;
  192     /** The modules subsystem. */
  193     private String subsystem;
  194   
  195     /**
  196      * Default Constructor.
  197      */
  198     public AbstractModule()
  199     {
  200       setModuleClass(this.getClass().getName());
  201     }
  202   
  203     /**
  204      * Loads the default module description from the file "module.properties". This file
  205      * must be in the same package as the implementing class.
  206      *
  207      * @throws ModuleInitializeException if an error occurs.
  208      */
  209     protected void loadModuleInfo() throws ModuleInitializeException
  210     {
  211       final InputStream in = getClass().getResourceAsStream("module.properties");
  212       if (in == null)
  213       {
  214         throw new ModuleInitializeException
  215             ("File 'module.properties' not found in module package.");
  216       }
  217       loadModuleInfo(in);
  218     }
  219   
  220     /**
  221      * Loads the module descriptiong from the given input stream. The module description
  222      * must conform to the rules define in the class description. The file must be encoded
  223      * with "ISO-8859-1" (like property files).
  224      *
  225      * @param in the input stream from where to read the file
  226      * @throws ModuleInitializeException if an error occurs.
  227      */
  228     protected void loadModuleInfo(final InputStream in) throws ModuleInitializeException
  229     {
  230       try
  231       {
  232         if (in == null)
  233         {
  234           throw new NullPointerException
  235               ("Given InputStream is null.");
  236         }
  237         final ReaderHelper rh = new ReaderHelper(new BufferedReader
  238             (new InputStreamReader(in, "ISO-8859-1")));
  239   
  240         final ArrayList optionalModules = new ArrayList();
  241         final ArrayList dependendModules = new ArrayList();
  242   
  243         while (rh.hasNext())
  244         {
  245           final String lastLineRead = rh.next();
  246           if (lastLineRead.startsWith("module-info:"))
  247           {
  248             readModuleInfo(rh);
  249           }
  250           else if (lastLineRead.startsWith("depends:"))
  251           {
  252             dependendModules.add(readExternalModule(rh));
  253           }
  254           else if (lastLineRead.startsWith("optional:"))
  255           {
  256             optionalModules.add(readExternalModule(rh));
  257           }
  258           else
  259           {
  260             // we dont understand the current line, so we skip it ...
  261             // should we throw a parse exception instead?
  262           }
  263         }
  264         rh.close();
  265   
  266         this.optionalModules = (ModuleInfo[])
  267             optionalModules.toArray(new ModuleInfo[optionalModules.size()]);
  268   
  269         this.requiredModules = (ModuleInfo[])
  270             dependendModules.toArray(new ModuleInfo[dependendModules.size()]);
  271       }
  272       catch (IOException ioe)
  273       {
  274         throw new ModuleInitializeException("Failed to load properties", ioe);
  275       }
  276     }
  277   
  278     /**
  279      * Reads a multiline value the stream. This will read the stream until
  280      * a new key is found or the end of the file is reached.
  281      *
  282      * @param reader the reader from where to read.
  283      * @param firstLine the first line (which was read elsewhere).
  284      * @return the complete value, never null
  285      * @throws IOException if an IO error occurs.
  286      */
  287     private String readValue(final ReaderHelper reader, String firstLine) throws IOException
  288     {
  289       final StringBuffer b = new StringBuffer(firstLine.trim());
  290       boolean newLine = true;
  291       while (isNextLineValueLine(reader))
  292       {
  293         firstLine = reader.next();
  294         final String trimedLine = firstLine.trim();
  295         if (trimedLine.length() == 0 && (newLine == false))
  296         {
  297           b.append ("\n");
  298           newLine = true;
  299         }
  300         else
  301         {
  302           if (newLine == false)
  303           {
  304             b.append(" ");
  305           }
  306           b.append(parseValue(trimedLine));
  307           newLine = false;
  308         }
  309       }
  310       return b.toString();
  311     }
  312   
  313     /**
  314      * Checks, whether the next line in the reader is a value line.
  315      * 
  316      * @param reader from where to read the lines.
  317      * @return true, if the next line is a value line, false otherwise.
  318      * @throws IOException if an IO error occurs.
  319      */
  320     private boolean isNextLineValueLine (final ReaderHelper reader) throws IOException
  321     {
  322       if (reader.hasNext() == false)
  323       {
  324         return false;
  325       }
  326       final String firstLine = reader.next();
  327       if (firstLine == null)
  328       {
  329         return false;
  330       }
  331       if (parseKey(firstLine) != null)
  332       {
  333         reader.pushBack(firstLine);
  334         return false;
  335       }
  336       reader.pushBack(firstLine);
  337       return true;
  338     }
  339   
  340     /**
  341      * Reads the module definition header. This header contains information about
  342      * the module itself.
  343      *
  344      * @param reader the reader from where to read the content.
  345      * @throws IOException if an error occures
  346      */
  347     private void readModuleInfo(final ReaderHelper reader) throws IOException
  348     {
  349       while (reader.hasNext())
  350       {
  351         final String lastLineRead = reader.next();
  352   
  353         if (Character.isWhitespace(lastLineRead.charAt(0)) == false)
  354         {
  355           // break if the current character is no whitespace ...
  356           reader.pushBack(lastLineRead);
  357           return;
  358         }
  359   
  360         final String line = lastLineRead.trim();
  361         final String key = parseKey(line);
  362         if (key != null)
  363         {
  364           // parse error: Non data line does not contain a colon
  365           final String b = readValue(reader, parseValue(line.trim()));
  366   
  367           if (key.equals("name"))
  368           {
  369             setName(b);
  370           }
  371           else if (key.equals("producer"))
  372           {
  373             setProducer(b);
  374           }
  375           else if (key.equals("description"))
  376           {
  377             setDescription(b);
  378           }
  379           else if (key.equals("subsystem"))
  380           {
  381             setSubSystem(b);
  382           }
  383           else if (key.equals("version.major"))
  384           {
  385             setMajorVersion(b);
  386           }
  387           else if (key.equals("version.minor"))
  388           {
  389             setMinorVersion(b);
  390           }
  391           else if (key.equals("version.patchlevel"))
  392           {
  393             setPatchLevel(b);
  394           }
  395         }
  396       }
  397     }
  398   
  399     /**
  400      * Parses an string to find the key section of the line. This section ends with
  401      * an colon.
  402      *
  403      * @param line the line which to parse
  404      * @return the key or null if no key is found.
  405      */
  406     private String parseKey(final String line)
  407     {
  408       final int idx = line.indexOf(':');
  409       if (idx == -1)
  410       {
  411         return null;
  412       }
  413       return line.substring(0, idx);
  414     }
  415   
  416     /**
  417      * Parses the value section of the given line.
  418      *
  419      * @param line the line that should be parsed
  420      * @return the value, never null
  421      */
  422     private String parseValue(final String line)
  423     {
  424       final int idx = line.indexOf(':');
  425       if (idx == -1)
  426       {
  427         return line;
  428       }
  429       if ((idx + 1) == line.length())
  430       {
  431         return "";
  432       }
  433       return line.substring(idx + 1);
  434     }
  435   
  436     /**
  437      * Reads an external module description. This describes either an optional or
  438      * a required module.
  439      *
  440      * @param reader the reader from where to read the module
  441      * @return the read module, never null
  442      * @throws IOException if an error occures.
  443      */
  444     private DefaultModuleInfo readExternalModule(final ReaderHelper reader)
  445         throws IOException
  446     {
  447       final DefaultModuleInfo mi = new DefaultModuleInfo();
  448   
  449       while (reader.hasNext())
  450       {
  451         final String lastLineRead = reader.next();
  452   
  453         if (Character.isWhitespace(lastLineRead.charAt(0)) == false)
  454         {
  455           // break if the current character is no whitespace ...
  456           reader.pushBack(lastLineRead);
  457           return mi;
  458         }
  459   
  460         final String line = lastLineRead.trim();
  461         final String key = parseKey(line);
  462         if (key != null)
  463         {
  464           final String b = readValue(reader, parseValue(line));
  465           if (key.equals("module"))
  466           {
  467             mi.setModuleClass(b);
  468           }
  469           else if (key.equals("version.major"))
  470           {
  471             mi.setMajorVersion(b);
  472           }
  473           else if (key.equals("version.minor"))
  474           {
  475             mi.setMinorVersion(b);
  476           }
  477           else if (key.equals("version.patchlevel"))
  478           {
  479             mi.setPatchLevel(b);
  480           }
  481         }
  482       }
  483       return mi;
  484     }
  485   
  486     /**
  487      * Returns the name of this module.
  488      *
  489      * @see org.jfree.report.modules.Module#getName()
  490      *
  491      * @return the module name
  492      */
  493     public String getName()
  494     {
  495       return name;
  496     }
  497   
  498     /**
  499      * Defines the name of the module.
  500      *
  501      * @param name the module name.
  502      */
  503     protected void setName(final String name)
  504     {
  505       this.name = name;
  506     }
  507   
  508     /**
  509      * Returns the module description.
  510      * @see org.jfree.report.modules.Module#getDescription()
  511      *
  512      * @return the description of the module.
  513      */
  514     public String getDescription()
  515     {
  516       return description;
  517     }
  518   
  519     /**
  520      * Defines the description of the module.
  521      *
  522      * @param description the module's desciption.
  523      */
  524     protected void setDescription(final String description)
  525     {
  526       this.description = description;
  527     }
  528   
  529     /**
  530      * Returns the producer of the module.
  531      *
  532      * @see org.jfree.report.modules.Module#getProducer()
  533      *
  534      * @return the producer.
  535      */
  536     public String getProducer()
  537     {
  538       return producer;
  539     }
  540   
  541     /**
  542      * Defines the producer of the module.
  543      *
  544      * @param producer the producer.
  545      */
  546     protected void setProducer(final String producer)
  547     {
  548       this.producer = producer;
  549     }
  550   
  551     /**
  552      * Returns a copy of the required modules array. This array contains all
  553      * description of the modules that need to be present to make this module work.
  554      * @see org.jfree.report.modules.Module#getRequiredModules()
  555      *
  556      * @return an array of all required modules.
  557      */
  558     public ModuleInfo[] getRequiredModules()
  559     {
  560       final ModuleInfo[] retval = new ModuleInfo[requiredModules.length];
  561       System.arraycopy(requiredModules, 0, retval, 0, requiredModules.length);
  562       return retval;
  563     }
  564   
  565     /**
  566      * Returns a copy of the required modules array. This array contains all
  567      * description of the optional modules that may improve the modules functonality.
  568      * @see org.jfree.report.modules.Module#getRequiredModules()
  569      *
  570      * @return an array of all required modules.
  571      */
  572     public ModuleInfo[] getOptionalModules()
  573     {
  574       final ModuleInfo[] retval = new ModuleInfo[optionalModules.length];
  575       System.arraycopy(optionalModules, 0, retval, 0, optionalModules.length);
  576       return retval;
  577     }
  578   
  579     /**
  580      * Defines the required module descriptions for this module.
  581      *
  582      * @param requiredModules the required modules.
  583      */
  584     protected void setRequiredModules(final ModuleInfo[] requiredModules)
  585     {
  586       this.requiredModules = new ModuleInfo[requiredModules.length];
  587       System.arraycopy(requiredModules, 0, this.requiredModules, 0, requiredModules.length);
  588     }
  589   
  590     /**
  591      * Defines the optional module descriptions for this module.
  592      *
  593      * @param optionalModules the optional modules.
  594      */
  595     public void setOptionalModules(final ModuleInfo[] optionalModules)
  596     {
  597       this.optionalModules = new ModuleInfo[optionalModules.length];
  598       System.arraycopy(optionalModules, 0, this.optionalModules, 0, optionalModules.length);
  599     }
  600   
  601     /**
  602      * Returns a string representation of this module.
  603      * @see java.lang.Object#toString()
  604      *
  605      * @return the string representation of this module for debugging purposes.
  606      */
  607     public String toString()
  608     {
  609       final StringBuffer buffer = new StringBuffer();
  610       buffer.append("Module : ");
  611       buffer.append(getName());
  612       buffer.append("\n");
  613       buffer.append("ModuleClass : ");
  614       buffer.append(getModuleClass());
  615       buffer.append("\n");
  616       buffer.append("Version: ");
  617       buffer.append(getMajorVersion());
  618       buffer.append(".");
  619       buffer.append(getMinorVersion());
  620       buffer.append(".");
  621       buffer.append(getPatchLevel());
  622       buffer.append("\n");
  623       buffer.append("Producer: ");
  624       buffer.append(getProducer());
  625       buffer.append("\n");
  626       buffer.append("Description: ");
  627       buffer.append(getDescription());
  628       buffer.append("\n");
  629       return buffer.toString();
  630     }
  631   
  632     /**
  633      * Tries to load a class to indirectly check for the existence
  634      * of a certain library.
  635      *
  636      * @param name the name of the library class.
  637      * @return true, if the class could be loaded, false otherwise.
  638      */
  639     protected static boolean isClassLoadable(final String name)
  640     {
  641       try
  642       {
  643         Thread.currentThread().getContextClassLoader().loadClass(name);
  644         return true;
  645       }
  646       catch (Exception e)
  647       {
  648         return false;
  649       }
  650     }
  651   
  652     /**
  653      * Configures the module by loading the configuration properties and
  654      * adding them to the package configuration.
  655      */
  656     public void configure()
  657     {
  658       final InputStream in = getClass().getResourceAsStream("configuration.properties");
  659       if (in == null)
  660       {
  661         return;
  662       }
  663       PackageManager.getInstance().getPackageConfiguration().load(in);
  664     }
  665   
  666     /**
  667      * Tries to load an module initializer and uses this initializer to initialize
  668      * the module.
  669      *
  670      * @param classname the class name of the initializer.
  671      * @throws ModuleInitializeException if an error occures
  672      */
  673     protected void performExternalInitialize(final String classname)
  674         throws ModuleInitializeException
  675     {
  676       try
  677       {
  678         final Class c = getClass().getClassLoader().loadClass(classname);
  679         if (c == null)
  680         {
  681           throw new ModuleInitializeException("Failed to load specified initializer class: " + classname);
  682         }
  683         final ModuleInitializer mi = (ModuleInitializer) c.newInstance();
  684         mi.performInit();
  685       }
  686       catch (ModuleInitializeException mie)
  687       {
  688         throw mie;
  689       }
  690       catch (Exception e)
  691       {
  692         throw new ModuleInitializeException("Failed to load specified initializer class: " + classname, e);
  693       }
  694     }
  695   
  696     /**
  697      * Returns the modules subsystem. If this module is not part of an subsystem
  698      * then return the modules name, but never null.
  699      *
  700      * @return the name of the subsystem.
  701      */
  702     public String getSubSystem()
  703     {
  704       if (subsystem == null)
  705       {
  706         return getName();
  707       }
  708       return subsystem;
  709     }
  710   
  711     /**
  712      * Defines the subsystem name for this module.
  713      *
  714      * @param name the new name of the subsystem.
  715      */
  716     protected void setSubSystem (final String name)
  717     {
  718       this.subsystem = name;
  719     }
  720   }

Save This Page
Home » pentaho-reporting-engine-classic-0.8.10 » org » jfree » report » modules » [javadoc | source]