blob: e650c9ced9a759d386ae836d423c7ec94932307a [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.p2;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
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.p2.PropertiesParser.PropertiesHandler;
import org.apache.ivy.osgi.util.DelegatingHandler;
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.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
public class P2MetadataParser implements XMLInputParser {
private final P2Descriptor p2Descriptor;
private int logLevel = Message.MSG_INFO;
public P2MetadataParser(P2Descriptor p2Descriptor) {
this.p2Descriptor = p2Descriptor;
}
public void setLogLevel(int logLevel) {
this.logLevel = logLevel;
}
public void parse(InputStream in) throws IOException, ParseException, SAXException {
RepositoryHandler handler = new RepositoryHandler(p2Descriptor);
try {
XMLHelper.parse(in, null, handler, null);
} catch (ParserConfigurationException e) {
throw new SAXException(e);
}
}
private class RepositoryHandler extends DelegatingHandler {
// private static final String P2_TIMESTAMP = "p2.timestamp";
private static final String REPOSITORY = "repository";
// private static final String NAME = "name";
//
// private static final String TYPE = "type";
//
// private static final String VERSION = "version";
//
// private static final String DESCRIPTION = "description";
//
// private static final String PROVIDER = "provider";
public RepositoryHandler(final P2Descriptor p2Descriptor) {
super(REPOSITORY);
// addChild(new PropertiesHandler(P2_TIMESTAMP),
// new ChildElementHandler<PropertiesHandler>() {
// public void childHandled(PropertiesHandler child) {
// String timestamp = child.properties.get(P2_TIMESTAMP);
// if (timestamp != null) {
// p2Descriptor.setTimestamp(Long.parseLong(timestamp));
// }
// }
// });
addChild(new UnitsHandler(), new ChildElementHandler<UnitsHandler>() {
@Override
public void childHandled(UnitsHandler child) {
for (BundleInfo bundle : child.bundles) {
p2Descriptor.addBundle(bundle);
}
}
});
addChild(new ReferencesHandler(), new ChildElementHandler<ReferencesHandler>() {
@Override
public void childHandled(ReferencesHandler child) {
}
});
}
// protected void handleAttributes(Attributes atts) {
// String name = atts.getValue(NAME);
// String type = atts.getValue(TYPE);
// String version = atts.getValue(VERSION);
// String description = atts.getValue(DESCRIPTION);
// String provider = atts.getValue(PROVIDER);
// }
}
private class ReferencesHandler extends DelegatingHandler {
private static final String REFERENCES = "references";
private static final String SIZE = "size";
List<URI> repositoryUris;
public ReferencesHandler() {
super(REFERENCES);
addChild(new RepositoryReferenceHandler(),
new ChildElementHandler<RepositoryReferenceHandler>() {
@Override
public void childHandled(RepositoryReferenceHandler child) {
repositoryUris.add(child.uri);
}
});
}
@Override
protected void handleAttributes(Attributes atts) throws SAXException {
int size = Integer.parseInt(atts.getValue(SIZE));
repositoryUris = new ArrayList<>(size);
}
}
private class RepositoryReferenceHandler extends DelegatingHandler {
private static final String REPOSITORY = "repository";
// private static final String TYPE = "type";
//
// private static final String OPTIONS = "options";
//
// private static final String NAME = "name";
private static final String URI = "uri";
private static final String URL = "url";
public RepositoryReferenceHandler() {
super(REPOSITORY);
}
// int type;
//
// int options;
//
// String name;
URI uri;
@Override
protected void handleAttributes(Attributes atts) throws SAXException {
// type = Integer.parseInt(atts.getValue(TYPE));
// options = Integer.parseInt(atts.getValue(OPTIONS));
// name = atts.getValue(NAME);
String uriAtt = atts.getValue(URI);
String urlAtt = atts.getValue(URL);
if (uriAtt != null) {
try {
uri = new URI(uriAtt);
} catch (URISyntaxException e) {
throw new SAXParseException("Invalid uri attribute " + uriAtt + "("
+ e.getMessage() + ")", getLocator());
}
}
if (uri != null && urlAtt != null) {
try {
uri = new URI(urlAtt);
} catch (URISyntaxException e) {
throw new SAXParseException("Invalid url attribute " + urlAtt + "("
+ e.getMessage() + ")", getLocator());
}
}
}
}
private class UnitsHandler extends DelegatingHandler {
private static final String UNITS = "units";
private static final String SIZE = "size";
List<BundleInfo> bundles;
public UnitsHandler() {
super(UNITS);
addChild(new UnitHandler(), new ChildElementHandler<UnitHandler>() {
@Override
public void childHandled(UnitHandler child) {
if (child.bundleInfo != null && !child.bundleInfo.getCapabilities().isEmpty()) {
bundles.add(child.bundleInfo);
}
}
});
}
@Override
protected void handleAttributes(Attributes atts) {
int size = Integer.parseInt(atts.getValue(SIZE));
bundles = new ArrayList<>(size);
}
}
class UnitHandler extends DelegatingHandler {
private static final String CATEGORY_PROPERTY = "org.eclipse.equinox.p2.type.category";
private static final String UNIT = "unit";
private static final String ID = "id";
private static final String VERSION = "version";
// private static final String SINGLETON = "singleton";
BundleInfo bundleInfo;
public UnitHandler() {
super(UNIT);
// addChild(new UpdateHandler(), new ChildElementHandler() {
// public void childHandled(DelegatingHandler child) {
// }
// });
addChild(new PropertiesHandler(CATEGORY_PROPERTY),
new ChildElementHandler<PropertiesHandler>() {
@Override
public void childHandled(PropertiesHandler child) {
String category = child.properties.get(CATEGORY_PROPERTY);
if (category != null && Boolean.valueOf(category)) {
// this is a category definition, this is useless, skip this unit
child.getParent().skip();
bundleInfo = null;
}
}
});
addChild(new ProvidesHandler(), new ChildElementHandler<ProvidesHandler>() {
@Override
public void childHandled(ProvidesHandler child) {
if ("source".equals(child.eclipseType)) {
// this is some source of some bundle
bundleInfo.setSource(true);
// we need to parse the manifest in the touchpointData to figure out the
// targeted bundle
// in case we won't have the proper data in the manifest, prepare the source
// data from the convention
String symbolicName = bundleInfo.getSymbolicName();
if (symbolicName.endsWith(".source")) {
bundleInfo.setSymbolicNameTarget(symbolicName.substring(0,
symbolicName.length() - 7));
bundleInfo.setVersionTarget(bundleInfo.getVersion());
}
}
for (BundleCapability capability : child.capabilities) {
bundleInfo.addCapability(capability);
}
}
});
addChild(new FilterHandler(), new ChildElementHandler<FilterHandler>() {
@Override
public void childHandled(FilterHandler child) {
}
});
addChild(new RequiresHandler(), new ChildElementHandler<RequiresHandler>() {
@Override
public void childHandled(RequiresHandler child) {
for (BundleRequirement requirement : child.requirements) {
bundleInfo.addRequirement(requirement);
}
}
});
addChild(new HostRequirementsHandler(),
new ChildElementHandler<HostRequirementsHandler>() {
@Override
public void childHandled(HostRequirementsHandler child) {
}
});
addChild(new MetaRequirementsHandler(),
new ChildElementHandler<MetaRequirementsHandler>() {
@Override
public void childHandled(MetaRequirementsHandler child) {
}
});
addChild(new ArtifactsHandler(), new ChildElementHandler<ArtifactsHandler>() {
@Override
public void childHandled(ArtifactsHandler child) {
}
});
// addChild(new TouchpointHandler(), new ChildElementHandler() {
// public void childHandled(DelegatingHandler child) {
// }
// });
addChild(new TouchpointDataHandler(), new ChildElementHandler<TouchpointDataHandler>() {
@Override
public void childHandled(TouchpointDataHandler child) throws SAXParseException {
if (child.zipped != null) {
bundleInfo.setHasInnerClasspath(child.zipped);
}
if (!bundleInfo.isSource()) {
// we only care about parsing the manifest if it is a source
return;
}
if (child.manifest != null) {
// Eclipse may have serialized a little bit weirdly
String manifest = ManifestParser.formatLines(child.manifest.trim());
BundleInfo embeddedInfo;
try {
embeddedInfo = ManifestParser.parseManifest(manifest);
} catch (IOException e) {
if (logLevel >= Message.MSG_VERBOSE) {
Message.verbose(
"The Manifest of the source bundle "
+ bundleInfo.getSymbolicName() + " could not be parsed",
e);
}
return;
} catch (ParseException e) {
if (logLevel >= Message.MSG_VERBOSE) {
Message.verbose(
"The Manifest of the source bundle "
+ bundleInfo.getSymbolicName() + " is ill formed", e);
}
return;
}
if (!embeddedInfo.isSource()) {
if (logLevel >= Message.MSG_VERBOSE) {
Message.verbose("The Manifest of the source bundle "
+ bundleInfo.getSymbolicName()
+ " is not declaring being a source.");
}
return;
}
String symbolicNameTarget = embeddedInfo.getSymbolicNameTarget();
if (symbolicNameTarget == null) {
if (logLevel >= Message.MSG_VERBOSE) {
Message.verbose("The Manifest of the source bundle "
+ bundleInfo.getSymbolicName()
+ " is not declaring a target symbolic name.");
}
return;
}
Version versionTarget = embeddedInfo.getVersionTarget();
if (versionTarget == null) {
if (logLevel >= Message.MSG_VERBOSE) {
Message.verbose("The Manifest of the source bundle "
+ bundleInfo.getSymbolicName()
+ " is not declaring a target version.");
}
return;
}
bundleInfo.setSymbolicNameTarget(symbolicNameTarget);
bundleInfo.setVersionTarget(versionTarget);
}
}
});
// addChild(new LicensesHandler(), new ChildElementHandler() {
// public void childHandled(DelegatingHandler child) {
// }
// });
// addChild(new CopyrightHandler(), new ChildElementHandler() {
// public void childHandled(DelegatingHandler child) {
// }
// });
// addChild(new ChangesHandler(), new ChildElementHandler() {
// public void childHandled(DelegatingHandler child) {
// }
// });
}
@Override
protected void handleAttributes(Attributes atts) throws SAXException {
String id = atts.getValue(ID);
String version = atts.getValue(VERSION);
// Boolean singleton = Boolean.valueOf(atts.getValue(SINGLETON));
bundleInfo = new BundleInfo(id, new Version(version));
}
}
// static class UpdateHandler extends DelegatingHandler {
//
// private static final String UPDATE = "update";
//
// private static final String ID = "id";
//
// private static final String RANGE = "range";
//
// private static final String SEVERITY = "severity";
//
// public UpdateHandler() {
// super(UPDATE);
// }
//
// protected void handleAttributes(Attributes atts) {
// String id = atts.getValue(ID);
// String range = atts.getValue(RANGE);
// String severity = atts.getValue(SEVERITY);
// }
//
// }
private static class FilterHandler extends DelegatingHandler {
private static final String FILTER = "filter";
public FilterHandler() {
super(FILTER);
setBufferingChar(true);
}
}
private static String namespace2Type(String namespace) {
if (namespace == null) {
return null;
}
if (namespace.equals("java.package")) {
return BundleInfo.PACKAGE_TYPE;
}
if (namespace.equals("osgi.bundle")) {
return BundleInfo.BUNDLE_TYPE;
}
return null;
}
private class ProvidesHandler extends DelegatingHandler {
private static final String PROVIDES = "provides";
private static final String SIZE = "size";
List<BundleCapability> capabilities;
String eclipseType;
public ProvidesHandler() {
super(PROVIDES);
addChild(new ProvidedHandler(), new ChildElementHandler<ProvidedHandler>() {
@Override
public void childHandled(ProvidedHandler child) {
if (child.namespace.equals("org.eclipse.equinox.p2.eclipse.type")) {
eclipseType = child.name;
} else {
String type = namespace2Type(child.namespace);
if (type == null) {
if (logLevel >= Message.MSG_DEBUG) {
Message.debug("Unsupported provided capability " + child.namespace
+ " " + child.name + " " + child.version);
}
return;
}
BundleCapability capability;
if (BundleInfo.PACKAGE_TYPE.equals(type)) {
capability = new ExportPackage(child.name, child.version);
} else {
capability = new BundleCapability(type, child.name, child.version);
}
capabilities.add(capability);
}
}
});
}
@Override
protected void handleAttributes(Attributes atts) {
int size = Integer.parseInt(atts.getValue(SIZE));
capabilities = new ArrayList<>(size);
}
}
private static class ProvidedHandler extends DelegatingHandler {
private static final String PROVIDED = "provided";
private static final String NAMESPACE = "namespace";
private static final String NAME = "name";
private static final String VERSION = "version";
String namespace;
String name;
Version version;
public ProvidedHandler() {
super(PROVIDED);
}
@Override
protected void handleAttributes(Attributes atts) throws SAXException {
namespace = atts.getValue(NAMESPACE);
name = atts.getValue(NAME);
version = new Version(atts.getValue(VERSION));
}
}
abstract class AbstractRequirementHandler extends DelegatingHandler {
private static final String SIZE = "size";
List<BundleRequirement> requirements;
public AbstractRequirementHandler(String name) {
super(name);
addChild(new RequiredHandler(), new ChildElementHandler<RequiredHandler>() {
@Override
public void childHandled(RequiredHandler child) {
String name = child.name;
VersionRange range = child.range;
String type = namespace2Type(child.namespace);
if (type == null) {
if (logLevel >= Message.MSG_DEBUG) {
Message.debug("Unsupported required capability " + child.namespace
+ " " + name + " " + range);
}
} else {
String resolution = child.optional ? "optional" : null;
requirements.add(new BundleRequirement(type, name, range, resolution));
}
}
});
}
@Override
protected void handleAttributes(Attributes atts) {
int size = Integer.parseInt(atts.getValue(SIZE));
requirements = new ArrayList<>(size);
}
}
private class RequiresHandler extends AbstractRequirementHandler {
private static final String REQUIRES = "requires";
public RequiresHandler() {
super(REQUIRES);
}
}
private class RequiredHandler extends DelegatingHandler {
private static final String REQUIRED = "required";
private static final String NAMESPACE = "namespace";
private static final String NAME = "name";
private static final String RANGE = "range";
private static final String OPTIONAL = "optional";
// private static final String GREEDY = "greedy";
String namespace;
String name;
VersionRange range;
// String filter;
//
// boolean greedy;
boolean optional;
public RequiredHandler() {
super(REQUIRED);
// addChild(new FilterHandler(), new ChildElementHandler<FilterHandler>() {
// public void childHandled(FilterHandler child) {
// filter = child.getBufferedChars().trim();
// }
// });
}
@Override
protected void handleAttributes(Attributes atts) throws SAXParseException {
namespace = atts.getValue(NAMESPACE);
name = atts.getValue(NAME);
try {
range = new VersionRange(atts.getValue(RANGE));
} catch (ParseException e) {
throw new RuntimeException(e);
}
// greedy = getOptionalBooleanAttribute(atts, GREEDY, Boolean.TRUE).booleanValue();
optional = getOptionalBooleanAttribute(atts, OPTIONAL, Boolean.FALSE);
}
}
private class HostRequirementsHandler extends AbstractRequirementHandler {
private static final String HOST_REQUIREMENTS = "hostRequirements";
public HostRequirementsHandler() {
super(HOST_REQUIREMENTS);
}
}
private class MetaRequirementsHandler extends AbstractRequirementHandler {
private static final String META_REQUIREMENTS = "metaRequirements";
public MetaRequirementsHandler() {
super(META_REQUIREMENTS);
}
}
private class ArtifactsHandler extends DelegatingHandler {
private static final String ARTIFACTS = "artifacts";
private static final String SIZE = "size";
List<P2Artifact> artifacts;
public ArtifactsHandler() {
super(ARTIFACTS);
addChild(new ArtifactHandler(), new ChildElementHandler<ArtifactHandler>() {
@Override
public void childHandled(ArtifactHandler child) {
artifacts.add(child.artifact);
}
});
}
@Override
protected void handleAttributes(Attributes atts) {
int size = Integer.parseInt(atts.getValue(SIZE));
artifacts = new ArrayList<>(size);
}
}
private class ArtifactHandler extends DelegatingHandler {
private static final String ARTIFACT = "artifact";
private static final String ID = "id";
private static final String VERSION = "version";
private static final String CLASSIFIER = "classifier";
P2Artifact artifact;
public ArtifactHandler() {
super(ARTIFACT);
}
@Override
protected void handleAttributes(Attributes atts) throws SAXException {
String id = atts.getValue(ID);
String version = atts.getValue(VERSION);
String classifier = atts.getValue(CLASSIFIER);
artifact = new P2Artifact(id, new Version(version), classifier);
}
}
// private static class TouchpointHandler extends DelegatingHandler {
//
// private static final String TOUCHPOINT = "touchpoint";
//
// private static final String ID = "id";
//
// private static final String VERSION = "version";
//
// public TouchpointHandler() {
// super(TOUCHPOINT);
// }
//
// protected void handleAttributes(Attributes atts) {
// String id = atts.getValue(ID);
// String version = atts.getValue(VERSION);
// }
//
// }
private class TouchpointDataHandler extends DelegatingHandler {
private static final String TOUCHPOINTDATA = "touchpointData";
// private static final String SIZE = "size";
String manifest;
Boolean zipped;
public TouchpointDataHandler() {
super(TOUCHPOINTDATA);
addChild(new InstructionsHandler(), new ChildElementHandler<InstructionsHandler>() {
@Override
public void childHandled(InstructionsHandler child) {
manifest = child.manifest;
zipped = child.zipped;
}
});
}
@Override
protected void handleAttributes(Attributes atts) {
// String size = atts.getValue(SIZE);
}
}
private class InstructionsHandler extends DelegatingHandler {
private static final String INSTRUCTIONS = "instructions";
// private static final String SIZE = "size";
String manifest;
Boolean zipped;
public InstructionsHandler() {
super(INSTRUCTIONS);
addChild(new InstructionHandler(), new ChildElementHandler<InstructionHandler>() {
@Override
public void childHandled(InstructionHandler child) {
manifest = null;
zipped = null;
String buffer = child.getBufferedChars().trim();
if ("manifest".equals(child.key)) {
manifest = buffer;
} else if ("zipped".equals(child.key) && buffer.length() != 0) {
zipped = Boolean.valueOf(buffer);
}
}
});
}
@Override
protected void handleAttributes(Attributes atts) {
// String size = atts.getValue(SIZE);
}
}
private class InstructionHandler extends DelegatingHandler {
private static final String INSTRUCTION = "instruction";
private static final String KEY = "key";
String key;
public InstructionHandler() {
super(INSTRUCTION);
setBufferingChar(true);
}
@Override
protected void handleAttributes(Attributes atts) {
key = atts.getValue(KEY);
}
}
// private static class LicensesHandler extends DelegatingHandler {
//
// private static final String LICENSES = "licenses";
//
// private static final String SIZE = "size";
//
// public LicensesHandler() {
// super(LICENSES);
// addChild(new LicenseHandler(), new ChildElementHandler() {
// public void childHandled(DelegatingHandler child) {
// }
// });
// }
//
// protected void handleAttributes(Attributes atts) {
// String size = atts.getValue(SIZE);
// }
//
// }
// private static class LicenseHandler extends DelegatingHandler {
//
// private static final String LICENSE = "license";
//
// private static final String URI = "uri";
//
// private static final String URL = "url";
//
// public LicenseHandler() {
// super(LICENSE);
// setBufferingChar(true);
// }
//
// protected void handleAttributes(Attributes atts) {
// String uri = atts.getValue(URI);
// String url = atts.getValue(URL);
// }
//
// }
// private static class CopyrightHandler extends DelegatingHandler {
//
// private static final String COPYRIGHT = "copyright";
//
// private static final String URI = "uri";
//
// private static final String URL = "url";
//
// public CopyrightHandler() {
// super(COPYRIGHT);
// }
//
// protected void handleAttributes(Attributes atts) {
// String uri = atts.getValue(URI);
// String url = atts.getValue(URL);
// }
//
// }
// private class ChangesHandler extends DelegatingHandler {
//
// private static final String CHANGES = "changes";
//
// private static final String SIZE = "size";
//
// public ChangesHandler() {
// super(CHANGES);
// addChild(new ChangeHandler(), new ChildElementHandler<ChangeHandler>() {
// public void childHandled(ChangeHandler child) {
// }
// });
// }
//
// protected void handleAttributes(Attributes atts) {
// int size = Integer.parseInt(atts.getValue(SIZE));
// }
// }
// private class ChangeHandler extends DelegatingHandler {
//
// private static final String CHANGE = "change";
//
// public ChangeHandler() {
// super(CHANGE);
// }
// }
// private class FromHandler extends AbstractRequirementHandler {
//
// private static final String FROM = "from";
//
// public FromHandler() {
// super(FROM);
// }
//
// }
// private class ToHandler extends AbstractRequirementHandler {
//
// private static final String TO = "to";
//
// public ToHandler() {
// super(TO);
// }
//
// }
// private class PatchScopeHandler extends DelegatingHandler {
//
// private static final String PATCH_SCOPE = "patchScope";
//
// private static final String SIZE = "size";
//
// public PatchScopeHandler() {
// super(PATCH_SCOPE);
// addChild(new PatchScopeHandler(), new ChildElementHandler<PatchScopeHandler>() {
// public void childHandled(PatchScopeHandler child) {
// }
// });
// }
//
// protected void handleAttributes(Attributes atts) {
// int size = Integer.parseInt(atts.getValue(SIZE));
// }
// }
// private class ScopeHandler extends DelegatingHandler {
//
// private static final String SCOPE = "scope";
//
// public ScopeHandler() {
// super(SCOPE);
// addChild(new RequiresHandler(), new ChildElementHandler<RequiresHandler>() {
// public void childHandled(RequiresHandler child) {
// }
// });
// }
// }
// private class LifeCycleHandler extends AbstractRequirementHandler {
//
// private static final String LIFE_CYCLE = "lifeCycle";
//
// public LifeCycleHandler() {
// super(LIFE_CYCLE);
// }
// }
}