org.deegree.services.wps.provider.jrxml.contentprovider.DataTableContentProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.deegree.services.wps.provider.jrxml.contentprovider.DataTableContentProvider.java

Source

//$HeadURL: svn+ssh://lbuesching@svn.wald.intevation.de/deegree/base/trunk/resources/eclipse/files_template.xml $
/*----------------------------------------------------------------------------
 This file is part of deegree, http://deegree.org/
 Copyright (C) 2001-2010 by:
 - Department of Geography, University of Bonn -
 and
 - lat/lon GmbH -
    
 This library is free software; you can redistribute it and/or modify it under
 the terms of the GNU Lesser General Public License as published by the Free
 Software Foundation; either version 2.1 of the License, or (at your option)
 any later version.
 This library 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.
 You should have received a copy of the GNU Lesser General Public License
 along with this library; if not, write to the Free Software Foundation, Inc.,
 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    
 Contact information:
    
 lat/lon GmbH
 Aennchenstr. 19, 53177 Bonn
 Germany
 http://lat-lon.de/
    
 Department of Geography, University of Bonn
 Prof. Dr. Klaus Greve
 Postfach 1147, 53001 Bonn
 Germany
 http://www.geographie.uni-bonn.de/deegree/
    
 e-mail: info@deegree.org
 ----------------------------------------------------------------------------*/
package org.deegree.services.wps.provider.jrxml.contentprovider;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;

import net.sf.jasperreports.engine.data.JRXmlDataSource;
import net.sf.jasperreports.engine.query.JRXPathQueryExecuterFactory;

import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.commons.io.IOUtils;
import org.deegree.commons.tom.ows.CodeType;
import org.deegree.commons.utils.Pair;
import org.deegree.commons.utils.io.StreamBufferStore;
import org.deegree.commons.xml.NamespaceBindings;
import org.deegree.commons.xml.XMLAdapter;
import org.deegree.commons.xml.XPath;
import org.deegree.commons.xml.stax.XMLStreamUtils;
import org.deegree.process.jaxb.java.ComplexFormatType;
import org.deegree.process.jaxb.java.ComplexInputDefinition;
import org.deegree.process.jaxb.java.ProcessletInputDefinition;
import org.deegree.services.wps.ProcessletException;
import org.deegree.services.wps.ProcessletInputs;
import org.deegree.services.wps.input.ComplexInput;
import org.deegree.services.wps.input.ProcessletInput;
import org.deegree.services.wps.provider.jrxml.JrxmlUtils;
import org.deegree.services.wps.provider.jrxml.ParameterDescription;
import org.deegree.workspace.Workspace;
import org.jaxen.dom.DOMXPath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

/**
 * Handles XML Datasources, fields must have a prefix 'xml' and suffix 'DetailEntry' and/or 'HeaderEntry'
 * 
 * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz</a>
 * @author last edited by: $Author: lyn $
 * 
 * @version $Revision: $, $Date: $
 */
public class DataTableContentProvider extends AbstractJrxmlContentProvider {

    private static final Logger LOG = LoggerFactory.getLogger(DataTableContentProvider.class);

    public static final String SCHEMA = "http://www.deegree.org/processprovider/table";

    public final static String MIME_TYPE = "text/xml";

    static final String TABLE_PREFIX = "xml";

    static final String DETAIL_SUFFIX = "DetailEntry";

    static final String HEADER_SUFFIX = "HeaderEntry";

    private static final NamespaceBindings nsContext;

    private String datasourceParameterName = JRXPathQueryExecuterFactory.PARAMETER_XML_DATA_DOCUMENT;

    // TODO: multiple datasources/xmlDaraTables!
    // datasource - xmldataTable report parameter must be asigned
    private String tableId;

    static {
        nsContext = JrxmlUtils.nsContext.addNamespace("tbl", SCHEMA);
    }

    public DataTableContentProvider(Workspace workspace) {
        super(workspace);
    }

    public DataTableContentProvider(Workspace workspace, String datasourceParameterName) {
        super(workspace);
        if (datasourceParameterName != null)
            this.datasourceParameterName = datasourceParameterName;
    }

    @Override
    public void inspectInputParametersFromJrxml(Map<String, ParameterDescription> parameterDescriptions,
            List<JAXBElement<? extends ProcessletInputDefinition>> inputs, XMLAdapter jrxmlAdapter,
            Map<String, String> parameters, List<String> handledParameters) {
        List<String> tableIds = new ArrayList<String>();

        List<OMElement> fieldElements = jrxmlAdapter.getElements(jrxmlAdapter.getRootElement(),
                new XPath("/jasper:jasperReport/jasper:field", nsContext));
        for (OMElement fieldElement : fieldElements) {
            String fieldName = fieldElement.getAttributeValue(new QName("name"));
            if (isTableParameter(fieldName)) {
                String identifier = getIdentifierFromParameter(fieldName);
                if (!tableIds.contains(identifier)) {
                    tableIds.add(identifier);
                }
            }
        }

        for (String tableId : tableIds) {
            LOG.debug("Found table component with id " + tableId);
            ComplexInputDefinition comp = new ComplexInputDefinition();
            addInput(comp, parameterDescriptions, tableId, 1, 0);
            ComplexFormatType format = new ComplexFormatType();
            format.setEncoding("UTF-8");
            format.setMimeType(MIME_TYPE);
            format.setSchema(SCHEMA);
            comp.setDefaultFormat(format);
            inputs.add(new JAXBElement<ComplexInputDefinition>(new QName("ProcessInput"),
                    ComplexInputDefinition.class, comp));
            this.tableId = tableId;
        }

    }

    private String getIdentifierFromParameter(String fieldName) {
        return fieldName.substring(TABLE_PREFIX.length(), fieldName.indexOf("_"));
    }

    private boolean isTableParameter(String paramName) {
        return paramName != null
                ? paramName.matches(TABLE_PREFIX + "[a-zA-Z0-9]*_(" + DETAIL_SUFFIX + "|" + HEADER_SUFFIX + ")1")
                : false;
    }

    @Override
    public Pair<InputStream, Boolean> prepareJrxmlAndReadInputParameters(InputStream jrxml,
            Map<String, Object> params, ProcessletInputs in, List<CodeType> processedIds,
            Map<String, String> parameters) throws ProcessletException {
        boolean hasDatasourceInserted = false;
        for (ProcessletInput input : in.getParameters()) {
            if (!processedIds.contains(input.getIdentifier()) && input instanceof ComplexInput) {
                ComplexInput complexIn = (ComplexInput) input;
                if (SCHEMA.equals(complexIn.getSchema()) && MIME_TYPE.equals(complexIn.getMimeType())) {

                    String tableId = complexIn.getIdentifier().getCode();
                    if (tableId.equals(this.tableId)) {
                        LOG.debug("Found input parameter " + tableId + " representing a xml datasource!");
                        ByteArrayOutputStream bos = new ByteArrayOutputStream();
                        try {

                            XMLAdapter jrxmlAdapter = new XMLAdapter(jrxml);
                            OMElement root = jrxmlAdapter.getRootElement();

                            String query = jrxmlAdapter
                                    .getNodeAsString(root,
                                            new XPath("/jasper:jasperReport/jasper:queryString", nsContext), ".")
                                    .trim();

                            XMLStreamReader tableAsStream = complexIn.getValueAsXMLStream();
                            Document document = XMLStreamUtils.getAsDocument(tableAsStream);

                            DOMXPath xpath = new DOMXPath("tbl:Header/tbl:HeaderEntry");
                            xpath.addNamespace("tbl", SCHEMA);
                            int numberOfEntries = xpath.selectNodes(document.getDocumentElement()).size();
                            if (numberOfEntries > 1) {
                                List<OMElement> fieldElements = jrxmlAdapter.getElements(root,
                                        new XPath("/jasper:jasperReport/jasper:field", nsContext));

                                OMFactory factory = OMAbstractFactory.getOMFactory();
                                for (OMElement fieldElement : fieldElements) {
                                    String fieldName = fieldElement.getAttributeValue(new QName("name"));
                                    if (isTableParameter(fieldName)
                                            && tableId.equals(getIdentifierFromParameter(fieldName))) {

                                        OMElement textFieldElement = jrxmlAdapter.getElement(root,
                                                new XPath(
                                                        ".//jasper:textField[jasper:textFieldExpression/text()='$F{"
                                                                + fieldName + "}']",
                                                        nsContext));
                                        for (int i = 2; i < numberOfEntries + 1; i++) {
                                            OMElement newFieldElement = fieldElement.cloneOMElement();
                                            String newFieldName = fieldName.substring(0, fieldName.length() - 1)
                                                    + i;
                                            newFieldElement.addAttribute("name", newFieldName, null);
                                            OMElement fieldDesc = jrxmlAdapter.getElement(newFieldElement,
                                                    new XPath("jasper:fieldDescription", nsContext));
                                            String text = fieldDesc.getText();
                                            text = text.replace("[1]", "[" + i + "]");
                                            setText(factory, fieldDesc, text);
                                            fieldElement.insertSiblingAfter(newFieldElement);

                                            // reference

                                            if (textFieldElement != null) {
                                                int width = jrxmlAdapter.getRequiredNodeAsInteger(textFieldElement,
                                                        new XPath("jasper:reportElement/@width", nsContext));
                                                int x = jrxmlAdapter.getRequiredNodeAsInteger(textFieldElement,
                                                        new XPath("jasper:reportElement/@x", nsContext));
                                                OMElement newDetailTextField = textFieldElement.cloneOMElement();
                                                jrxmlAdapter
                                                        .getElement(newDetailTextField,
                                                                new XPath("jasper:reportElement", nsContext))
                                                        .addAttribute("x", Integer.toString(x + width * (i - 1)),
                                                                null);
                                                OMElement newTextFieldExpr = jrxmlAdapter.getElement(
                                                        newDetailTextField,
                                                        new XPath("jasper:textFieldExpression", nsContext));
                                                setText(factory, newTextFieldExpr, "$F{" + newFieldName + "}");
                                                textFieldElement.insertSiblingAfter(newDetailTextField);
                                            }
                                        }

                                    }
                                }
                                if (LOG.isTraceEnabled()) {
                                    LOG.trace("Adjusted jrxml: " + root);
                                }
                            }

                            // reset xml
                            root.serialize(bos);
                            jrxml = new ByteArrayInputStream(bos.toByteArray());

                            // // add complete input xml
                            // OMNodeEx e ;
                            // OMElement document = tableAdapter.getRootElement();
                            // DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
                            // Document doc = builder.parse( tableAdapter.getRootElement() );
                            // TODO: reload should not be required!
                            if (parameters.containsKey(datasourceParameterName)
                                    && "net.sf.jasperreports.engine.JRDataSource"
                                            .equals(parameters.get(datasourceParameterName))) {
                                InputStream is = getAsInputStream(complexIn.getValueAsXMLStream());
                                params.put(datasourceParameterName, new JRXmlDataSource(is, query));
                            } else {
                                Document doc = getAsDocument(complexIn.getValueAsXMLStream());
                                params.put(datasourceParameterName, doc);
                            }
                            hasDatasourceInserted = true;
                        } catch (Exception e) {
                            String msg = "Could not process data table content: " + e.getMessage();
                            LOG.error(msg, e);
                            throw new ProcessletException(msg);
                        } finally {
                            IOUtils.closeQuietly(bos);
                        }
                        processedIds.add(complexIn.getIdentifier());
                    }
                }
            }
        }
        return new Pair<InputStream, Boolean>(jrxml, hasDatasourceInserted);
    }

    private static Document getAsDocument(XMLStreamReader xmlStreamReader) throws XMLStreamException,
            FactoryConfigurationError, ParserConfigurationException, SAXException, IOException {
        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        StreamBufferStore store = new StreamBufferStore();
        XMLStreamWriter xmlWriter = null;
        try {
            xmlWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(store);
            XMLAdapter.writeElement(xmlWriter, xmlStreamReader);
        } finally {
            if (xmlWriter != null) {
                try {
                    xmlWriter.close();
                } catch (XMLStreamException e) {
                    LOG.error("Unable to close xmlwriter.");
                }
            }
        }
        Document doc = builder.parse(store.getInputStream());
        store.close();
        return doc;
    }

    private static InputStream getAsInputStream(XMLStreamReader xmlStreamReader) throws XMLStreamException,
            FactoryConfigurationError, ParserConfigurationException, SAXException, IOException {
        StreamBufferStore store = new StreamBufferStore();
        XMLStreamWriter xmlWriter = null;
        try {
            xmlWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(store);
            XMLAdapter.writeElement(xmlWriter, xmlStreamReader);
        } finally {
            if (xmlWriter != null) {
                try {
                    xmlWriter.close();
                } catch (XMLStreamException e) {
                    LOG.error("Unable to close xmlwriter.");
                }
            }
        }
        return store.getInputStream();
    }

    void setTableId(String tableId) {
        this.tableId = tableId;
    }

    private void setText(OMFactory factory, OMElement txtElement, String text) {
        // this does not work:
        // e.setText( layer );
        // it attaches the text, but does not replace
        txtElement.getFirstOMChild().detach();
        txtElement.addChild(factory.createOMText(txtElement, text));
    }
}