+
+ return artifacts;
+ } catch (Exception e) {
+ throw new SlcException("Cannot resolve distribution", e);
+ }
+ }
+
+ protected void syncDistribution(Set<Artifact> artifacts) {
+ Long begin = System.currentTimeMillis();
+ try {
+ JcrUtils.mkdirs(jcrSession, artifactBasePath);
+ JcrUtils.mkdirs(jcrSession, distributionsBasePath + '/'
+ + distributionName);
+ artifacts: for (Artifact artifact : artifacts) {
+ File file = artifact.getFile();
+ if (file == null) {
+ log.warn("File not found for " + artifact);
+
+ file = artifactToFile(artifact);
+
+ if (!file.exists()) {
+ log.warn("Generated file " + file + " for " + artifact
+ + " does not exist");
+ continue artifacts;
+ }
+ }
+
+ try {
+ String parentPath = artifactBasePath + '/'
+ + artifactParentPath(artifact);
+ Node parentNode;
+ if (!jcrSession.itemExists(parentPath)) {
+ parentNode = JcrUtils.mkdirs(jcrSession, parentPath,
+ NodeType.NT_FOLDER, false);
+ } else {
+ parentNode = jcrSession.getNode(parentPath);
+ }
+
+ Node fileNode;
+ if (!parentNode.hasNode(file.getName())) {
+ fileNode = createFileNode(parentNode, file);
+ } else {
+ fileNode = parentNode.getNode(file.getName());
+ }
+ processArtifact(fileNode, artifact);
+ if (fileNode.isNodeType(RepoTypes.SLC_JAR_FILE)) {
+ processOsgiBundle(fileNode);
+ }
+ jcrSession.save();
+
+ if (!jcrSession
+ .itemExists(bundleDistributionPath(fileNode))
+ && fileNode
+ .isNodeType(RepoTypes.SLC_BUNDLE_ARTIFACT))
+ jcrSession.getWorkspace().clone(
+ jcrSession.getWorkspace().getName(),
+ fileNode.getPath(),
+ bundleDistributionPath(fileNode), false);
+
+ if (log.isDebugEnabled())
+ log.debug("Synchronized " + fileNode);
+ } catch (Exception e) {
+ log.error("Could not synchronize " + artifact, e);
+ jcrSession.refresh(false);
+ throw e;
+ }
+ }
+
+ Long duration = (System.currentTimeMillis() - begin) / 1000;
+ if (log.isDebugEnabled())
+ log.debug("Synchronized distribution in " + duration + "s");
+ } catch (Exception e) {
+ throw new SlcException("Cannot synchronize distribution", e);
+ }
+ }
+
+ protected String artifactParentPath(Artifact artifact) {
+ return artifact.getGroupId().replace('.', '/') + '/'
+ + artifact.getArtifactId() + '/' + artifact.getVersion();
+ }
+
+ protected String bundleDistributionPath(Node fileNode) {
+ try {
+ return distributionsBasePath
+ + '/'
+ + distributionName
+ + '/'
+ + fileNode.getProperty(RepoNames.SLC_SYMBOLIC_NAME)
+ .getString()
+ + '_'
+ + fileNode.getProperty(RepoNames.SLC_BUNDLE_VERSION)
+ .getString();
+ } catch (RepositoryException e) {
+ throw new SlcException("Cannot create distribution path for "
+ + fileNode, e);
+ }
+ }
+
+ protected void processArtifact(Node fileNode, Artifact artifact) {
+ try {
+ fileNode.addMixin(RepoTypes.SLC_ARTIFACT);
+ fileNode.setProperty(RepoNames.SLC_ARTIFACT_ID,
+ artifact.getArtifactId());
+ fileNode.setProperty(RepoNames.SLC_GROUP_ID, artifact.getGroupId());
+ fileNode.setProperty(RepoNames.SLC_ARTIFACT_VERSION,
+ artifact.getVersion());
+ fileNode.setProperty(RepoNames.SLC_ARTIFACT_EXTENSION,
+ artifact.getExtension());
+ fileNode.setProperty(RepoNames.SLC_ARTIFACT_CLASSIFIER,
+ artifact.getClassifier());
+ } catch (RepositoryException e) {
+ throw new SlcException("Cannot process artifact " + artifact
+ + " on node " + fileNode, e);
+ }
+
+ }
+
+ protected File artifactToFile(Artifact artifact) {
+ return new File(System.getProperty("user.home")
+ + File.separator
+ + ".m2"
+ + File.separator
+ + "repository"
+ + File.separator
+ + artifact.getGroupId().replace('.', File.separatorChar)
+ + File.separator
+ + artifact.getArtifactId()
+ + File.separator
+ + artifact.getVersion()
+ + File.separator
+ + artifact.getArtifactId()
+ + '-'
+ + artifact.getVersion()
+ + (artifact.getClassifier().equals("") ? ""
+ : '-' + artifact.getClassifier()) + '.'
+ + artifact.getExtension());
+ }
+
+ protected void processOsgiBundle(Node fileNode) {
+ Binary manifestBinary = null;
+ InputStream manifestIn = null;
+ try {
+ manifestBinary = fileNode.getProperty(RepoNames.SLC_MANIFEST)
+ .getBinary();
+ manifestIn = manifestBinary.getStream();
+ Manifest manifest = new Manifest(manifestIn);
+ Attributes attrs = manifest.getMainAttributes();
+
+ if (log.isTraceEnabled())
+ for (Object key : attrs.keySet())
+ log.trace(key + ": " + attrs.getValue(key.toString()));
+
+ if (!attrs.containsKey(new Name(Constants.BUNDLE_SYMBOLICNAME))) {
+ log.warn(fileNode + " is not an OSGi bundle");
+ return;// not an osgi bundle
+ }
+
+ fileNode.addMixin(RepoTypes.SLC_BUNDLE_ARTIFACT);
+
+ // symbolic name
+ String symbolicName = attrs.getValue(Constants.BUNDLE_SYMBOLICNAME);
+ // make sure there is no directive
+ symbolicName = symbolicName.split(";")[0];
+ fileNode.setProperty(RepoNames.SLC_SYMBOLIC_NAME, symbolicName);
+
+ // direct mapping
+ addAttr(Constants.BUNDLE_SYMBOLICNAME, fileNode, attrs);
+ addAttr(Constants.BUNDLE_NAME, fileNode, attrs);
+ addAttr(Constants.BUNDLE_DESCRIPTION, fileNode, attrs);
+ addAttr(Constants.BUNDLE_MANIFESTVERSION, fileNode, attrs);
+ addAttr(Constants.BUNDLE_CATEGORY, fileNode, attrs);
+ addAttr(Constants.BUNDLE_ACTIVATIONPOLICY, fileNode, attrs);
+ addAttr(Constants.BUNDLE_COPYRIGHT, fileNode, attrs);
+ addAttr(Constants.BUNDLE_VENDOR, fileNode, attrs);
+ addAttr("Bundle-License", fileNode, attrs);
+ addAttr(Constants.BUNDLE_DOCURL, fileNode, attrs);
+ addAttr(Constants.BUNDLE_CONTACTADDRESS, fileNode, attrs);
+ addAttr(Constants.BUNDLE_ACTIVATOR, fileNode, attrs);
+ addAttr(Constants.BUNDLE_UPDATELOCATION, fileNode, attrs);
+ addAttr(Constants.BUNDLE_LOCALIZATION, fileNode, attrs);
+
+ // required execution environment
+ if (attrs.containsKey(new Name(
+ Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT)))
+ fileNode.setProperty(
+ RepoNames.SLC_
+ + Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT,
+ attrs.getValue(
+ Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT)
+ .split(","));
+
+ // bundle classpath
+ if (attrs.containsKey(new Name(Constants.BUNDLE_CLASSPATH)))
+ fileNode.setProperty(RepoNames.SLC_
+ + Constants.BUNDLE_CLASSPATH,
+ attrs.getValue(Constants.BUNDLE_CLASSPATH).split(","));
+
+ // version
+ Version version = new Version(
+ attrs.getValue(Constants.BUNDLE_VERSION));
+ fileNode.setProperty(RepoNames.SLC_BUNDLE_VERSION,
+ version.toString());
+ cleanSubNodes(fileNode, RepoNames.SLC_ + Constants.BUNDLE_VERSION);
+ Node bundleVersionNode = fileNode.addNode(RepoNames.SLC_
+ + Constants.BUNDLE_VERSION, RepoTypes.SLC_OSGI_VERSION);
+ mapOsgiVersion(version, bundleVersionNode);
+
+ // fragment
+ cleanSubNodes(fileNode, RepoNames.SLC_ + Constants.FRAGMENT_HOST);
+ if (attrs.containsKey(new Name(Constants.FRAGMENT_HOST))) {
+ String fragmentHost = attrs.getValue(Constants.FRAGMENT_HOST);
+ String[] tokens = fragmentHost.split(";");
+ Node node = fileNode.addNode(RepoNames.SLC_
+ + Constants.FRAGMENT_HOST, RepoTypes.SLC_FRAGMENT_HOST);
+ node.setProperty(RepoNames.SLC_SYMBOLIC_NAME, tokens[0]);
+ for (int i = 1; i < tokens.length; i++) {
+ if (tokens[i]
+ .startsWith(Constants.BUNDLE_VERSION_ATTRIBUTE)) {
+ node.setProperty(RepoNames.SLC_BUNDLE_VERSION,
+ attributeValue(tokens[i]));
+ }
+ }
+ }
+
+ // imported packages
+ cleanSubNodes(fileNode, RepoNames.SLC_ + Constants.IMPORT_PACKAGE);
+ if (attrs.containsKey(new Name(Constants.IMPORT_PACKAGE))) {
+ String importPackages = attrs
+ .getValue(Constants.IMPORT_PACKAGE);
+ List<String> packages = parsePackages(importPackages);
+ for (String pkg : packages) {
+ String[] tokens = pkg.split(";");
+ Node node = fileNode.addNode(RepoNames.SLC_
+ + Constants.IMPORT_PACKAGE,
+ RepoTypes.SLC_IMPORTED_PACKAGE);
+ node.setProperty(RepoNames.SLC_NAME, tokens[0]);
+ for (int i = 1; i < tokens.length; i++) {
+ if (tokens[i].startsWith(Constants.VERSION_ATTRIBUTE)) {
+ node.setProperty(RepoNames.SLC_VERSION,
+ attributeValue(tokens[i]));
+ } else if (tokens[i]
+ .startsWith(Constants.RESOLUTION_DIRECTIVE)) {
+ node.setProperty(
+ RepoNames.SLC_OPTIONAL,
+ directiveValue(tokens[i]).equals(
+ Constants.RESOLUTION_OPTIONAL));
+ }
+ }
+ }
+ }
+
+ // dynamic import package
+ cleanSubNodes(fileNode, RepoNames.SLC_
+ + Constants.DYNAMICIMPORT_PACKAGE);
+ if (attrs.containsKey(new Name(Constants.DYNAMICIMPORT_PACKAGE))) {
+ String importPackages = attrs
+ .getValue(Constants.DYNAMICIMPORT_PACKAGE);
+ List<String> packages = parsePackages(importPackages);
+ for (String pkg : packages) {
+ String[] tokens = pkg.split(";");
+ Node node = fileNode.addNode(RepoNames.SLC_
+ + Constants.DYNAMICIMPORT_PACKAGE,
+ RepoTypes.SLC_DYNAMIC_IMPORTED_PACKAGE);
+ node.setProperty(RepoNames.SLC_NAME, tokens[0]);
+ for (int i = 1; i < tokens.length; i++) {
+ if (tokens[i].startsWith(Constants.VERSION_ATTRIBUTE)) {
+ node.setProperty(RepoNames.SLC_VERSION,
+ attributeValue(tokens[i]));
+ }
+ }
+ }
+ }
+
+ // exported packages
+ cleanSubNodes(fileNode, RepoNames.SLC_ + Constants.EXPORT_PACKAGE);
+ if (attrs.containsKey(new Name(Constants.EXPORT_PACKAGE))) {
+ String exportPackages = attrs
+ .getValue(Constants.EXPORT_PACKAGE);
+ List<String> packages = parsePackages(exportPackages);
+ for (String pkg : packages) {
+ String[] tokens = pkg.split(";");
+ Node node = fileNode.addNode(RepoNames.SLC_
+ + Constants.EXPORT_PACKAGE,
+ RepoTypes.SLC_EXPORTED_PACKAGE);
+ node.setProperty(RepoNames.SLC_NAME, tokens[0]);
+ // TODO: are these cleans really necessary?
+ cleanSubNodes(node, RepoNames.SLC_USES);
+ cleanSubNodes(node, RepoNames.SLC_VERSION);
+ for (int i = 1; i < tokens.length; i++) {
+ if (tokens[i].startsWith(Constants.VERSION_ATTRIBUTE)) {
+ String versionStr = attributeValue(tokens[i]);
+ Node versionNode = node.addNode(
+ RepoNames.SLC_VERSION,
+ RepoTypes.SLC_OSGI_VERSION);
+ mapOsgiVersion(new Version(versionStr), versionNode);
+ } else if (tokens[i]
+ .startsWith(Constants.USES_DIRECTIVE)) {
+ String usedPackages = directiveValue(tokens[i]);
+ // log.debug("uses='" + usedPackages + "'");
+ for (String usedPackage : usedPackages.split(",")) {
+ // log.debug("usedPackage='" + usedPackage +
+ // "'");
+ Node usesNode = node.addNode(
+ RepoNames.SLC_USES,
+ RepoTypes.SLC_JAVA_PACKAGE);
+ usesNode.setProperty(RepoNames.SLC_NAME,
+ usedPackage);
+ }
+ }
+ }
+ }
+ }
+
+ // required bundle
+ cleanSubNodes(fileNode, RepoNames.SLC_ + Constants.REQUIRE_BUNDLE);
+ if (attrs.containsKey(new Name(Constants.REQUIRE_BUNDLE))) {
+ String requireBundle = attrs.getValue(Constants.REQUIRE_BUNDLE);
+ String[] bundles = requireBundle.split(",");
+ for (String bundle : bundles) {
+ String[] tokens = bundle.split(";");
+ Node node = fileNode.addNode(RepoNames.SLC_
+ + Constants.REQUIRE_BUNDLE,
+ RepoTypes.SLC_REQUIRED_BUNDLE);
+ node.setProperty(RepoNames.SLC_SYMBOLIC_NAME, tokens[0]);
+ for (int i = 1; i < tokens.length; i++) {
+ if (tokens[i]
+ .startsWith(Constants.BUNDLE_VERSION_ATTRIBUTE)) {
+ node.setProperty(RepoNames.SLC_BUNDLE_VERSION,
+ attributeValue(tokens[i]));
+ } else if (tokens[i]
+ .startsWith(Constants.RESOLUTION_DIRECTIVE)) {
+ node.setProperty(
+ RepoNames.SLC_OPTIONAL,
+ directiveValue(tokens[i]).equals(
+ Constants.RESOLUTION_OPTIONAL));
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new SlcException("Cannot process OSGi bundle " + fileNode, e);
+ } finally {
+ if (manifestBinary != null)
+ manifestBinary.dispose();
+ IOUtils.closeQuietly(manifestIn);
+ }
+ }
+
+ /** Parse package list with nested directive with ',' */
+ private List<String> parsePackages(String str) {
+ List<String> res = new ArrayList<String>();
+ StringBuffer curr = new StringBuffer("");
+ boolean in = false;
+ for (char c : str.toCharArray()) {
+ if (c == ',') {
+ if (!in) {
+ res.add(curr.toString());
+ curr = new StringBuffer("");
+ }
+ } else if (c == '\"') {
+ in = !in;
+ curr.append(c);
+ } else {
+ curr.append(c);
+ }
+ }
+ res.add(curr.toString());
+ log.debug(res);
+ return res;
+ }
+
+ private void addAttr(String key, Node node, Attributes attrs)
+ throws RepositoryException {
+ addAttr(new Name(key), node, attrs);
+ }
+
+ private void addAttr(Name key, Node node, Attributes attrs)
+ throws RepositoryException {
+ if (attrs.containsKey(key)) {
+ String value = attrs.getValue(key);
+ node.setProperty(RepoNames.SLC_ + key, value);
+ }
+ }
+
+ private void cleanSubNodes(Node node, String name)
+ throws RepositoryException {
+ if (node.hasNode(name)) {
+ NodeIterator nit = node.getNodes(name);
+ while (nit.hasNext())
+ nit.nextNode().remove();
+ }
+ }
+
+ protected void mapOsgiVersion(Version version, Node versionNode)
+ throws RepositoryException {
+ versionNode.setProperty(RepoNames.SLC_AS_STRING, version.toString());
+ versionNode.setProperty(RepoNames.SLC_MAJOR, version.getMajor());
+ versionNode.setProperty(RepoNames.SLC_MINOR, version.getMinor());
+ versionNode.setProperty(RepoNames.SLC_MICRO, version.getMicro());
+ if (!version.getQualifier().equals(""))
+ versionNode.setProperty(RepoNames.SLC_QUALIFIER,
+ version.getQualifier());
+ }
+
+ private String attributeValue(String str) {
+ return extractValue(str, "=");
+ }
+
+ private String directiveValue(String str) {
+ return extractValue(str, ":=");
+ }
+
+ private String extractValue(String str, String eq) {
+ String[] tokens = str.split(eq);
+ // String key = tokens[0];
+ String value = tokens[1].trim();
+ // TODO: optimize?
+ if (value.startsWith("\""))
+ value = value.substring(1);
+ if (value.endsWith("\""))
+ value = value.substring(0, value.length() - 1);
+ return value;
+ }
+
+ protected Node createFileNode(Node parentNode, File file) {
+ Binary binary = null;
+ try {
+ Node fileNode = parentNode
+ .addNode(file.getName(), NodeType.NT_FILE);
+ Node contentNode = fileNode.addNode(Node.JCR_CONTENT,
+ NodeType.NT_RESOURCE);
+ binary = jcrSession.getValueFactory().createBinary(
+ new FileInputStream(file));
+ contentNode.setProperty(Property.JCR_DATA, binary);
+ // jar file
+ if (FilenameUtils.isExtension(file.getName(), "jar")) {
+ JarInputStream jarIn = null;
+ ByteArrayOutputStream bo = null;
+ ByteArrayInputStream bi = null;
+ Binary manifestBinary = null;
+ try {
+ jarIn = new JarInputStream(binary.getStream());
+ Manifest manifest = jarIn.getManifest();
+ bo = new ByteArrayOutputStream();
+ manifest.write(bo);
+ bi = new ByteArrayInputStream(bo.toByteArray());
+ manifestBinary = jcrSession.getValueFactory().createBinary(
+ bi);
+ fileNode.addMixin(RepoTypes.SLC_JAR_FILE);
+ fileNode.setProperty(RepoNames.SLC_MANIFEST, manifestBinary);
+ Attributes attrs = manifest.getMainAttributes();
+ addAttr(Attributes.Name.MANIFEST_VERSION, fileNode, attrs);
+ addAttr(Attributes.Name.SIGNATURE_VERSION, fileNode, attrs);
+ addAttr(Attributes.Name.CLASS_PATH, fileNode, attrs);
+ addAttr(Attributes.Name.MAIN_CLASS, fileNode, attrs);
+ addAttr(Attributes.Name.EXTENSION_NAME, fileNode, attrs);
+ addAttr(Attributes.Name.IMPLEMENTATION_VERSION, fileNode,
+ attrs);
+ addAttr(Attributes.Name.IMPLEMENTATION_VENDOR, fileNode,
+ attrs);
+ addAttr(Attributes.Name.IMPLEMENTATION_VENDOR_ID, fileNode,
+ attrs);
+ addAttr(Attributes.Name.SPECIFICATION_TITLE, fileNode,
+ attrs);
+ addAttr(Attributes.Name.SPECIFICATION_VERSION, fileNode,
+ attrs);
+ addAttr(Attributes.Name.SPECIFICATION_VENDOR, fileNode,
+ attrs);
+ addAttr(Attributes.Name.SEALED, fileNode, attrs);
+ } finally {
+ if (manifestBinary != null)
+ manifestBinary.dispose();
+ IOUtils.closeQuietly(bi);
+ IOUtils.closeQuietly(bo);
+ IOUtils.closeQuietly(jarIn);
+ }
+ }
+ return fileNode;