org.flowable.osgi.BarTransformer Maven / Gradle / Ivy
/* 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.flowable.osgi;
import static org.flowable.osgi.Constants.BUNDLE_FLOWABLE_HEADER;
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.OutputStream;
import java.net.URL;
import java.util.Set;
import java.util.TreeSet;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
/**
* @author Guillaume Nodet
*/
public class BarTransformer {
public static void transform(URL url, OutputStream os) throws Exception {
// Heuristicly retrieve name and version
String name = url.getPath();
int idx = name.lastIndexOf('/');
if (idx >= 0) {
name = name.substring(idx + 1);
}
String[] str = extractNameVersionType(name);
// Build the list of folders containing resources
String pathHeader;
JarInputStream jis = new JarInputStream(url.openStream());
try {
Set paths = new TreeSet<>();
ZipEntry e;
while ((e = jis.getNextEntry()) != null) {
String n = e.getName();
int i = n.lastIndexOf('/');
if (-1 == i) {// Add root path if the .bpmn20.xml is in the root
// of the bar file and the value is
// example.bpmn20.xml
paths.add("/"); // Extender#checkBundle calls the
// HeaderParser#parseHeader and it does not
// parse an empty string
} else if (i < n.length() - 1) {
paths.add(n.substring(0, i + 1));
}
}
StringBuilder sb = new StringBuilder();
for (String s : paths) {
if (sb.length() > 0) {
sb.append(",");
}
sb.append(s);
}
pathHeader = sb.toString();
} finally {
jis.close();
}
// Build the stream
jis = new JarInputStream(url.openStream());
try {
JarOutputStream jos = new JarOutputStream(os);
jos.setLevel(Deflater.NO_COMPRESSION);
// Transform manifest
Manifest m = jis.getManifest();
if (m == null) {
m = new Manifest();
m.getMainAttributes().putValue("Manifest-Version", "2");
}
if (m.getMainAttributes().getValue(BUNDLE_MANIFESTVERSION) == null) {
m.getMainAttributes().putValue(BUNDLE_MANIFESTVERSION, "2");
}
if (m.getMainAttributes().getValue(BUNDLE_SYMBOLICNAME) == null) {
m.getMainAttributes().putValue(BUNDLE_SYMBOLICNAME, str[0]);
}
if (m.getMainAttributes().getValue(BUNDLE_VERSION) == null) {
m.getMainAttributes().putValue(BUNDLE_VERSION, str[1]);
}
m.getMainAttributes().putValue(BUNDLE_FLOWABLE_HEADER, pathHeader);
// Write manifest
ZipEntry e = new ZipEntry(JarFile.MANIFEST_NAME);
jos.putNextEntry(e);
m.write(jos);
jos.closeEntry();
// Write all entries
byte[] readBuffer = new byte[8192];
while ((e = jis.getNextEntry()) != null) {
ZipEntry e2 = new ZipEntry(e.getName());
// e2.setMethod(ZipEntry.STORED);
// e2.setSize(e.getSize());
// e2.setCrc(e.getCrc());
jos.putNextEntry(e2);
int bytesIn = jis.read(readBuffer);
while (bytesIn != -1) {
jos.write(readBuffer, 0, bytesIn);
bytesIn = jis.read(readBuffer);
}
jos.closeEntry();
}
jos.finish();
jos.flush();
} finally {
jis.close();
}
}
private static final String DEFAULT_VERSION = "0.0.0";
private static final Pattern ARTIFACT_MATCHER = Pattern.compile("(.+)(?:-(\\d+)(?:\\.(\\d+)(?:\\.(\\d+))?)?(?:[^a-zA-Z0-9](.*))?)(?:\\.([^\\.]+))", Pattern.DOTALL);
private static final Pattern FUZZY_MODIFIDER = Pattern.compile("(?:\\d+[.-])*(.*)", Pattern.DOTALL);
public static String[] extractNameVersionType(String url) {
Matcher m = ARTIFACT_MATCHER.matcher(url);
if (!m.matches()) {
return new String[]{url, DEFAULT_VERSION};
} else {
// System.err.println(m.groupCount());
// for (int i = 1; i <= m.groupCount(); i++) {
// System.err.println("Group " + i + ": " + m.group(i));
// }
StringBuffer v = new StringBuffer();
String d1 = m.group(1);
String d2 = m.group(2);
String d3 = m.group(3);
String d4 = m.group(4);
String d5 = m.group(5);
String d6 = m.group(6);
if (d2 != null) {
v.append(d2);
if (d3 != null) {
v.append('.');
v.append(d3);
if (d4 != null) {
v.append('.');
v.append(d4);
if (d5 != null) {
v.append(".");
cleanupModifier(v, d5);
}
} else if (d5 != null) {
v.append(".0.");
cleanupModifier(v, d5);
}
} else if (d5 != null) {
v.append(".0.0.");
cleanupModifier(v, d5);
}
}
return new String[]{d1, v.toString(), d6};
}
}
private static void cleanupModifier(StringBuffer result, String modifier) {
Matcher m = FUZZY_MODIFIDER.matcher(modifier);
if (m.matches()) {
modifier = m.group(1);
}
for (int i = 0; i < modifier.length(); i++) {
char c = modifier.charAt(i);
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '-') {
result.append(c);
}
}
}
}