/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.ui.wizards;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.teiid.core.designer.util.CoreStringUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Exports resources to a .zip file
*
* @since 8.0
*/
public class ModelerZipExporter {
private ZipOutputStream outputStream;
private boolean useCompression = true;
private boolean clearSourceConnectionInfo = true;
// constants
/**
* Create an instance of this class.
*
* @param filename
* java.lang.String
* @param compress
* boolean
* @param includeManifestFile
* boolean
* @param clearSourceConnectionInfo
* boolean
* @exception java.io.IOException
*/
public ModelerZipExporter(String filename, boolean compress,
boolean clearSourceConnectionInfo) throws IOException {
this.outputStream = new ZipOutputStream(new FileOutputStream(filename));
this.useCompression = compress;
this.clearSourceConnectionInfo = clearSourceConnectionInfo;
}
/**
* Do all required cleanup now that we're finished with the currently-open
* .zip
*
* @exception java.io.IOException
*/
public void finished() throws IOException {
outputStream.close();
}
/**
* Create a new ZipEntry with the passed pathname and contents, and write it
* to the current archive
*
* @param pathname
* java.lang.String
* @param contents
* byte[]
* @exception java.io.IOException
*/
protected void write(String pathname, byte[] contents) throws IOException {
ZipEntry newEntry = new ZipEntry(pathname);
// if the contents are being compressed then we get the below for free.
if (!useCompression) {
newEntry.setMethod(ZipEntry.STORED);
newEntry.setSize(contents.length);
CRC32 checksumCalculator = new CRC32();
checksumCalculator.update(contents);
newEntry.setCrc(checksumCalculator.getValue());
}
outputStream.putNextEntry(newEntry);
outputStream.write(contents);
outputStream.closeEntry();
}
/**
* Write the passed resource to the current archive
*
* @param resource
* org.eclipse.core.resources.IFile
* @param destinationPath
* java.lang.String
* @exception java.io.IOException
* @exception org.eclipse.core.runtime.CoreException
* @throws TransformerFactoryConfigurationError
* @throws TransformerException
* @throws TransformerConfigurationException
*/
public void write(IFile resource, String destinationPath)
throws IOException, CoreException, SAXException,
ParserConfigurationException, TransformerConfigurationException,
TransformerException, TransformerFactoryConfigurationError {
ByteArrayOutputStream output = null;
InputStream contentStream = null;
Document doc = null;
// If the user wants to remove the connection info during export and
// this is a model file, look for "tags" with key values that start
// with "connection" and remove the node
if (this.clearSourceConnectionInfo
&& resource.getFileExtension().equals("xmi")) { //$NON-NLS-1$
contentStream = resource.getContents(false);
doc = readXml(contentStream);
removeAll(doc, Node.ELEMENT_NODE, "tags", "connection"); //$NON-NLS-1$ //$NON-NLS-2$
doc.normalize();
contentStream = convertDocToInputStream(doc);
}
try {
output = new ByteArrayOutputStream();
if (contentStream == null)
contentStream = resource.getContents(false);
int chunkSize = contentStream.available();
byte[] readBuffer = new byte[chunkSize];
int n = contentStream.read(readBuffer);
while (n > 0) {
output.write(readBuffer);
n = contentStream.read(readBuffer);
}
} finally {
if (output != null)
output.close();
if (contentStream != null)
contentStream.close();
}
write(destinationPath, output.toByteArray());
}
// This method walks the document and removes all nodes
// of the specified type and specified name that satisfy the filter condition.
public static void removeAll(Node node, short nodeType, String name, String filter) {
if (node.getNodeType() == nodeType && node.getNodeName().equals(name)
&& node.getAttributes().getNamedItem("key").getTextContent().startsWith(filter)) { //$NON-NLS-1$
node.getParentNode().removeChild(node);
} else {
// Visit the children
NodeList list = node.getChildNodes();
for (int i=0; i<list.getLength(); i++) {
removeAll(list.item(i), nodeType, name, filter);
}
}
}
/**
* Read XML as DOM.
*/
public Document readXml(InputStream is) throws SAXException, IOException,
ParserConfigurationException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(false);
dbf.setIgnoringComments(false);
dbf.setIgnoringElementContentWhitespace(true);
dbf.setNamespaceAware(true);
DocumentBuilder db = null;
db = dbf.newDocumentBuilder();
db.setEntityResolver(new NullResolver());
return db.parse(is);
}
public InputStream convertDocToInputStream(Document doc)
throws TransformerConfigurationException, TransformerException,
TransformerFactoryConfigurationError {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Source xmlSource = new DOMSource(doc);
Result outputTarget = new StreamResult(outputStream);
TransformerFactory.newInstance().newTransformer().transform(xmlSource,
outputTarget);
InputStream is = new ByteArrayInputStream(outputStream.toByteArray());
return is;
}
class NullResolver implements EntityResolver {
@Override
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
return new InputSource(new StringReader(
CoreStringUtil.Constants.EMPTY_STRING));
}
}
}