/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2001 - 2013 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved. */ package org.pentaho.reporting.engine.classic.core.modules.parser.bundle.content; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.pentaho.reporting.engine.classic.core.ParameterMapping; import org.pentaho.reporting.engine.classic.core.ReportDataFactoryException; import org.pentaho.reporting.engine.classic.core.SubReport; import org.pentaho.reporting.engine.classic.core.function.Expression; import org.pentaho.reporting.engine.classic.core.modules.parser.base.ReportParserUtil; import org.pentaho.reporting.engine.classic.core.modules.parser.bundle.BundleNamespaces; import org.pentaho.reporting.engine.classic.core.modules.parser.bundle.data.SubReportDataDefinition; import org.pentaho.reporting.libraries.resourceloader.FactoryParameterKey; import org.pentaho.reporting.libraries.resourceloader.ResourceLoadingException; import org.pentaho.reporting.libraries.xmlns.parser.AbstractXmlReadHandler; import org.pentaho.reporting.libraries.xmlns.parser.IgnoreAnyChildReadHandler; import org.pentaho.reporting.libraries.xmlns.parser.ParseException; import org.pentaho.reporting.libraries.xmlns.parser.RootXmlReadHandler; import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import java.util.Map; /** * The content root handler is the first handler that is parsed when dealing with bundle-reports. This file contains all * the forwards to the various report-files. * <p/> * A bundle always contains a master-report. It is not possible to parse a full bundle into a subreport. However, it is * possible to parse the subreport xml files contained in a bundle into subreports, if needed. * * @author Thomas Morgner */ public class SubContentRootElementHandler extends AbstractXmlReadHandler { private static final Log logger = LogFactory.getLog( SubContentRootElementHandler.class ); private SubReport report; public SubContentRootElementHandler() { } /** * Initialises the handler. * * @param rootHandler * the root handler. * @param tagName * the tag name. */ public void init( final RootXmlReadHandler rootHandler, final String uri, final String tagName ) throws SAXException { super.init( rootHandler, uri, tagName ); rootHandler.setHelperObject( "property-expansion", Boolean.FALSE ); } /** * Starts parsing. * * @param attrs * the attributes. * @throws SAXException * if there is a parsing error. */ protected void startParsing( final Attributes attrs ) throws SAXException { final Object maybeReport = getRootHandler().getHelperObject( ReportParserUtil.HELPER_OBJ_REPORT_NAME ); if ( maybeReport instanceof SubReport == false ) { // replace it .. report = new SubReport(); getRootHandler().setHelperObject( ReportParserUtil.HELPER_OBJ_REPORT_NAME, report ); } else { report = (SubReport) maybeReport; } } /** * Returns the handler for a child element. * * @param uri * the URI of the namespace of the current element. * @param tagName * the tag name. * @param atts * the attributes. * @return the handler or null, if the tagname is invalid. * @throws SAXException * if there is a parsing error. */ protected XmlReadHandler getHandlerForChild( final String uri, final String tagName, final Attributes atts ) throws SAXException { if ( BundleNamespaces.CONTENT.equals( uri ) == false ) { return null; } if ( "data-definition".equals( tagName ) ) { final String primaryFile = atts.getValue( getUri(), "ref" ); if ( primaryFile == null ) { throw new ParseException( "Required attribute 'ref' is not specified", getLocator() ); } if ( parseDataDefinition( primaryFile ) == false ) { final String fallbackFile = atts.getValue( getUri(), "local-copy" ); if ( fallbackFile != null ) { if ( parseDataDefinition( fallbackFile ) == false ) { throw new ParseException( "Parsing the specified local-copy failed", getLocator() ); } } } return new IgnoreAnyChildReadHandler(); } if ( "styles".equals( tagName ) ) { final String primaryFile = atts.getValue( getUri(), "ref" ); if ( primaryFile == null ) { throw new ParseException( "Required attribute 'ref' is not specified", getLocator() ); } if ( parseStyles( primaryFile ) == false ) { final String fallbackFile = atts.getValue( getUri(), "local-copy" ); if ( fallbackFile != null ) { if ( parseStyles( fallbackFile ) == false ) { throw new ParseException( "Parsing the specified local-copy failed", getLocator() ); } } } return new IgnoreAnyChildReadHandler(); } if ( "layout".equals( tagName ) ) { final String primaryFile = atts.getValue( getUri(), "ref" ); if ( primaryFile == null ) { throw new ParseException( "Required attribute 'ref' is not specified", getLocator() ); } if ( parseLayout( primaryFile ) == false ) { final String fallbackFile = atts.getValue( getUri(), "local-copy" ); if ( fallbackFile != null ) { if ( parseLayout( fallbackFile ) == false ) { throw new ParseException( "Parsing the specified local-copy failed", getLocator() ); } } } return new IgnoreAnyChildReadHandler(); } return null; } /** * Done parsing. * * @throws SAXException * if there is a parsing error. */ protected void doneParsing() throws SAXException { // Now, after all the user-defined and global files have been parsed, finally override whatever had been // defined in these files with the contents from the bundle. This will merge all the settings from the bundle // with the global definitions but grants the local settings higer preference parseLocalFiles(); } private void parseLocalFiles() throws ParseException { parseDataDefinition( "datadefinition.xml" ); parseStyles( "styles.xml" ); parseLayout( "layout.xml" ); } private boolean parseLayout( final String layout ) throws ParseException { try { final SubReport report = (SubReport) performExternalParsing( layout, SubReport.class ); return report == this.report; } catch ( ResourceLoadingException e ) { SubContentRootElementHandler.logger.warn( "Unable to parse the parameter for this bundle from file: " + layout ); return false; } } private boolean parseStyles( final String stylefile ) throws ParseException { try { final SubReport report = (SubReport) performExternalParsing( stylefile, SubReport.class ); return report == this.report; } catch ( ResourceLoadingException e ) { SubContentRootElementHandler.logger .warn( "Unable to parse the parameter for this bundle from file: " + stylefile ); return false; } } private boolean parseDataDefinition( final String parameterFile ) throws ParseException { try { final Map parameters = deriveParseParameters(); parameters.put( new FactoryParameterKey( ReportParserUtil.HELPER_OBJ_REPORT_NAME ), null ); final SubReportDataDefinition dataDefinition = (SubReportDataDefinition) performExternalParsing( parameterFile, SubReportDataDefinition.class, parameters ); report.setDataFactory( dataDefinition.getDataFactory() ); report.setQuery( dataDefinition.getQuery() ); report.setQueryLimit( dataDefinition.getQueryLimit() ); report.setQueryTimeout( dataDefinition.getQueryTimeout() ); final ParameterMapping[] inputMapping = dataDefinition.getImportParameters(); for ( int i = 0; i < inputMapping.length; i++ ) { final ParameterMapping mapping = inputMapping[i]; report.addInputParameter( mapping.getName(), mapping.getAlias() ); } final ParameterMapping[] exportMapping = dataDefinition.getExportParameters(); for ( int i = 0; i < exportMapping.length; i++ ) { final ParameterMapping mapping = exportMapping[i]; report.addExportParameter( mapping.getName(), mapping.getAlias() ); } final Expression[] expressions = dataDefinition.getExpressions(); if ( expressions != null ) { for ( int i = 0; i < expressions.length; i++ ) { final Expression expression = expressions[i]; report.addExpression( expression ); } } return true; } catch ( ResourceLoadingException e ) { SubContentRootElementHandler.logger.warn( "Unable to parse the parameter for this bundle from file: " + parameterFile ); return false; } catch ( ReportDataFactoryException e ) { throw new ParseException( "Unable to configure datafactory.", getLocator() ); } } /** * Returns the object for this element or null, if this element does not create an object. * * @return the object. * @throws SAXException * if an parser error occured. */ public Object getObject() throws SAXException { return report; } }