Java tutorial
/* * eXist Open Source Native XML Database * Copyright (C) 2001-09 The eXist Project * http://exist-db.org * * This program 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 * of the License, or (at your option) any later version. * * 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. * * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * $Id$ */ package org.exist.xquery.modules.compression; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import org.apache.commons.io.output.ByteArrayOutputStream; import org.exist.util.MimeTable; import org.exist.util.MimeType; import org.exist.xmldb.EXistResource; import org.exist.xmldb.LocalCollection; import org.exist.xquery.BasicFunction; import org.exist.xquery.FunctionCall; import org.exist.xquery.FunctionSignature; import org.exist.xquery.XPathException; import org.exist.xquery.XQueryContext; import org.exist.xquery.functions.xmldb.XMLDBAbstractCollectionManipulator; import org.exist.xquery.modules.ModuleUtils; import org.exist.xquery.value.AnyURIValue; import org.exist.xquery.value.Base64BinaryValueType; import org.exist.xquery.value.BinaryValue; import org.exist.xquery.value.BinaryValueFromInputStream; import org.exist.xquery.value.BooleanValue; import org.exist.xquery.value.FunctionReference; import org.exist.xquery.value.NodeValue; import org.exist.xquery.value.Sequence; import org.exist.xquery.value.StringValue; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xmldb.api.base.Collection; import org.xmldb.api.base.Resource; import org.xmldb.api.base.XMLDBException; import org.xmldb.api.modules.XMLResource; /** * @author Adam Retter <adam@exist-db.org> * @version 1.0 */ public abstract class AbstractExtractFunction extends BasicFunction { private FunctionReference entryFilterFunction = null; protected Sequence filterParam = null; private FunctionReference entryDataFunction = null; protected Sequence storeParam = null; private Sequence contextSequence; public AbstractExtractFunction(XQueryContext context, FunctionSignature signature) { super(context, signature); } @Override public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException { this.contextSequence = contextSequence; if (args[0].isEmpty()) return Sequence.EMPTY_SEQUENCE; //get the entry-filter function and check its types if (!(args[1].itemAt(0) instanceof FunctionReference)) throw new XPathException("No entry-filter function provided."); entryFilterFunction = (FunctionReference) args[1].itemAt(0); FunctionSignature entryFilterFunctionSig = entryFilterFunction.getSignature(); if (entryFilterFunctionSig.getArgumentCount() < 3) throw new XPathException("entry-filter function must take at least 3 arguments."); filterParam = args[2]; //get the entry-data function and check its types if (!(args[3].itemAt(0) instanceof FunctionReference)) throw new XPathException("No entry-data function provided."); entryDataFunction = (FunctionReference) args[3].itemAt(0); FunctionSignature entryDataFunctionSig = entryDataFunction.getSignature(); if (entryDataFunctionSig.getArgumentCount() < 3) throw new XPathException("entry-data function must take at least 3 arguments"); storeParam = args[4]; BinaryValue compressedData = ((BinaryValue) args[0].itemAt(0)); try { return processCompressedData(compressedData); } catch (XMLDBException e) { throw new XPathException(e); } } /** * Processes a compressed archive * * @param compressedData the compressed data to extract * @return Sequence of results */ protected abstract Sequence processCompressedData(BinaryValue compressedData) throws XPathException, XMLDBException; /** * Processes a compressed entry from an archive * * @param name The name of the entry * @param isDirectory true if the entry is a directory, false otherwise * @param is an InputStream for reading the uncompressed data of the entry * @param filterParam is an additional param for entry filtering function * @param storeParam is an additional param for entry storing function * @throws XMLDBException */ protected Sequence processCompressedEntry(String name, boolean isDirectory, InputStream is, Sequence filterParam, Sequence storeParam) throws IOException, XPathException, XMLDBException { String dataType = isDirectory ? "folder" : "resource"; //call the entry-filter function Sequence filterParams[] = new Sequence[3]; filterParams[0] = new StringValue(name); filterParams[1] = new StringValue(dataType); filterParams[2] = filterParam; Sequence entryFilterFunctionResult = entryFilterFunction.evalFunction(contextSequence, null, filterParams); if (BooleanValue.FALSE == entryFilterFunctionResult.itemAt(0)) { return Sequence.EMPTY_SEQUENCE; } else { Sequence entryDataFunctionResult; Sequence uncompressedData = Sequence.EMPTY_SEQUENCE; //copy the input data ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte buf[] = new byte[1024]; int read = -1; while ((read = is.read(buf)) != -1) { baos.write(buf, 0, read); } byte[] entryData = baos.toByteArray(); if (entryDataFunction.getSignature().getArgumentCount() == 3) { Sequence dataParams[] = new Sequence[3]; System.arraycopy(filterParams, 0, dataParams, 0, 2); dataParams[2] = storeParam; entryDataFunctionResult = entryDataFunction.evalFunction(contextSequence, null, dataParams); String path = entryDataFunctionResult.itemAt(0).getStringValue(); Collection root = new LocalCollection(context.getUser(), context.getBroker().getBrokerPool(), new AnyURIValue("/db").toXmldbURI(), context.getAccessContext()); if (isDirectory) { XMLDBAbstractCollectionManipulator.createCollection(root, path); } else { Resource resource; File file = new File(path); name = file.getName(); path = file.getParent(); Collection target = (path == null) ? root : XMLDBAbstractCollectionManipulator.createCollection(root, path); MimeType mime = MimeTable.getInstance().getContentTypeFor(name); try { NodeValue content = ModuleUtils.streamToXML(context, new ByteArrayInputStream(baos.toByteArray())); resource = target.createResource(name, "XMLResource"); ContentHandler handler = ((XMLResource) resource).setContentAsSAX(); handler.startDocument(); content.toSAX(context.getBroker(), handler, null); handler.endDocument(); } catch (SAXException e) { resource = target.createResource(name, "BinaryResource"); resource.setContent(baos.toByteArray()); } if (resource != null) { if (mime != null) { ((EXistResource) resource).setMimeType(mime.getName()); } target.storeResource(resource); } } } else { //try and parse as xml, fall back to binary try { uncompressedData = ModuleUtils.streamToXML(context, new ByteArrayInputStream(entryData)); } catch (SAXException saxe) { if (entryData.length > 0) uncompressedData = BinaryValueFromInputStream.getInstance(context, new Base64BinaryValueType(), new ByteArrayInputStream(entryData)); } //call the entry-data function Sequence dataParams[] = new Sequence[4]; System.arraycopy(filterParams, 0, dataParams, 0, 2); dataParams[2] = uncompressedData; dataParams[3] = storeParam; entryDataFunctionResult = entryDataFunction.evalFunction(contextSequence, null, dataParams); } return entryDataFunctionResult; } } }