| /* |
| * 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 |
| * |
| * https://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.ivy.osgi.obr.xml; |
| |
| import java.io.OutputStream; |
| import java.text.ParseException; |
| import java.util.Set; |
| |
| import javax.xml.transform.OutputKeys; |
| import javax.xml.transform.TransformerConfigurationException; |
| import javax.xml.transform.sax.TransformerHandler; |
| import javax.xml.transform.stream.StreamResult; |
| |
| import org.apache.ivy.core.IvyContext; |
| import org.apache.ivy.osgi.core.BundleArtifact; |
| import org.apache.ivy.osgi.core.BundleCapability; |
| import org.apache.ivy.osgi.core.BundleInfo; |
| import org.apache.ivy.osgi.core.BundleRequirement; |
| import org.apache.ivy.osgi.core.ExportPackage; |
| import org.apache.ivy.osgi.core.ManifestParser; |
| import org.apache.ivy.osgi.obr.xml.OBRXMLParser.CapabilityHandler; |
| import org.apache.ivy.osgi.obr.xml.OBRXMLParser.CapabilityPropertyHandler; |
| import org.apache.ivy.osgi.obr.xml.OBRXMLParser.RepositoryHandler; |
| import org.apache.ivy.osgi.obr.xml.OBRXMLParser.RequireHandler; |
| import org.apache.ivy.osgi.obr.xml.OBRXMLParser.ResourceHandler; |
| import org.apache.ivy.osgi.obr.xml.OBRXMLParser.ResourceSourceHandler; |
| import org.apache.ivy.osgi.repo.ManifestAndLocation; |
| import org.apache.ivy.osgi.util.Version; |
| import org.apache.ivy.osgi.util.VersionRange; |
| import org.apache.ivy.util.Message; |
| import org.apache.ivy.util.XMLHelper; |
| import org.xml.sax.ContentHandler; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.helpers.AttributesImpl; |
| |
| public class OBRXMLWriter { |
| |
| public static ContentHandler newHandler(OutputStream out, String encoding, boolean indent) |
| throws TransformerConfigurationException { |
| TransformerHandler hd = XMLHelper.getTransformerHandler(); |
| hd.getTransformer().setOutputProperty(OutputKeys.ENCODING, encoding); |
| hd.getTransformer().setOutputProperty(OutputKeys.INDENT, indent ? "yes" : "no"); |
| StreamResult stream = new StreamResult(out); |
| hd.setResult(stream); |
| return hd; |
| } |
| |
| public static void writeManifests(Iterable<ManifestAndLocation> manifestAndLocations, |
| ContentHandler handler, boolean quiet) throws SAXException { |
| int level = quiet ? Message.MSG_DEBUG : Message.MSG_WARN; |
| handler.startDocument(); |
| AttributesImpl atts = new AttributesImpl(); |
| handler.startElement("", RepositoryHandler.REPOSITORY, RepositoryHandler.REPOSITORY, atts); |
| int nbOk = 0; |
| int nbRejected = 0; |
| for (ManifestAndLocation manifestAndLocation : manifestAndLocations) { |
| BundleInfo bundleInfo; |
| try { |
| bundleInfo = ManifestParser.parseManifest(manifestAndLocation.getManifest()); |
| bundleInfo |
| .addArtifact(new BundleArtifact(false, manifestAndLocation.getUri(), null)); |
| if (manifestAndLocation.getSourceURI() != null) { |
| bundleInfo.addArtifact(new BundleArtifact(true, manifestAndLocation |
| .getSourceURI(), null)); |
| } |
| nbOk++; |
| } catch (ParseException e) { |
| nbRejected++; |
| IvyContext |
| .getContext() |
| .getMessageLogger() |
| .log("Rejected " + manifestAndLocation.getUri() + ": " + e.getMessage(), |
| level); |
| continue; |
| } |
| saxBundleInfo(bundleInfo, handler); |
| } |
| handler.endElement("", RepositoryHandler.REPOSITORY, RepositoryHandler.REPOSITORY); |
| handler.endDocument(); |
| Message.info(nbOk + " bundle" + (nbOk > 1 ? "s" : "") + " added, " + nbRejected + " bundle" |
| + (nbRejected > 1 ? "s" : "") + " rejected."); |
| } |
| |
| public static void writeBundles(Iterable<BundleInfo> bundleInfos, ContentHandler handler) |
| throws SAXException { |
| handler.startDocument(); |
| AttributesImpl atts = new AttributesImpl(); |
| handler.startElement("", RepositoryHandler.REPOSITORY, RepositoryHandler.REPOSITORY, atts); |
| for (BundleInfo bundleInfo : bundleInfos) { |
| saxBundleInfo(bundleInfo, handler); |
| } |
| handler.endElement("", RepositoryHandler.REPOSITORY, RepositoryHandler.REPOSITORY); |
| handler.endDocument(); |
| } |
| |
| private static void saxBundleInfo(BundleInfo bundleInfo, ContentHandler handler) |
| throws SAXException { |
| AttributesImpl atts = new AttributesImpl(); |
| addAttr(atts, ResourceHandler.SYMBOLIC_NAME, bundleInfo.getSymbolicName()); |
| addAttr(atts, ResourceHandler.VERSION, bundleInfo.getRawVersion()); |
| for (BundleArtifact artifact : bundleInfo.getArtifacts()) { |
| if (!artifact.isSource()) { |
| addAttr(atts, ResourceHandler.URI, bundleInfo.getArtifacts().get(0).getUri() |
| .toString()); |
| break; |
| } |
| } |
| handler.startElement("", ResourceHandler.RESOURCE, ResourceHandler.RESOURCE, atts); |
| for (BundleArtifact artifact : bundleInfo.getArtifacts()) { |
| if (artifact.isSource()) { |
| startElement(handler, ResourceSourceHandler.SOURCE); |
| characters(handler, artifact.getUri().toString()); |
| endElement(handler, ResourceSourceHandler.SOURCE); |
| break; |
| } |
| } |
| for (BundleCapability capability : bundleInfo.getCapabilities()) { |
| saxCapability(capability, handler); |
| } |
| for (BundleRequirement requirement : bundleInfo.getRequirements()) { |
| saxRequirement(requirement, handler); |
| } |
| handler.endElement("", ResourceHandler.RESOURCE, ResourceHandler.RESOURCE); |
| handler.characters("\n".toCharArray(), 0, 1); |
| } |
| |
| private static void saxCapability(BundleCapability capability, ContentHandler handler) |
| throws SAXException { |
| AttributesImpl atts = new AttributesImpl(); |
| String type = capability.getType(); |
| addAttr(atts, CapabilityHandler.NAME, type); |
| handler.startElement("", CapabilityHandler.CAPABILITY, CapabilityHandler.CAPABILITY, atts); |
| switch (type) { |
| case BundleInfo.BUNDLE_TYPE: |
| // nothing to do, already handled with the resource tag |
| break; |
| case BundleInfo.PACKAGE_TYPE: { |
| saxCapabilityProperty("package", capability.getName(), handler); |
| Version v = capability.getRawVersion(); |
| if (v != null) { |
| saxCapabilityProperty("version", v.toString(), handler); |
| } |
| Set<String> uses = ((ExportPackage) capability).getUses(); |
| if (uses != null && !uses.isEmpty()) { |
| StringBuilder builder = new StringBuilder(); |
| for (String use : uses) { |
| if (builder.length() != 0) { |
| builder.append(','); |
| } |
| builder.append(use); |
| } |
| saxCapabilityProperty("uses", builder.toString(), handler); |
| } |
| break; |
| } |
| case BundleInfo.SERVICE_TYPE: { |
| saxCapabilityProperty("service", capability.getName(), handler); |
| Version v = capability.getRawVersion(); |
| if (v != null) { |
| saxCapabilityProperty("version", v.toString(), handler); |
| } |
| break; |
| } |
| default: |
| // oups |
| break; |
| } |
| handler.endElement("", CapabilityHandler.CAPABILITY, CapabilityHandler.CAPABILITY); |
| handler.characters("\n".toCharArray(), 0, 1); |
| } |
| |
| private static void saxCapabilityProperty(String n, String v, ContentHandler handler) |
| throws SAXException { |
| saxCapabilityProperty(n, null, v, handler); |
| } |
| |
| private static void saxCapabilityProperty(String n, String t, String v, ContentHandler handler) |
| throws SAXException { |
| AttributesImpl atts = new AttributesImpl(); |
| addAttr(atts, CapabilityPropertyHandler.NAME, n); |
| if (t != null) { |
| addAttr(atts, CapabilityPropertyHandler.TYPE, t); |
| } |
| addAttr(atts, CapabilityPropertyHandler.VALUE, v); |
| handler.startElement("", CapabilityPropertyHandler.CAPABILITY_PROPERTY, |
| CapabilityPropertyHandler.CAPABILITY_PROPERTY, atts); |
| handler.endElement("", CapabilityPropertyHandler.CAPABILITY_PROPERTY, |
| CapabilityPropertyHandler.CAPABILITY_PROPERTY); |
| handler.characters("\n".toCharArray(), 0, 1); |
| } |
| |
| private static void saxRequirement(BundleRequirement requirement, ContentHandler handler) |
| throws SAXException { |
| AttributesImpl atts = new AttributesImpl(); |
| addAttr(atts, RequireHandler.NAME, requirement.getType()); |
| if ("optional".equals(requirement.getResolution())) { |
| addAttr(atts, RequireHandler.OPTIONAL, Boolean.TRUE.toString()); |
| } |
| addAttr(atts, RequireHandler.FILTER, buildFilter(requirement)); |
| handler.startElement("", RequireHandler.REQUIRE, RequireHandler.REQUIRE, atts); |
| handler.endElement("", RequireHandler.REQUIRE, RequireHandler.REQUIRE); |
| handler.characters("\n".toCharArray(), 0, 1); |
| } |
| |
| private static String buildFilter(BundleRequirement requirement) { |
| StringBuilder filter = new StringBuilder(); |
| VersionRange v = requirement.getVersion(); |
| if (v != null) { |
| appendVersion(filter, v); |
| } |
| filter.append('('); |
| filter.append(requirement.getType()); |
| filter.append("="); |
| filter.append(requirement.getName()); |
| filter.append(')'); |
| if (v != null) { |
| filter.append(')'); |
| } |
| return filter.toString(); |
| } |
| |
| private static void appendVersion(StringBuilder filter, VersionRange v) { |
| filter.append("(&"); |
| Version start = v.getStartVersion(); |
| if (start != null) { |
| if (!v.isStartExclusive()) { |
| filter.append("(version>="); |
| filter.append(start.toString()); |
| filter.append(')'); |
| } else { |
| filter.append("(!"); |
| filter.append("(version<="); |
| filter.append(start.toString()); |
| filter.append("))"); |
| } |
| } |
| Version end = v.getEndVersion(); |
| if (end != null) { |
| if (!v.isEndExclusive()) { |
| filter.append("(version<="); |
| filter.append(end.toString()); |
| filter.append(')'); |
| } else { |
| filter.append("(!"); |
| filter.append("(version>="); |
| filter.append(end.toString()); |
| filter.append("))"); |
| } |
| } |
| } |
| |
| private static void addAttr(AttributesImpl atts, String name, String value) { |
| if (value != null) { |
| atts.addAttribute("", name, name, "CDATA", value); |
| } |
| } |
| |
| private static void addAttr(AttributesImpl atts, String name, Object value) { |
| if (value != null) { |
| atts.addAttribute("", name, name, "CDATA", value.toString()); |
| } |
| } |
| |
| private static void startElement(ContentHandler handler, String name) throws SAXException { |
| handler.startElement("", name, name, new AttributesImpl()); |
| } |
| |
| private static void endElement(ContentHandler handler, String name) throws SAXException { |
| handler.endElement("", name, name); |
| } |
| |
| private static void characters(ContentHandler handler, String value) throws SAXException { |
| char[] chars = value.toCharArray(); |
| handler.characters(chars, 0, chars.length); |
| } |
| |
| } |