/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.aries.application.resolver.obr.impl;
import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.aries.application.management.ResolverException;
import org.apache.aries.application.management.spi.repository.RepositoryGenerator;
import org.apache.aries.application.management.spi.runtime.LocalPlatform;
import org.apache.aries.application.modelling.ModelledResource;
import org.apache.aries.application.modelling.ModelledResourceManager;
import org.apache.aries.application.resolver.obr.ext.BundleResource;
import org.apache.aries.application.resolver.obr.ext.BundleResourceTransformer;
import org.apache.aries.util.filesystem.FileSystem;
import org.apache.aries.util.filesystem.FileUtils;
import org.apache.aries.util.filesystem.IDirectory;
import org.apache.aries.util.io.IOUtils;
import org.apache.felix.bundlerepository.Capability;
import org.apache.felix.bundlerepository.Property;
import org.apache.felix.bundlerepository.RepositoryAdmin;
import org.apache.felix.bundlerepository.Requirement;
import org.apache.felix.bundlerepository.Resource;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public final class RepositoryGeneratorImpl implements RepositoryGenerator
{
private RepositoryAdmin repositoryAdmin;
private ModelledResourceManager modelledResourceManager;
private LocalPlatform tempDir;
private static Logger logger = LoggerFactory.getLogger(RepositoryGeneratorImpl.class);
private static Collection<BundleResourceTransformer> bundleResourceTransformers = new ArrayList<BundleResourceTransformer>();
private static final String MANDATORY_DIRECTIVE = Constants.MANDATORY_DIRECTIVE + ":";
public void setModelledResourceManager( ModelledResourceManager modelledResourceManager) {
this.modelledResourceManager = modelledResourceManager;
}
public void setTempDir(LocalPlatform tempDir) {
this.tempDir = tempDir;
}
public void setBundleResourceTransformers (List<BundleResourceTransformer> brts) {
bundleResourceTransformers = brts;
}
public RepositoryGeneratorImpl(RepositoryAdmin repositoryAdmin) {
this.repositoryAdmin = repositoryAdmin;
}
private static void addProperty(Document doc, Element capability, String name,
String value, String type)
{
logger.debug(LOG_ENTRY, "addProperty", new Object[]{doc, capability, name, value, type});
Element p = doc.createElement("p");
p.setAttribute("n", name);
p.setAttribute("v", value);
if (type != null) p.setAttribute("t", type);
capability.appendChild(p);
logger.debug(LOG_ENTRY, "addProperty", new Object[]{});
}
/**
* Write out the resource element
*
* @param r
* resource
* @param writer
* buffer writer
* @throws IOException
*/
private static void writeResource(Resource r, String uri, Document doc, Element root) throws IOException
{
logger.debug(LOG_ENTRY, "writeResource", new Object[]{r, uri, doc, root});
Element resource = doc.createElement("resource");
resource.setAttribute(Resource.VERSION, r.getVersion().toString());
resource.setAttribute("uri", r.getURI());
resource.setAttribute(Resource.SYMBOLIC_NAME, r.getSymbolicName());
resource.setAttribute(Resource.ID, r.getSymbolicName() + "/" + r.getVersion());
resource.setAttribute(Resource.PRESENTATION_NAME, r.getPresentationName());
root.appendChild(resource);
for (Capability c : r.getCapabilities())
writeCapability(c, doc, resource);
for (Requirement req : r.getRequirements()) {
writeRequirement(req, doc, resource);
}
logger.debug(LOG_EXIT, "writeResource");
}
/**
* Write out the capability
*
* @param c capability
* @param writer buffer writer
* @throws IOException
*/
private static void writeCapability(Capability c, Document doc, Element resource) throws IOException
{
logger.debug(LOG_ENTRY, "writeCapability", new Object[]{c, doc, resource});
Element capability = doc.createElement("capability");
capability.setAttribute("name", c.getName());
resource.appendChild(capability);
Property[] props = c.getProperties();
for (Property entry : props) {
String name = (String) entry.getName();
String objectAttrs = entry.getValue();
String type = (entry.getType() == null) ? getType(name) : entry.getType();
// remove the beginning " and tailing "
if (objectAttrs.startsWith("\"") && objectAttrs.endsWith("\""))
objectAttrs = objectAttrs.substring(1, objectAttrs.length() - 1);
addProperty(doc, capability, name, objectAttrs, type);
}
logger.debug(LOG_EXIT, "writeCapability");
}
/**
* write the requirement
*
* @param req
* requirement
* @param writer
* buffer writer
* @throws IOException
*/
private static void writeRequirement(Requirement req, Document doc, Element resource) throws IOException
{
logger.debug(LOG_ENTRY, "writeRequirement", new Object[]{req, doc, resource});
Element requirement = doc.createElement("require");
requirement.setAttribute("name", req.getName());
requirement.setAttribute("extend", String.valueOf(req.isExtend()));
requirement.setAttribute("multiple", String.valueOf(req.isMultiple()));
requirement.setAttribute("optional", String.valueOf(req.isOptional()));
requirement.setAttribute("filter", req.getFilter());
requirement.setTextContent(req.getComment());
resource.appendChild(requirement);
logger.debug(LOG_EXIT, "writeRequirement");
}
public void generateRepository(String repositoryName,
Collection<? extends ModelledResource> byValueBundles, OutputStream os)
throws ResolverException, IOException
{
logger.debug(LOG_ENTRY, "generateRepository", new Object[]{repositoryName, byValueBundles, os});
generateRepository(repositoryAdmin, repositoryName, byValueBundles, os);
logger.debug(LOG_EXIT, "generateRepository");
}
public static void generateRepository (RepositoryAdmin repositoryAdmin, String repositoryName,
Collection<? extends ModelledResource> byValueBundles, OutputStream os)
throws ResolverException, IOException {
logger.debug(LOG_ENTRY, "generateRepository", new Object[]{repositoryAdmin, repositoryName, byValueBundles, os});
Document doc;
try {
doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
} catch (ParserConfigurationException pce) {
throw new ResolverException(pce);
}
Element root = doc.createElement("repository");
root.setAttribute("name", repositoryName);
doc.appendChild(root);
for (ModelledResource mr : byValueBundles) {
BundleResource bundleResource = new BundleResource(mr, repositoryAdmin);
if (bundleResourceTransformers.size() > 0) {
for (BundleResourceTransformer brt : bundleResourceTransformers) {
bundleResource = brt.transform (bundleResource);
}
}
writeResource (bundleResource, mr.getLocation(), doc, root);
}
try {
Transformer trans = TransformerFactory.newInstance().newTransformer();
trans.setOutputProperty(OutputKeys.INDENT, "yes");
trans.transform(new DOMSource(doc), new StreamResult(os));
} catch (TransformerException te) {
logger.debug(LOG_EXIT, "generateRepository", te);
throw new ResolverException(te);
}
logger.debug(LOG_EXIT, "generateRepository");
}
private static String getType(String name) {
logger.debug(LOG_ENTRY, "getType", new Object[]{name});
String type = null;
if (Constants.VERSION_ATTRIBUTE.equals(name) || (Constants.BUNDLE_VERSION_ATTRIBUTE.equals(name))) {
type = "version";
} else if (Constants.OBJECTCLASS.equals(name) || MANDATORY_DIRECTIVE.equals(name))
type = "set";
logger.debug(LOG_EXIT, "getType", new Object[]{type});
return type;
}
public void generateRepository(String[] source, OutputStream fout) throws IOException{
logger.debug(LOG_ENTRY, "generateRepository", new Object[]{source, fout});
List<URI> jarFiles = new ArrayList<URI>();
InputStream in = null;
OutputStream out = null;
File wstemp = null;
Set<ModelledResource> mrs = new HashSet<ModelledResource>();
if (source != null) {
try {
for (String urlString : source) {
// for each entry, we need to find out whether it is in local file system. If yes, we would like to
// scan the bundles recursively under that directory
URI entry;
try {
File f = new File(urlString);
if (f.exists()) {
entry = f.toURI();
} else {
entry = new URI(urlString);
}
if ("file".equals(entry.toURL().getProtocol())) {
jarFiles.addAll(FileUtils.getBundlesRecursive(entry));
} else {
jarFiles.add(entry);
}
} catch (URISyntaxException use) {
throw new IOException(urlString + " is not a valide uri.");
}
}
for (URI jarFileURI : jarFiles) {
String uriString = jarFileURI.toString();
File f = null;
if ("file".equals(jarFileURI.toURL().getProtocol())) {
f = new File(jarFileURI);
} else {
int lastIndexOfSlash = uriString.lastIndexOf("/");
String fileName = uriString.substring(lastIndexOfSlash + 1);
//we need to download this jar/war to wstemp and work on it
URLConnection jarConn = jarFileURI.toURL().openConnection();
in = jarConn.getInputStream();
if (wstemp == null) {
wstemp = new File(tempDir.getTemporaryDirectory(), "generateRepositoryXML_" + System.currentTimeMillis());
boolean created = wstemp.mkdirs();
if (created) {
logger.debug("The temp directory was created successfully.");
} else {
logger.debug("The temp directory was NOT created.");
}
}
//Let's open the stream to download the bundles from remote
f = new File(wstemp, fileName);
out = new FileOutputStream(f);
IOUtils.copy(in, out);
}
IDirectory jarDir = FileSystem.getFSRoot(f);
mrs.add(modelledResourceManager.getModelledResource(uriString, jarDir));
}
generateRepository("Resource Repository", mrs, fout);
} catch (Exception e) {
logger.debug(LOG_EXIT, "generateRepository");
throw new IOException(e);
} finally {
IOUtils.close(in);
IOUtils.close(out);
if (wstemp != null) {
IOUtils.deleteRecursive(wstemp);
}
}
} else {
logger.debug("The URL list is empty");
}
logger.debug(LOG_EXIT, "generateRepository");
}
}