blob: fc5557f58b91e99d910c0d8c23346bfa6f7c75d6 [file] [log] [blame]
/*
* 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);
}
}