001    /**
002     * ========================================
003     * JFreeReport : a free Java report library
004     * ========================================
005     *
006     * Project Info:  http://reporting.pentaho.org/
007     *
008     * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
009     *
010     * This library is free software; you can redistribute it and/or modify it under the terms
011     * of the GNU Lesser General Public License as published by the Free Software Foundation;
012     * either version 2.1 of the License, or (at your option) any later version.
013     *
014     * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016     * See the GNU Lesser General Public License for more details.
017     *
018     * You should have received a copy of the GNU Lesser General Public License along with this
019     * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020     * Boston, MA 02111-1307, USA.
021     *
022     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023     * in the United States and other countries.]
024     *
025     * ------------
026     * $Id: TypedPropertyReadHandler.java 3525 2007-10-16 11:43:48Z tmorgner $
027     * ------------
028     * (C) Copyright 2000-2005, by Object Refinery Limited.
029     * (C) Copyright 2005-2007, by Pentaho Corporation.
030     */
031    package org.jfree.report.modules.factories.report.flow;
032    
033    import java.beans.IntrospectionException;
034    import java.io.ByteArrayInputStream;
035    import java.io.IOException;
036    import java.io.ObjectInputStream;
037    
038    import org.jfree.report.util.CharacterEntityParser;
039    import org.jfree.report.util.beans.BeanException;
040    import org.jfree.report.util.beans.BeanUtility;
041    import org.jfree.util.Log;
042    import org.jfree.util.ObjectUtilities;
043    import org.jfree.xmlns.parser.Base64;
044    import org.jfree.xmlns.parser.ParseException;
045    import org.jfree.xmlns.parser.PropertyReadHandler;
046    import org.jfree.xmlns.parser.XmlReadHandler;
047    import org.xml.sax.Attributes;
048    import org.xml.sax.SAXException;
049    
050    /**
051     * Creation-Date: 09.04.2006, 12:58:24
052     *
053     * @author Thomas Morgner
054     */
055    public class TypedPropertyReadHandler extends PropertyReadHandler
056    {
057      private boolean plainContent;
058      private String encoding;
059      private String className;
060      private BeanUtility beanUtility;
061      private String expressionName;
062      private CharacterEntityParser entityParser;
063    
064      public TypedPropertyReadHandler(final BeanUtility beanDescription,
065                                      final String expressionName,
066                                      final CharacterEntityParser entityParser)
067      {
068        if (beanDescription == null)
069        {
070          throw new NullPointerException(
071                  "Expression must not be null");
072        }
073        if (entityParser == null)
074        {
075          throw new NullPointerException(
076                  "EntityParser must not be null");
077        }
078        this.expressionName = expressionName;
079        this.beanUtility = beanDescription;
080        this.entityParser = entityParser;
081        this.plainContent = true;
082      }
083    
084      /**
085       * Done parsing.
086       *
087       * @throws SAXException       if there is a parsing error.
088       */
089      protected void doneParsing() throws SAXException
090      {
091        super.doneParsing();
092        try
093        {
094          if (plainContent)
095          {
096            final String result = getResult();
097            if ("base64".equals(encoding))
098            {
099              final byte[] data = Base64.decode(result.trim().toCharArray());
100              final ByteArrayInputStream bin = new ByteArrayInputStream(data);
101              final ObjectInputStream oin = new ObjectInputStream(bin);
102              final Object value = oin.readObject();
103              beanUtility.setProperty(getName(), value);
104            }
105            else
106            {
107              if (className != null)
108              {
109                final ClassLoader cl = ObjectUtilities.getClassLoader
110                        (TypedPropertyReadHandler.class);
111                final Class c = cl.loadClass(className);
112                beanUtility.setPropertyAsString
113                        (getName(), c, entityParser.decodeEntities(result));
114              }
115              else
116              {
117                beanUtility.setPropertyAsString
118                        (getName(), entityParser.decodeEntities(result));
119              }
120            }
121          }
122        }
123        catch (BeanException e)
124        {
125          e.printStackTrace();
126          throw new ParseException("Unable to assign property '" + getName()
127                  + "' to expression '" + expressionName + "'", e, getLocator());
128        }
129        catch (ClassNotFoundException e)
130        {
131          throw new ParseException("Unable to assign property '" + getName()
132                  + "' to expression '" + expressionName + "'", e, getLocator());
133        }
134        catch (IOException e)
135        {
136          throw new ParseException("Unable to assign property '" + getName()
137                  + "' to expression '" + expressionName + "'", e, getLocator());
138        }
139      }
140    
141      /**
142       * Starts parsing.
143       *
144       * @param attrs the attributes.
145       * @throws SAXException if there is a parsing error.
146       */
147      protected void startParsing(final Attributes attrs) throws SAXException
148      {
149        super.startParsing(attrs);
150        className = attrs.getValue(getUri(), "class");
151        encoding = attrs.getValue(getUri(), "encoding");
152        if (encoding == null)
153        {
154          encoding = "text";
155        }
156        else if (("text".equals(encoding) == false) && "base64".equals(
157                encoding) == false)
158        {
159          Log.warn("Invalid value for attribute 'encoding'. Defaulting to 'text'");
160          encoding = "text";
161        }
162      }
163    
164      /**
165       * Returns the handler for a child element.
166       *
167       * @param tagName the tag name.
168       * @param atts    the attributes.
169       * @return the handler or null, if the tagname is invalid.
170       * @throws SAXException       if there is a parsing error.
171       */
172      protected XmlReadHandler getHandlerForChild(final String uri,
173                                                  final String tagName,
174                                                  final Attributes atts)
175              throws SAXException
176      {
177        if (isSameNamespace(uri) == false)
178        {
179          return null;
180        }
181    
182        if ("property".equals(tagName))
183        {
184          plainContent = false;
185          final String name = atts.getValue(uri, "name");
186          if (name == null)
187          {
188            throw new ParseException("Required attribute 'name' is missing", getLocator());
189          }
190          try
191          {
192            final Class type = beanUtility.getPropertyType(name);
193            final Object property = type.newInstance();
194            final BeanUtility propertyUtility = new BeanUtility(property);
195            return new TypedPropertyReadHandler
196                    (propertyUtility, expressionName, entityParser);
197          }
198          catch (BeanException e)
199          {
200            throw new ParseException("Property '" + name + "' for expression '" +
201                    className + "' is not valid. The specified class was not found.",
202                    e, getRootHandler().getDocumentLocator());
203          }
204          catch (IllegalAccessException e)
205          {
206            throw new ParseException(
207                    "Property '" + name + "' for expression '" + className +
208                            "' is not valid. The specified class was not found.",
209                    e, getRootHandler().getDocumentLocator());
210          }
211          catch (InstantiationException e)
212          {
213            throw new ParseException(
214                    "Property '" + name + "' for expression '" + className +
215                            "' is not valid. The specified class cannot be instantiated.",
216                    e, getRootHandler().getDocumentLocator());
217          }
218          catch (IntrospectionException e)
219          {
220            throw new ParseException(
221                    "Property '" + name + "' for expression '" + className +
222                            "' is not valid. Introspection failed for this expression.",
223                    e, getRootHandler().getDocumentLocator());
224          }
225        }
226        return null;
227      }
228    }