/*
- * Copyright (C) 2007-2012 Mathieu Baudier
+ * Copyright (C) 2007-2012 Argeo GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.Properties;
import java.util.jar.Attributes;
import java.util.jar.Attributes.Name;
+import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
* Indexes jar file, currently supports standard J2SE and OSGi metadata (both
* from MANIFEST)
*/
-public class JarFileIndexer implements NodeIndexer {
+public class JarFileIndexer implements NodeIndexer, SlcNames {
private final static Log log = LogFactory.getLog(JarFileIndexer.class);
+ private Boolean force = false;
public Boolean support(String path) {
return FilenameUtils.getExtension(path).equals("jar");
ByteArrayInputStream bi = null;
Binary manifestBinary = null;
try {
+ if (!support(fileNode.getPath()))
+ return;
+
+ // Already indexed
+ if (!force && fileNode.isNodeType(SlcTypes.SLC_JAR_FILE))
+ return;
+
if (!fileNode.isNodeType(NodeType.NT_FILE))
return;
Session jcrSession = fileNode.getSession();
Node contentNode = fileNode.getNode(Node.JCR_CONTENT);
fileBinary = contentNode.getProperty(Property.JCR_DATA).getBinary();
- // jar file
- // if (!FilenameUtils.isExtension(fileNode.getName(), "jar")) {
- // return;
- // }
jarIn = new JarInputStream(fileBinary.getStream());
Manifest manifest = jarIn.getManifest();
log.error(fileNode + " has no MANIFEST");
return;
}
+
bo = new ByteArrayOutputStream();
manifest.write(bo);
- bi = new ByteArrayInputStream(bo.toByteArray());
+ byte[] newManifest = bo.toByteArray();
+ if (fileNode.hasProperty(SLC_MANIFEST)) {
+ byte[] storedManifest = JcrUtils.getBinaryAsBytes(fileNode
+ .getProperty(SLC_MANIFEST));
+ if (Arrays.equals(newManifest, storedManifest)) {
+ if (log.isTraceEnabled())
+ log.trace("Manifest not changed, doing nothing "
+ + fileNode);
+ return;
+ }
+ }
+
+ bi = new ByteArrayInputStream(newManifest);
manifestBinary = jcrSession.getValueFactory().createBinary(bi);
// standard jar file
fileNode.addMixin(SlcTypes.SLC_JAR_FILE);
+
fileNode.setProperty(SlcNames.SLC_MANIFEST, manifestBinary);
Attributes attrs = manifest.getMainAttributes();
- if (log.isTraceEnabled())
- for (Object key : attrs.keySet())
- log.trace(key + ": " + attrs.getValue(key.toString()));
+
+ getI18nValues(fileBinary, attrs);
// standard J2SE MANIFEST attributes
addAttr(Attributes.Name.MANIFEST_VERSION, fileNode, attrs);
// OSGi
if (attrs.containsKey(new Name(Constants.BUNDLE_SYMBOLICNAME))) {
addOsgiMetadata(fileNode, attrs);
- JcrUtils.updateLastModified(fileNode);
if (log.isTraceEnabled())
log.trace("Indexed OSGi bundle " + fileNode);
} else {
- JcrUtils.updateLastModified(fileNode);
if (log.isTraceEnabled())
log.trace("Indexed JAR file " + fileNode);
}
+
+ JcrUtils.updateLastModified(fileNode);
+
} catch (Exception e) {
throw new SlcException("Cannot index jar " + fileNode, e);
} finally {
}
+ private void getI18nValues(Binary fileBinary, Attributes attrs)
+ throws IOException {
+ JarInputStream jarIn = null;
+ try {
+ jarIn = new JarInputStream(fileBinary.getStream());
+ String bundleLocalization = null;
+
+ String blKey = Constants.BUNDLE_LOCALIZATION; // "Bundle-Localization";
+ Name blkName = new Name(blKey);
+
+ browse: for (Object obj : attrs.keySet()) {
+ String value = attrs.getValue((Attributes.Name) obj);
+ if (value.startsWith("%")) {
+ if (attrs.containsKey(blkName)) {
+ bundleLocalization = attrs.getValue(blkName);
+ break browse;
+ }
+ }
+ }
+
+ JarEntry jarEntry = null;
+ byte[] propBytes = null;
+ ByteArrayOutputStream baos = null;
+ browse: if (bundleLocalization != null) {
+ JarEntry entry = jarIn.getNextJarEntry();
+ while (entry != null) {
+ if (entry.getName().equals(
+ bundleLocalization + ".properties")) {
+ jarEntry = entry;
+
+ // if(je.getSize() != -1){
+ // propBytes = new byte[(int)je.getSize()];
+ // int len = (int) je.getSize();
+ // int offset = 0;
+ // while (offset != len)
+ // offset += jarIn.read(propBytes, offset, len -
+ // offset);
+ // } else {
+ baos = new ByteArrayOutputStream();
+ while (true) {
+ int qwe = jarIn.read();
+ if (qwe == -1)
+ break;
+ baos.write(qwe);
+ }
+ propBytes = baos.toByteArray();
+ break browse;
+ }
+ entry = jarIn.getNextJarEntry();
+ }
+ }
+
+ if (jarEntry != null) {
+ Properties prop = new Properties();
+ InputStream is = new ByteArrayInputStream(propBytes);
+ prop.load(is);
+
+ for (Object obj : attrs.keySet()) {
+ String value = attrs.getValue((Attributes.Name) obj);
+ if (value.startsWith("%")) {
+ String newVal = prop.getProperty(value.substring(1));
+ if (newVal != null)
+ attrs.put(obj, newVal);
+ }
+ }
+ }
+ } catch (RepositoryException e) {
+ throw new SlcException(
+ "Error while reading the jar binary content " + fileBinary,
+ e);
+ } catch (IOException ioe) {
+ throw new SlcException("unable to get internationalized values",
+ ioe);
+ } finally {
+ IOUtils.closeQuietly(jarIn);
+ }
+ }
+
protected void addOsgiMetadata(Node fileNode, Attributes attrs)
throws RepositoryException {
+
+ // TODO remove this ?
+ // Compulsory for the time being, because bundle artifact extends
+ // artifact
+ if (!fileNode.isNodeType(SlcTypes.SLC_ARTIFACT)) {
+ ArtifactIndexer indexer = new ArtifactIndexer();
+ indexer.index(fileNode);
+ }
+
fileNode.addMixin(SlcTypes.SLC_BUNDLE_ARTIFACT);
// symbolic name
cleanSubNodes(fileNode, SlcNames.SLC_ + Constants.IMPORT_PACKAGE);
if (attrs.containsKey(new Name(Constants.IMPORT_PACKAGE))) {
String importPackages = attrs.getValue(Constants.IMPORT_PACKAGE);
- List<String> packages = parsePackages(importPackages);
+ List<String> packages = parseCommaSeparated(importPackages);
for (String pkg : packages) {
String[] tokens = pkg.split(";");
Node node = fileNode.addNode(SlcNames.SLC_
if (attrs.containsKey(new Name(Constants.DYNAMICIMPORT_PACKAGE))) {
String importPackages = attrs
.getValue(Constants.DYNAMICIMPORT_PACKAGE);
- List<String> packages = parsePackages(importPackages);
+ List<String> packages = parseCommaSeparated(importPackages);
for (String pkg : packages) {
String[] tokens = pkg.split(";");
Node node = fileNode.addNode(SlcNames.SLC_
cleanSubNodes(fileNode, SlcNames.SLC_ + Constants.EXPORT_PACKAGE);
if (attrs.containsKey(new Name(Constants.EXPORT_PACKAGE))) {
String exportPackages = attrs.getValue(Constants.EXPORT_PACKAGE);
- List<String> packages = parsePackages(exportPackages);
+ List<String> packages = parseCommaSeparated(exportPackages);
for (String pkg : packages) {
String[] tokens = pkg.split(";");
Node node = fileNode.addNode(SlcNames.SLC_
cleanSubNodes(fileNode, SlcNames.SLC_ + Constants.REQUIRE_BUNDLE);
if (attrs.containsKey(new Name(Constants.REQUIRE_BUNDLE))) {
String requireBundle = attrs.getValue(Constants.REQUIRE_BUNDLE);
- String[] bundles = requireBundle.split(",");
+ List<String> bundles = parseCommaSeparated(requireBundle);
for (String bundle : bundles) {
String[] tokens = bundle.split(";");
Node node = fileNode.addNode(SlcNames.SLC_
}
/** Parse package list with nested directive with ',' */
- private List<String> parsePackages(String str) {
+ private List<String> parseCommaSeparated(String str) {
List<String> res = new ArrayList<String>();
StringBuffer curr = new StringBuffer("");
boolean in = false;
for (char c : str.toCharArray()) {
if (c == ',') {
- if (!in) {
+ if (!in) {// new package
res.add(curr.toString());
curr = new StringBuffer("");
+ } else {// a ',' within " "
+ curr.append(c);
}
} else if (c == '\"') {
in = !in;
version.getQualifier());
}
+ public void setForce(Boolean force) {
+ this.force = force;
+ }
+
}