/* * 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.apache.aries.subsystem.itests.util; import java.io.File; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.apache.aries.application.Content; import org.apache.aries.application.management.BundleInfo; import org.apache.aries.subsystem.util.felix.FelixResourceAdapter; import org.apache.aries.subsystem.util.felix.OsgiResourceAdapter; import org.apache.felix.bundlerepository.Reason; import org.apache.felix.bundlerepository.Repository; import org.apache.felix.bundlerepository.RepositoryAdmin; import org.apache.felix.bundlerepository.Resolver; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.framework.Version; import org.osgi.framework.namespace.IdentityNamespace; import org.osgi.resource.Resource; import org.osgi.service.subsystem.SubsystemException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; public class RepositoryGenerator { private static final Logger LOGGER = LoggerFactory .getLogger(RepositoryGenerator.class); private static final String REPOSITORY_FILE = "repository-subsystems.xml"; final private BundleContext context; private RepositoryAdmin repositoryAdmin; private static boolean generated = false; private String obrPath; public RepositoryGenerator(BundleContext context) { this.context = context; } public RepositoryGenerator(BundleContext context, String obrPath) { this.context = context; this.obrPath = obrPath; } public void generateOBR() { if (generated) { return; } synchronized(this) { if (obrPath == null) { // set to a default obr file which is local m2 repo String file = System.getProperty("user.home") + "/.m2/repository/"; if (new File(file).exists()) { obrPath = file; } } // if repository.xml already exists, no need to generate it if (new File(obrPath + REPOSITORY_FILE).exists()) { registerOBR(); generated = true; return; } File rootFile = new File(obrPath); if (!rootFile.exists() || !rootFile.isDirectory()) { throw new IllegalArgumentException("obr path " + obrPath + " is not valid"); } Manve2Repository repo = new Manve2Repository(rootFile); SortedSet<String> ss = repo.listFiles(); Set<BundleInfo> infos = new HashSet<BundleInfo>(); for (String s : ss) { BundleInfo info = new BundleInfoImpl(s); infos.add(info); } Document doc; try { doc = RepositoryDescriptorGenerator.generateRepositoryDescriptor( "Subsystem Repository description", infos); FileOutputStream fout = new FileOutputStream(obrPath + REPOSITORY_FILE); TransformerFactory.newInstance().newTransformer().transform( new DOMSource(doc), new StreamResult(fout)); fout.close(); TransformerFactory.newInstance().newTransformer().transform( new DOMSource(doc), new StreamResult(System.out)); } catch (Exception e) { LOGGER.error("Exception occurred when generate obr", e); e.printStackTrace(); } registerOBR(); generated = true; } } private void registerOBR() { // set repositoryAdmin ServiceReference ref = context.getServiceReference(RepositoryAdmin.class); if (ref != null) { this.repositoryAdmin = (RepositoryAdmin) context.getService(ref); try { this.repositoryAdmin.addRepository(new File(obrPath + REPOSITORY_FILE).toURI().toURL()); } catch (Exception e) { LOGGER.warn("Exception occurred when register obr", e); e.printStackTrace(); } this.context.ungetService(ref); } else { LOGGER.error("Unable to register OBR as RepositoryAdmin service is not available"); } } /** * the format of resource is like bundlesymbolicname;version=1.0.0, for example com.ibm.ws.eba.example.blog.api;version=1.0.0, */ @SuppressWarnings({ "rawtypes", "unused" }) public Resource find(String resource) throws SubsystemException { generateOBR(); Content content = new ContentImpl(resource); String symbolicName = content.getContentName(); // this version could possibly be a range String version = content.getVersion().toString(); StringBuilder filterString = new StringBuilder(); filterString.append("(&(name" + "=" + symbolicName + "))"); filterString.append("(version" + "=" + version + "))"); //org.apache.felix.bundlerepository.Resource[] res = this.repositoryAdmin.discoverResources(filterString.toString()); Repository[] repos = this.repositoryAdmin.listRepositories(); org.apache.felix.bundlerepository.Resource res = null; for (Repository repo : repos) { org.apache.felix.bundlerepository.Resource[] resources = repo.getResources(); for (int i = 0; i < resources.length; i++) { if (resources[i].getSymbolicName().equals(symbolicName)) { if (resources[i].getVersion().compareTo(new Version(version)) == 0) { res = resources[i]; break; } } } } if (res == null) { // throw new SubsystemException("unable to find the resource " + resource); return null; } Map props = res.getProperties(); Object type = props.get(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE); return new FelixResourceAdapter(res); } public List<Resource> resolve(List<Resource> subsystemContent, List<Resource> subsystemResources) throws SubsystemException { generateOBR(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Attempt to resolve subsystem content {} subsystem resource {}", subsystemContent.toString(), subsystemResources.toString()); } Resolver obrResolver = this.repositoryAdmin.resolver(); // add subsystem content to the resolver for (Resource res : subsystemContent) { // org.apache.felix.bundlerepository.Resource obrRes = findOBRResource(res); // obrResolver.add(obrRes); obrResolver.add(new OsgiResourceAdapter(res)); } // add subsystem resource to the resolver for (Resource res : subsystemResources) { // org.apache.felix.bundlerepository.Resource obrRes = findOBRResource(res); // obrResolver.add(obrRes); obrResolver.add(new OsgiResourceAdapter(res)); } // Question: do we need to create the repository.xml for the subsystem and add the repo to RepoAdmin? List<Resource> resources = new ArrayList<Resource>(); if (obrResolver.resolve()) { for (org.apache.felix.bundlerepository.Resource res : obrResolver.getRequiredResources()) { // resources.add(toResource(res)); resources.add(new FelixResourceAdapter(res)); } // Question: should we handle optional resource differently? for (org.apache.felix.bundlerepository.Resource res : obrResolver.getOptionalResources()) { // resources.add(toResource(res)); resources.add(new FelixResourceAdapter(res)); } } else { // log the unsatisfied requirement Reason[] reasons = obrResolver.getUnsatisfiedRequirements(); StringBuilder builder = new StringBuilder("Failed to resolve subsystem").append(System.getProperty("line.separator")); for (Reason reason : reasons) { LOGGER.warn("Unable to resolve subsystem content {} subsystem resource {} because of unsatisfied requirement {}", new Object[] {subsystemContent.toString(), subsystemResources.toString(), reason.getRequirement().getName()}); builder .append("resource = ") .append(reason.getResource().getSymbolicName()) .append(", requirement = ") .append(reason.getRequirement().getName()) .append(System.getProperty("line.separator")); } throw new SubsystemException(builder.toString()); } return resources; } }