| /* |
| * 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.felix.bundlerepository.impl; |
| |
| import java.io.*; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.text.SimpleDateFormat; |
| import java.util.Date; |
| import java.util.Dictionary; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.jar.Attributes; |
| import java.util.jar.JarFile; |
| import java.util.jar.Manifest; |
| import java.util.zip.GZIPInputStream; |
| import java.util.zip.ZipEntry; |
| import java.util.zip.ZipInputStream; |
| |
| import org.apache.felix.bundlerepository.Capability; |
| import org.apache.felix.bundlerepository.DataModelHelper; |
| import org.apache.felix.bundlerepository.Property; |
| import org.apache.felix.bundlerepository.Repository; |
| import org.apache.felix.bundlerepository.Requirement; |
| import org.apache.felix.bundlerepository.Resource; |
| import org.apache.felix.utils.filter.FilterImpl; |
| import org.apache.felix.utils.manifest.Attribute; |
| import org.apache.felix.utils.manifest.Clause; |
| import org.apache.felix.utils.manifest.Directive; |
| import org.apache.felix.utils.manifest.Parser; |
| import org.apache.felix.utils.version.VersionCleaner; |
| import org.apache.felix.utils.version.VersionRange; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.Constants; |
| import org.osgi.framework.Filter; |
| import org.osgi.framework.InvalidSyntaxException; |
| import org.osgi.framework.Version; |
| |
| public class DataModelHelperImpl implements DataModelHelper |
| { |
| |
| public static final String BUNDLE_LICENSE = "Bundle-License"; |
| public static final String BUNDLE_SOURCE = "Bundle-Source"; |
| |
| public Requirement requirement(String name, String filter) |
| { |
| RequirementImpl req = new RequirementImpl(); |
| req.setName(name); |
| if (filter != null) |
| { |
| req.setFilter(filter); |
| } |
| return req; |
| } |
| |
| public Filter filter(String filter) |
| { |
| try |
| { |
| return FilterImpl.newInstance(filter); |
| } |
| catch (InvalidSyntaxException e) |
| { |
| IllegalArgumentException ex = new IllegalArgumentException(); |
| ex.initCause(e); |
| throw ex; |
| } |
| } |
| |
| public Repository repository(final URL url) throws Exception |
| { |
| InputStream is = null; |
| |
| try |
| { |
| if (url.getPath().endsWith(".zip")) |
| { |
| ZipInputStream zin = new ZipInputStream(FileUtil.openURL(url)); |
| ZipEntry entry = zin.getNextEntry(); |
| while (entry != null) |
| { |
| if (entry.getName().equals("repository.xml") || entry.getName().equals("index.xml")) |
| { |
| is = zin; |
| break; |
| } |
| entry = zin.getNextEntry(); |
| } |
| // as the ZipInputStream is not used further it would not be closed. |
| if (is == null) |
| { |
| try |
| { |
| zin.close(); |
| } |
| catch (IOException ex) |
| { |
| // Not much we can do. |
| } |
| } |
| } |
| else if (url.getPath().endsWith(".gz")) |
| { |
| is = new GZIPInputStream(FileUtil.openURL(url)); |
| } |
| else |
| { |
| is = FileUtil.openURL(url); |
| } |
| |
| if (is != null) |
| { |
| String repositoryUri = url.toExternalForm(); |
| String baseUri; |
| if (repositoryUri.endsWith(".zip")) { |
| baseUri = new StringBuilder("jar:").append(repositoryUri).append("!/").toString(); |
| } else if (repositoryUri.endsWith(".xml")) { |
| baseUri = repositoryUri.substring(0, repositoryUri.lastIndexOf('/') + 1); |
| } else { |
| baseUri = repositoryUri; |
| } |
| RepositoryImpl repository = repository(is, URI.create(baseUri)); |
| repository.setURI(repositoryUri); |
| |
| return repository; |
| } |
| else |
| { |
| // This should not happen. |
| throw new Exception("Unable to get input stream for repository."); |
| } |
| } |
| finally |
| { |
| try |
| { |
| if (is != null) |
| { |
| is.close(); |
| } |
| } |
| catch (IOException ex) |
| { |
| // Not much we can do. |
| } |
| } |
| } |
| |
| public RepositoryImpl repository(InputStream is, URI baseURI) throws Exception |
| { |
| RepositoryParser parser = RepositoryParser.getParser(); |
| RepositoryImpl repository = parser.parseRepository(is, baseURI); |
| |
| return repository; |
| } |
| |
| public Repository repository(Resource[] resources) |
| { |
| return new RepositoryImpl(resources); |
| } |
| |
| public Capability capability(String name, Map properties) |
| { |
| CapabilityImpl cap = new CapabilityImpl(name); |
| for (Iterator it = properties.entrySet().iterator(); it.hasNext();) |
| { |
| Map.Entry e = (Map.Entry) it.next(); |
| cap.addProperty((String) e.getKey(), (String) e.getValue()); |
| } |
| return cap; |
| } |
| |
| public String writeRepository(Repository repository) |
| { |
| try |
| { |
| StringWriter sw = new StringWriter(); |
| writeRepository(repository, sw); |
| return sw.toString(); |
| } |
| catch (IOException e) |
| { |
| IllegalStateException ex = new IllegalStateException(e); |
| ex.initCause(e); |
| throw ex; |
| } |
| } |
| |
| public void writeRepository(Repository repository, Writer writer) throws IOException |
| { |
| XmlWriter w = new XmlWriter(writer); |
| toXml(w, repository); |
| } |
| |
| public String writeResource(Resource resource) |
| { |
| try |
| { |
| StringWriter sw = new StringWriter(); |
| writeResource(resource, sw); |
| return sw.toString(); |
| } |
| catch (IOException e) |
| { |
| IllegalStateException ex = new IllegalStateException(e); |
| ex.initCause(e); |
| throw ex; |
| } |
| } |
| |
| public void writeResource(Resource resource, Writer writer) throws IOException |
| { |
| XmlWriter w = new XmlWriter(writer); |
| toXml(w, resource); |
| } |
| |
| public String writeCapability(Capability capability) |
| { |
| try |
| { |
| StringWriter sw = new StringWriter(); |
| writeCapability(capability, sw); |
| return sw.toString(); |
| } |
| catch (IOException e) |
| { |
| IllegalStateException ex = new IllegalStateException(e); |
| ex.initCause(e); |
| throw ex; |
| } |
| } |
| |
| public void writeCapability(Capability capability, Writer writer) throws IOException |
| { |
| XmlWriter w = new XmlWriter(writer); |
| toXml(w, capability); |
| } |
| |
| public String writeRequirement(Requirement requirement) |
| { |
| try |
| { |
| StringWriter sw = new StringWriter(); |
| writeRequirement(requirement, sw); |
| return sw.toString(); |
| } |
| catch (IOException e) |
| { |
| IllegalStateException ex = new IllegalStateException(e); |
| ex.initCause(e); |
| throw ex; |
| } |
| } |
| |
| public void writeRequirement(Requirement requirement, Writer writer) throws IOException |
| { |
| XmlWriter w = new XmlWriter(writer); |
| toXml(w, requirement); |
| } |
| |
| public String writeProperty(Property property) |
| { |
| try |
| { |
| StringWriter sw = new StringWriter(); |
| writeProperty(property, sw); |
| return sw.toString(); |
| } |
| catch (IOException e) |
| { |
| IllegalStateException ex = new IllegalStateException(e); |
| ex.initCause(e); |
| throw ex; |
| } |
| } |
| |
| public void writeProperty(Property property, Writer writer) throws IOException |
| { |
| XmlWriter w = new XmlWriter(writer); |
| toXml(w, property); |
| } |
| |
| private static void toXml(XmlWriter w, Repository repository) throws IOException |
| { |
| SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmss.SSS"); |
| w.element(RepositoryParser.REPOSITORY) |
| .attribute(RepositoryParser.NAME, repository.getName()) |
| .attribute(RepositoryParser.LASTMODIFIED, format.format(new Date(repository.getLastModified()))); |
| |
| if (repository instanceof RepositoryImpl) |
| { |
| Referral[] referrals = ((RepositoryImpl) repository).getReferrals(); |
| for (int i = 0; referrals != null && i < referrals.length; i++) |
| { |
| w.element(RepositoryParser.REFERRAL) |
| .attribute(RepositoryParser.DEPTH, new Integer(referrals[i].getDepth())) |
| .attribute(RepositoryParser.URL, referrals[i].getUrl()) |
| .end(); |
| } |
| } |
| |
| Resource[] resources = repository.getResources(); |
| for (int i = 0; resources != null && i < resources.length; i++) |
| { |
| toXml(w, resources[i]); |
| } |
| |
| w.end(); |
| } |
| |
| private static void toXml(XmlWriter w, Resource resource) throws IOException |
| { |
| w.element(RepositoryParser.RESOURCE) |
| .attribute(Resource.ID, resource.getId()) |
| .attribute(Resource.SYMBOLIC_NAME, resource.getSymbolicName()) |
| .attribute(Resource.PRESENTATION_NAME, resource.getPresentationName()) |
| .attribute(Resource.URI, getRelativeUri(resource, Resource.URI)) |
| .attribute(Resource.VERSION, resource.getVersion().toString()); |
| |
| w.textElement(Resource.DESCRIPTION, resource.getProperties().get(Resource.DESCRIPTION)) |
| .textElement(Resource.SIZE, resource.getProperties().get(Resource.SIZE)) |
| .textElement(Resource.DOCUMENTATION_URI, getRelativeUri(resource, Resource.DOCUMENTATION_URI)) |
| .textElement(Resource.SOURCE_URI, getRelativeUri(resource, Resource.SOURCE_URI)) |
| .textElement(Resource.JAVADOC_URI, getRelativeUri(resource, Resource.JAVADOC_URI)) |
| .textElement(Resource.LICENSE_URI, getRelativeUri(resource, Resource.LICENSE_URI)); |
| |
| String[] categories = resource.getCategories(); |
| for (int i = 0; categories != null && i < categories.length; i++) |
| { |
| w.element(RepositoryParser.CATEGORY) |
| .attribute(RepositoryParser.ID, categories[i]) |
| .end(); |
| } |
| Capability[] capabilities = resource.getCapabilities(); |
| for (int i = 0; capabilities != null && i < capabilities.length; i++) |
| { |
| toXml(w, capabilities[i]); |
| } |
| Requirement[] requirements = resource.getRequirements(); |
| for (int i = 0; requirements != null && i < requirements.length; i++) |
| { |
| toXml(w, requirements[i]); |
| } |
| w.end(); |
| } |
| |
| private static String getRelativeUri(Resource resource, String name) |
| { |
| String uri = (String) resource.getProperties().get(name); |
| if (resource instanceof ResourceImpl) |
| { |
| try |
| { |
| uri = URI.create(((ResourceImpl) resource).getRepository().getURI()).relativize(URI.create(uri)).toASCIIString(); |
| } |
| catch (Throwable t) |
| { |
| } |
| } |
| return uri; |
| } |
| |
| private static void toXml(XmlWriter w, Capability capability) throws IOException |
| { |
| w.element(RepositoryParser.CAPABILITY) |
| .attribute(RepositoryParser.NAME, capability.getName()); |
| Property[] props = capability.getProperties(); |
| for (int j = 0; props != null && j < props.length; j++) |
| { |
| toXml(w, props[j]); |
| } |
| w.end(); |
| } |
| |
| private static void toXml(XmlWriter w, Property property) throws IOException |
| { |
| w.element(RepositoryParser.P) |
| .attribute(RepositoryParser.N, property.getName()) |
| .attribute(RepositoryParser.T, property.getType()) |
| .attribute(RepositoryParser.V, property.getValue()) |
| .end(); |
| } |
| |
| private static void toXml(XmlWriter w, Requirement requirement) throws IOException |
| { |
| w.element(RepositoryParser.REQUIRE) |
| .attribute(RepositoryParser.NAME, requirement.getName()) |
| .attribute(RepositoryParser.FILTER, requirement.getFilter()) |
| .attribute(RepositoryParser.EXTEND, Boolean.toString(requirement.isExtend())) |
| .attribute(RepositoryParser.MULTIPLE, Boolean.toString(requirement.isMultiple())) |
| .attribute(RepositoryParser.OPTIONAL, Boolean.toString(requirement.isOptional())) |
| .text(requirement.getComment().trim()) |
| .end(); |
| } |
| |
| public Resource createResource(final Bundle bundle) |
| { |
| final Dictionary dict = bundle.getHeaders(); |
| return createResource(new Headers() |
| { |
| public String getHeader(String name) |
| { |
| return (String) dict.get(name); |
| } |
| }); |
| } |
| |
| public Resource createResource(final URL bundleUrl) throws IOException |
| { |
| ResourceImpl resource = createResource(new Headers() |
| { |
| private final Manifest manifest; |
| private Properties localization; |
| { |
| // Do not use a JarInputStream so that we can read the manifest even if it's not |
| // the first entry in the JAR. |
| byte[] man = loadEntry(JarFile.MANIFEST_NAME); |
| if (man == null) |
| { |
| throw new IllegalArgumentException("The specified url is not a valid jar (can't read manifest): " + bundleUrl); |
| } |
| manifest = new Manifest(new ByteArrayInputStream(man)); |
| } |
| public String getHeader(String name) |
| { |
| String value = manifest.getMainAttributes().getValue(name); |
| if (value != null && value.startsWith("%")) |
| { |
| if (localization == null) |
| { |
| try |
| { |
| localization = new Properties(); |
| String path = manifest.getMainAttributes().getValue(Constants.BUNDLE_LOCALIZATION); |
| if (path == null) |
| { |
| path = Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME; |
| } |
| path += ".properties"; |
| byte[] loc = loadEntry(path); |
| if (loc != null) |
| { |
| localization.load(new ByteArrayInputStream(loc)); |
| } |
| } |
| catch (IOException e) |
| { |
| // TODO: ? |
| } |
| } |
| value = value.substring(1); |
| value = localization.getProperty(value, value); |
| } |
| return value; |
| } |
| private byte[] loadEntry(String name) throws IOException |
| { |
| ZipInputStream zis = new ZipInputStream(FileUtil.openURL(bundleUrl)); |
| try |
| { |
| for (ZipEntry e = zis.getNextEntry(); e != null; e = zis.getNextEntry()) |
| { |
| if (name.equalsIgnoreCase(e.getName())) |
| { |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| byte[] buf = new byte[1024]; |
| int n; |
| while ((n = zis.read(buf, 0, buf.length)) > 0) |
| { |
| baos.write(buf, 0, n); |
| } |
| return baos.toByteArray(); |
| } |
| } |
| } |
| finally |
| { |
| zis.close(); |
| } |
| return null; |
| } |
| }); |
| if (resource != null) |
| { |
| if ("file".equals(bundleUrl.getProtocol())) |
| { |
| try { |
| File f = new File(bundleUrl.toURI()); |
| resource.put(Resource.SIZE, Long.toString(f.length()), null); |
| } catch (URISyntaxException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| resource.put(Resource.URI, bundleUrl.toExternalForm(), null); |
| } |
| return resource; |
| } |
| |
| public Resource createResource(final Attributes attributes) |
| { |
| return createResource(new Headers() |
| { |
| public String getHeader(String name) |
| { |
| return attributes.getValue(name); |
| } |
| }); |
| } |
| |
| public ResourceImpl createResource(Headers headers) |
| { |
| String bsn = headers.getHeader(Constants.BUNDLE_SYMBOLICNAME); |
| if (bsn == null) |
| { |
| return null; |
| } |
| ResourceImpl resource = new ResourceImpl(); |
| populate(headers, resource); |
| return resource; |
| } |
| |
| static void populate(Headers headers, ResourceImpl resource) |
| { |
| String bsn = getSymbolicName(headers); |
| String v = getVersion(headers); |
| |
| resource.put(Resource.ID, bsn + "/" + v); |
| resource.put(Resource.SYMBOLIC_NAME, bsn); |
| resource.put(Resource.VERSION, v); |
| if (headers.getHeader(Constants.BUNDLE_NAME) != null) |
| { |
| resource.put(Resource.PRESENTATION_NAME, headers.getHeader(Constants.BUNDLE_NAME)); |
| } |
| if (headers.getHeader(Constants.BUNDLE_DESCRIPTION) != null) |
| { |
| resource.put(Resource.DESCRIPTION, headers.getHeader(Constants.BUNDLE_DESCRIPTION)); |
| } |
| if (headers.getHeader(BUNDLE_LICENSE) != null) |
| { |
| resource.put(Resource.LICENSE_URI, headers.getHeader(BUNDLE_LICENSE)); |
| } |
| if (headers.getHeader(Constants.BUNDLE_COPYRIGHT) != null) |
| { |
| resource.put(Resource.COPYRIGHT, headers.getHeader(Constants.BUNDLE_COPYRIGHT)); |
| } |
| if (headers.getHeader(Constants.BUNDLE_DOCURL) != null) |
| { |
| resource.put(Resource.DOCUMENTATION_URI, headers.getHeader(Constants.BUNDLE_DOCURL)); |
| } |
| if (headers.getHeader(BUNDLE_SOURCE) != null) |
| { |
| resource.put(Resource.SOURCE_URI, headers.getHeader(BUNDLE_SOURCE)); |
| } |
| |
| doCategories(resource, headers); |
| doBundle(resource, headers); |
| doImportExportServices(resource, headers); |
| doFragment(resource, headers); |
| doRequires(resource, headers); |
| doExports(resource, headers); |
| doImports(resource, headers); |
| doExecutionEnvironment(resource, headers); |
| doProvides(resource, headers); |
| } |
| |
| private static void doCategories(ResourceImpl resource, Headers headers) |
| { |
| Clause[] clauses = Parser.parseHeader(headers.getHeader(Constants.BUNDLE_CATEGORY)); |
| for (int i = 0; clauses != null && i < clauses.length; i++) |
| { |
| resource.addCategory(clauses[i].getName()); |
| } |
| } |
| |
| private static void doImportExportServices(ResourceImpl resource, Headers headers) |
| { |
| Clause[] imports = Parser.parseHeader(headers.getHeader(Constants.IMPORT_SERVICE)); |
| for (int i = 0; imports != null && i < imports.length; i++) { |
| RequirementImpl ri = new RequirementImpl(Capability.SERVICE); |
| ri.setFilter(createServiceFilter(imports[i])); |
| ri.addText("Import Service " + imports[i].getName()); |
| |
| String avail = imports[i].getDirective("availability"); |
| String mult = imports[i].getDirective("multiple"); |
| ri.setOptional("optional".equalsIgnoreCase(avail)); |
| ri.setMultiple(!"false".equalsIgnoreCase(mult)); |
| resource.addRequire(ri); |
| } |
| |
| Clause[] exports = Parser.parseHeader(headers.getHeader(Constants.EXPORT_SERVICE)); |
| for (int i = 0; exports != null && i < exports.length; i++) { |
| CapabilityImpl cap = createServiceCapability(exports[i]); |
| resource.addCapability(cap); |
| } |
| } |
| |
| private static String createServiceFilter(Clause clause) { |
| String f = clause.getAttribute("filter"); |
| StringBuffer filter = new StringBuffer(); |
| if (f != null) { |
| filter.append("(&"); |
| } |
| filter.append("("); |
| filter.append(Capability.SERVICE); |
| filter.append("="); |
| filter.append(clause.getName()); |
| filter.append(")"); |
| if (f != null) { |
| if (!f.startsWith("(")) |
| { |
| filter.append("(").append(f).append(")"); |
| } |
| else |
| { |
| filter.append(f); |
| } |
| filter.append(")"); |
| } |
| return filter.toString(); |
| } |
| |
| private static CapabilityImpl createServiceCapability(Clause clause) { |
| CapabilityImpl capability = new CapabilityImpl(Capability.SERVICE); |
| capability.addProperty(Capability.SERVICE, clause.getName()); |
| Attribute[] attributes = clause.getAttributes(); |
| for (int i = 0; attributes != null && i < attributes.length; i++) |
| { |
| capability.addProperty(attributes[i].getName(), attributes[i].getValue()); |
| } |
| return capability; |
| } |
| |
| private static void doFragment(ResourceImpl resource, Headers headers) |
| { |
| // Check if we are a fragment |
| Clause[] clauses = Parser.parseHeader(headers.getHeader(Constants.FRAGMENT_HOST)); |
| if (clauses != null && clauses.length == 1) |
| { |
| // We are a fragment, create a requirement |
| // to our host. |
| RequirementImpl r = new RequirementImpl(Capability.BUNDLE); |
| StringBuffer sb = new StringBuffer(); |
| sb.append("(&(symbolicname="); |
| sb.append(clauses[0].getName()); |
| sb.append(")"); |
| appendVersion(sb, VersionRange.parseVersionRange(clauses[0].getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE))); |
| sb.append(")"); |
| r.setFilter(sb.toString()); |
| r.addText("Required Host " + clauses[0].getName()); |
| r.setExtend(true); |
| r.setOptional(false); |
| r.setMultiple(false); |
| resource.addRequire(r); |
| |
| // And insert a capability that we are available |
| // as a fragment. ### Do we need that with extend? |
| CapabilityImpl capability = new CapabilityImpl(Capability.FRAGMENT); |
| capability.addProperty("host", clauses[0].getName()); |
| capability.addProperty("version", Property.VERSION, getVersion(clauses[0])); |
| resource.addCapability(capability); |
| } |
| } |
| |
| private static void doRequires(ResourceImpl resource, Headers headers) |
| { |
| Clause[] clauses = Parser.parseHeader(headers.getHeader(Constants.REQUIRE_BUNDLE)); |
| for (int i = 0; clauses != null && i < clauses.length; i++) { |
| RequirementImpl r = new RequirementImpl(Capability.BUNDLE); |
| |
| VersionRange v = VersionRange.parseVersionRange(clauses[i].getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE)); |
| |
| StringBuffer sb = new StringBuffer(); |
| sb.append("(&(symbolicname="); |
| sb.append(clauses[i].getName()); |
| sb.append(")"); |
| appendVersion(sb, v); |
| sb.append(")"); |
| r.setFilter(sb.toString()); |
| |
| r.addText("Require Bundle " + clauses[i].getName() + "; " + v); |
| r.setOptional(Constants.RESOLUTION_OPTIONAL.equalsIgnoreCase(clauses[i].getDirective(Constants.RESOLUTION_DIRECTIVE))); |
| resource.addRequire(r); |
| } |
| } |
| |
| private static void doBundle(ResourceImpl resource, Headers headers) { |
| CapabilityImpl capability = new CapabilityImpl(Capability.BUNDLE); |
| capability.addProperty(Resource.SYMBOLIC_NAME, getSymbolicName(headers)); |
| if (headers.getHeader(Constants.BUNDLE_NAME) != null) |
| { |
| capability.addProperty(Resource.PRESENTATION_NAME, headers.getHeader(Constants.BUNDLE_NAME)); |
| } |
| capability.addProperty(Resource.VERSION, Property.VERSION, getVersion(headers)); |
| capability.addProperty(Resource.MANIFEST_VERSION, getManifestVersion(headers)); |
| resource.addCapability(capability); |
| } |
| |
| private static void doExports(ResourceImpl resource, Headers headers) |
| { |
| Clause[] clauses = Parser.parseHeader(headers.getHeader(Constants.EXPORT_PACKAGE)); |
| for (int i = 0; clauses != null && i < clauses.length; i++) |
| { |
| CapabilityImpl capability = createCapability(Capability.PACKAGE, clauses[i]); |
| resource.addCapability(capability); |
| } |
| } |
| |
| private static void doProvides(ResourceImpl resource, Headers headers) { |
| Clause[] clauses = Parser.parseHeader(headers.getHeader(Constants.PROVIDE_CAPABILITY)); |
| |
| if (clauses != null) { |
| for (Clause clause : clauses) { |
| CapabilityImpl capability = createCapability(clause.getName(), clause); |
| resource.addCapability(capability); |
| } |
| } |
| } |
| |
| private static CapabilityImpl createCapability(String name, Clause clause) |
| { |
| CapabilityImpl capability = new CapabilityImpl(NamespaceTranslator.getFelixNamespace(name)); |
| capability.addProperty(name, clause.getName()); |
| capability.addProperty(Resource.VERSION, Property.VERSION, getVersion(clause)); |
| Attribute[] attributes = clause.getAttributes(); |
| for (int i = 0; attributes != null && i < attributes.length; i++) |
| { |
| String key = attributes[i].getName(); |
| if (key.equalsIgnoreCase(Constants.PACKAGE_SPECIFICATION_VERSION) || key.equalsIgnoreCase(Constants.VERSION_ATTRIBUTE) || key.equalsIgnoreCase("version:Version")) |
| { |
| continue; |
| } |
| else |
| { |
| String value = attributes[i].getValue(); |
| capability.addProperty(key, value); |
| } |
| } |
| Directive[] directives = clause.getDirectives(); |
| for (int i = 0; directives != null && i < directives.length; i++) |
| { |
| String key = directives[i].getName(); |
| String value = directives[i].getValue(); |
| capability.addProperty(key + ":", value); |
| } |
| return capability; |
| } |
| |
| private static void doImports(ResourceImpl resource, Headers headers) |
| { |
| Clause[] clauses = Parser.parseHeader(headers.getHeader(Constants.IMPORT_PACKAGE)); |
| for (int i = 0; clauses != null && i < clauses.length; i++) |
| { |
| RequirementImpl requirement = new RequirementImpl(Capability.PACKAGE); |
| |
| createImportFilter(requirement, Capability.PACKAGE, clauses[i]); |
| requirement.addText("Import package " + clauses[i]); |
| requirement.setOptional(Constants.RESOLUTION_OPTIONAL.equalsIgnoreCase(clauses[i].getDirective(Constants.RESOLUTION_DIRECTIVE))); |
| resource.addRequire(requirement); |
| } |
| } |
| |
| private static void createImportFilter(RequirementImpl requirement, String name, Clause clause) |
| { |
| StringBuffer filter = new StringBuffer(); |
| filter.append("(&("); |
| filter.append(name); |
| filter.append("="); |
| filter.append(clause.getName()); |
| filter.append(")"); |
| appendVersion(filter, getVersionRange(clause)); |
| Attribute[] attributes = clause.getAttributes(); |
| Set attrs = doImportPackageAttributes(requirement, filter, attributes); |
| |
| // The next code is using the subset operator |
| // to check mandatory attributes, it seems to be |
| // impossible to rewrite. It must assert that whateber |
| // is in mandatory: must be in any of the attributes. |
| // This is a fundamental shortcoming of the filter language. |
| if (attrs.size() > 0) |
| { |
| String del = ""; |
| filter.append("(mandatory:<*"); |
| for (Iterator i = attrs.iterator(); i.hasNext();) |
| { |
| filter.append(del); |
| filter.append(i.next()); |
| del = ", "; |
| } |
| filter.append(")"); |
| } |
| filter.append(")"); |
| requirement.setFilter(filter.toString()); |
| } |
| |
| private static Set doImportPackageAttributes(RequirementImpl requirement, StringBuffer filter, Attribute[] attributes) |
| { |
| HashSet set = new HashSet(); |
| for (int i = 0; attributes != null && i < attributes.length; i++) |
| { |
| String name = attributes[i].getName(); |
| String value = attributes[i].getValue(); |
| if (name.equalsIgnoreCase(Constants.PACKAGE_SPECIFICATION_VERSION) || name.equalsIgnoreCase(Constants.VERSION_ATTRIBUTE)) |
| { |
| continue; |
| } |
| else if (name.equalsIgnoreCase(Constants.RESOLUTION_DIRECTIVE + ":")) |
| { |
| requirement.setOptional(Constants.RESOLUTION_OPTIONAL.equalsIgnoreCase(value)); |
| } |
| if (name.endsWith(":")) |
| { |
| // Ignore |
| } |
| else |
| { |
| filter.append("("); |
| filter.append(name); |
| filter.append("="); |
| filter.append(value); |
| filter.append(")"); |
| set.add(name); |
| } |
| } |
| return set; |
| } |
| |
| private static void doExecutionEnvironment(ResourceImpl resource, Headers headers) |
| { |
| Clause[] clauses = Parser.parseHeader(headers.getHeader(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT)); |
| if (clauses != null && clauses.length > 0) |
| { |
| StringBuffer sb = new StringBuffer(); |
| sb.append("(|"); |
| for (int i = 0; i < clauses.length; i++) |
| { |
| sb.append("("); |
| sb.append(Capability.EXECUTIONENVIRONMENT); |
| sb.append("="); |
| sb.append(clauses[i].getName()); |
| sb.append(")"); |
| } |
| sb.append(")"); |
| RequirementImpl req = new RequirementImpl(Capability.EXECUTIONENVIRONMENT); |
| req.setFilter(sb.toString()); |
| req.addText("Execution Environment " + sb.toString()); |
| resource.addRequire(req); |
| } |
| } |
| |
| private static String getVersion(Clause clause) |
| { |
| String v = clause.getAttribute(Constants.VERSION_ATTRIBUTE); |
| if (v == null) |
| { |
| v = clause.getAttribute(Constants.PACKAGE_SPECIFICATION_VERSION); |
| } |
| if (v == null) |
| { |
| v = clause.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE); |
| } |
| if (v == null) |
| { |
| v = clause.getAttribute("version:Version"); |
| } |
| |
| return VersionCleaner.clean(v); |
| } |
| |
| private static VersionRange getVersionRange(Clause clause) |
| { |
| String v = clause.getAttribute(Constants.VERSION_ATTRIBUTE); |
| if (v == null) |
| { |
| v = clause.getAttribute(Constants.PACKAGE_SPECIFICATION_VERSION); |
| } |
| if (v == null) |
| { |
| v = clause.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE); |
| } |
| return VersionRange.parseVersionRange(v); |
| } |
| |
| private static String getSymbolicName(Headers headers) |
| { |
| String bsn = headers.getHeader(Constants.BUNDLE_SYMBOLICNAME); |
| if (bsn == null) |
| { |
| bsn = headers.getHeader(Constants.BUNDLE_NAME); |
| if (bsn == null) |
| { |
| bsn = "Untitled-" + headers.hashCode(); |
| } |
| } |
| Clause[] clauses = Parser.parseHeader(bsn); |
| return clauses[0].getName(); |
| } |
| |
| private static String getVersion(Headers headers) |
| { |
| String v = headers.getHeader(Constants.BUNDLE_VERSION); |
| return VersionCleaner.clean(v); |
| } |
| |
| private static String getManifestVersion(Headers headers) |
| { |
| String v = headers.getHeader(Constants.BUNDLE_MANIFESTVERSION); |
| if (v == null) |
| { |
| v = "1"; |
| } |
| return v; |
| } |
| |
| private static void appendVersion(StringBuffer filter, VersionRange version) |
| { |
| if (version != null) |
| { |
| if ( !version.isOpenFloor() ) |
| { |
| if ( !Version.emptyVersion.equals(version.getFloor()) ) |
| { |
| filter.append("("); |
| filter.append(Constants.VERSION_ATTRIBUTE); |
| filter.append(">="); |
| filter.append(version.getFloor()); |
| filter.append(")"); |
| } |
| } |
| else |
| { |
| filter.append("(!("); |
| filter.append(Constants.VERSION_ATTRIBUTE); |
| filter.append("<="); |
| filter.append(version.getFloor()); |
| filter.append("))"); |
| } |
| |
| if (!VersionRange.INFINITE_VERSION.equals(version.getCeiling())) |
| { |
| if ( !version.isOpenCeiling() ) |
| { |
| filter.append("("); |
| filter.append(Constants.VERSION_ATTRIBUTE); |
| filter.append("<="); |
| filter.append(version.getCeiling()); |
| filter.append(")"); |
| } |
| else |
| { |
| filter.append("(!("); |
| filter.append(Constants.VERSION_ATTRIBUTE); |
| filter.append(">="); |
| filter.append(version.getCeiling()); |
| filter.append("))"); |
| } |
| } |
| } |
| } |
| |
| interface Headers |
| { |
| String getHeader(String name); |
| } |
| |
| public Repository readRepository(String xml) throws Exception |
| { |
| try |
| { |
| return readRepository(new StringReader(xml)); |
| } |
| catch (IOException e) |
| { |
| IllegalStateException ex = new IllegalStateException(e); |
| ex.initCause(e); |
| throw ex; |
| } |
| } |
| |
| public Repository readRepository(Reader reader) throws Exception |
| { |
| return RepositoryParser.getParser().parseRepository(reader); |
| } |
| |
| public Resource readResource(String xml) throws Exception |
| { |
| try |
| { |
| return readResource(new StringReader(xml)); |
| } |
| catch (IOException e) |
| { |
| IllegalStateException ex = new IllegalStateException(e); |
| ex.initCause(e); |
| throw ex; |
| } |
| } |
| |
| public Resource readResource(Reader reader) throws Exception |
| { |
| return RepositoryParser.getParser().parseResource(reader); |
| } |
| |
| public Capability readCapability(String xml) throws Exception |
| { |
| try |
| { |
| return readCapability(new StringReader(xml)); |
| } |
| catch (IOException e) |
| { |
| IllegalStateException ex = new IllegalStateException(e); |
| ex.initCause(e); |
| throw ex; |
| } |
| } |
| |
| public Capability readCapability(Reader reader) throws Exception |
| { |
| return RepositoryParser.getParser().parseCapability(reader); |
| } |
| |
| public Requirement readRequirement(String xml) throws Exception |
| { |
| try |
| { |
| return readRequirement(new StringReader(xml)); |
| } |
| catch (IOException e) |
| { |
| IllegalStateException ex = new IllegalStateException(e); |
| ex.initCause(e); |
| throw ex; |
| } |
| } |
| |
| public Requirement readRequirement(Reader reader) throws Exception |
| { |
| return RepositoryParser.getParser().parseRequirement(reader); |
| } |
| |
| public Property readProperty(String xml) throws Exception |
| { |
| try |
| { |
| return readProperty(new StringReader(xml)); |
| } |
| catch (IOException e) |
| { |
| IllegalStateException ex = new IllegalStateException(e); |
| ex.initCause(e); |
| throw ex; |
| } |
| } |
| |
| public Property readProperty(Reader reader) throws Exception |
| { |
| return RepositoryParser.getParser().parseProperty(reader); |
| } |
| } |