/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.camunda.bpm.extension.osgi.fileinstall.impl;
import static org.camunda.bpm.extension.osgi.Constants.BUNDLE_PROCESS_DEFINITIONS_HEADER;
import static org.camunda.bpm.extension.osgi.Constants.BUNDLE_PROCESS_DEFINTIONS_DEFAULT;
import static org.osgi.framework.Constants.BUNDLE_MANIFESTVERSION;
import static org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME;
import static org.osgi.framework.Constants.BUNDLE_VERSION;
import java.io.ByteArrayInputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Properties;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.camunda.bpm.extension.osgi.fileinstall.impl.util.NameVersionTypeExtractor;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* Helper class to actually transform the BPMN xml file into a bundle.
*
* @author <a href="gnodet@gmail.com">Guillaume Nodet</a>
* @author Ronny Bräunlich
*/
public class BpmnTransformer {
private static final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
private static final TransformerFactory tf = TransformerFactory.newInstance();
public void transform(URL url, OutputStream os) throws Exception {
// Build dom document
Document doc = parse(url);
// Heuristicly retrieve name and version
String name = url.getPath();
int idx = name.lastIndexOf('/');
if (idx >= 0) {
name = name.substring(idx + 1);
}
String[] str = NameVersionTypeExtractor.extractNameVersionType(name);
// Create manifest
Manifest m = new Manifest();
m.getMainAttributes().putValue("Manifest-Version", "2");
m.getMainAttributes().putValue(BUNDLE_MANIFESTVERSION, "2");
m.getMainAttributes().putValue(BUNDLE_SYMBOLICNAME, str[0]);
m.getMainAttributes().putValue(BUNDLE_VERSION, str[1]);
m.getMainAttributes().putValue(BUNDLE_PROCESS_DEFINITIONS_HEADER,
BUNDLE_PROCESS_DEFINTIONS_DEFAULT);
// Extract manifest entries from the DOM
NodeList l = doc.getElementsByTagName("manifest");
if (l != null) {
for (int i = 0; i < l.getLength(); i++) {
Element e = (Element) l.item(i);
String text = e.getTextContent();
Properties props = new Properties();
props.load(new ByteArrayInputStream(text.trim().getBytes()));
Set<String> en = props.stringPropertyNames();
for (String k : en) {
String v = props.getProperty(k);
m.getMainAttributes().putValue(k, v);
}
e.getParentNode().removeChild(e);
}
}
JarOutputStream out = new JarOutputStream(os);
ZipEntry e = new ZipEntry(JarFile.MANIFEST_NAME);
out.putNextEntry(e);
m.write(out);
out.closeEntry();
e = new ZipEntry("OSGI-INF/");
out.putNextEntry(e);
String processDefDir = m.getMainAttributes().getValue(BUNDLE_PROCESS_DEFINITIONS_HEADER);
e = new ZipEntry(processDefDir);
out.putNextEntry(e);
out.closeEntry();
e = new ZipEntry(processDefDir + name);
out.putNextEntry(e);
// Copy the new DOM
tf.newTransformer()
.transform(new DOMSource(doc), new StreamResult(out));
out.closeEntry();
out.close();
}
private Document parse(URL url) throws Exception {
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
return db.parse(url.toString());
}
}