blob: ad7d8b7ea249bb5208afe61f2a09f9b36d068caa [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.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.ParseException;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.ivy.osgi.core.BundleArtifact;
import org.apache.ivy.osgi.core.BundleInfo;
import org.apache.ivy.osgi.core.ExecutionEnvironmentProfileProvider;
import org.apache.ivy.osgi.filter.OSGiFilter;
import org.apache.ivy.osgi.filter.OSGiFilterParser;
import org.apache.ivy.osgi.repo.BundleRepoDescriptor;
import org.apache.ivy.osgi.util.DelegatingHandler;
import org.apache.ivy.osgi.util.Version;
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 OBRXMLParser {
public static BundleRepoDescriptor parse(URI baseUri, InputStream in) throws IOException,
SAXException {
RepositoryHandler handler = new RepositoryHandler(baseUri);
try {
XMLHelper.parse(in, null, handler, null);
} catch (ParserConfigurationException e) {
throw new SAXException(e);
}
return handler.repo;
}
static class RepositoryHandler extends DelegatingHandler {
static final String REPOSITORY = "repository";
static final String LASTMODIFIED = "lastmodified";
static final String NAME = "name";
BundleRepoDescriptor repo;
private final URI baseUri;
public RepositoryHandler(URI baseUri) {
super(REPOSITORY);
this.baseUri = baseUri;
addChild(new ResourceHandler(), new ChildElementHandler<ResourceHandler>() {
@Override
public void childHandled(ResourceHandler child) {
repo.addBundle(child.bundleInfo);
}
});
}
@Override
protected void handleAttributes(Attributes atts) {
repo = new BundleRepoDescriptor(baseUri,
ExecutionEnvironmentProfileProvider.getInstance());
repo.setName(atts.getValue(NAME));
repo.setLastModified(atts.getValue(LASTMODIFIED));
}
}
static class ResourceHandler extends DelegatingHandler {
private static final String DEFAULT_VERSION = "1.0.0";
static final String RESOURCE = "resource";
static final String ID = "id";
static final String PRESENTATION_NAME = "presentationname";
static final String SYMBOLIC_NAME = "symbolicname";
static final String URI = "uri";
static final String VERSION = "version";
BundleInfo bundleInfo;
public ResourceHandler() {
super(RESOURCE);
setSkipOnError(true); // if anything bad happen in any children, just ignore the
// resource
addChild(new ResourceSourceHandler(), new ChildElementHandler<ResourceSourceHandler>() {
@Override
public void childHandled(ResourceSourceHandler child) {
String uri = child.getBufferedChars().trim();
if (!uri.endsWith(".jar")) {
// the maven plugin is putting some useless source url sometimes...
log(Message.MSG_WARN,
"A source uri is suspect, it is not ending with .jar, it is probably"
+ " a pointer to a download page. Ignoring it.");
return;
}
try {
bundleInfo.addArtifact(new BundleArtifact(true, new URI(uri), null));
} catch (URISyntaxException e) {
log(Message.MSG_WARN, "Incorrect uri " + uri + ". The source of "
+ bundleInfo.getSymbolicName() + " is then ignored.");
return;
}
}
});
addChild(new ResourceDescriptionHandler(),
new ChildElementHandler<ResourceDescriptionHandler>() {
@Override
public void childHandled(ResourceDescriptionHandler child) {
bundleInfo.setDescription(child.getBufferedChars().trim());
}
});
addChild(new ResourceDocumentationHandler(),
new ChildElementHandler<ResourceDocumentationHandler>() {
@Override
public void childHandled(ResourceDocumentationHandler child) {
bundleInfo.setDocumentation(child.getBufferedChars().trim());
}
});
addChild(new ResourceLicenseHandler(),
new ChildElementHandler<ResourceLicenseHandler>() {
@Override
public void childHandled(ResourceLicenseHandler child) {
bundleInfo.setLicense(child.getBufferedChars().trim());
}
});
addChild(new ResourceSizeHandler(), new ChildElementHandler<ResourceSizeHandler>() {
@Override
public void childHandled(ResourceSizeHandler child) {
String size = child.getBufferedChars().trim();
try {
bundleInfo.setSize(Integer.valueOf(size));
} catch (NumberFormatException e) {
log(Message.MSG_WARN,
"Invalid size for the bundle " + bundleInfo.getSymbolicName() + ": "
+ size + ". This size is then ignored.");
}
}
});
addChild(new CapabilityHandler(), new ChildElementHandler<CapabilityHandler>() {
@Override
public void childHandled(CapabilityHandler child) throws SAXParseException {
try {
CapabilityAdapter.adapt(bundleInfo, child.capability);
} catch (ParseException e) {
throw new SAXParseException("Invalid capability: " + e.getMessage(), child
.getLocator());
}
}
});
addChild(new RequireHandler(), new ChildElementHandler<RequireHandler>() {
@Override
public void childHandled(RequireHandler child) throws SAXParseException {
try {
RequirementAdapter.adapt(bundleInfo, child.requirement);
} catch (UnsupportedFilterException e) {
throw new SAXParseException("Unsupported requirement filter: "
+ child.filter + " (" + e.getMessage() + ")", getLocator());
} catch (ParseException e) {
throw new SAXParseException(
"Error in the requirement filter on the bundle: " + e.getMessage(),
getLocator());
}
}
});
addChild(new ExtendHandler(), new ChildElementHandler<ExtendHandler>() {
@Override
public void childHandled(ExtendHandler child) throws SAXParseException {
// TODO handle fragment host
}
});
}
@Override
protected void handleAttributes(Attributes atts) throws SAXException {
String symbolicname = atts.getValue(SYMBOLIC_NAME);
if (symbolicname == null) {
log(Message.MSG_ERR, "Resource with no symbolic name, skipping it.");
skip();
return;
}
String v = getOptionalAttribute(atts, VERSION, DEFAULT_VERSION);
Version version = new Version(v);
bundleInfo = new BundleInfo(symbolicname, version);
bundleInfo.setPresentationName(atts.getValue(PRESENTATION_NAME));
String uri = atts.getValue(URI);
if (uri != null) {
try {
bundleInfo.addArtifact(new BundleArtifact(false, new URI(uri), null));
} catch (URISyntaxException e) {
log(Message.MSG_ERR, "Incorrect uri " + uri + ". The resource " + symbolicname
+ " is then ignored.");
skip();
return;
}
}
bundleInfo.setId(atts.getValue(ID));
}
@Override
protected String getCurrentElementIdentifier() {
return bundleInfo.getSymbolicName() + "/" + bundleInfo.getVersion();
}
}
static class ResourceSourceHandler extends DelegatingHandler {
static final String SOURCE = "source";
public ResourceSourceHandler() {
super(SOURCE);
setBufferingChar(true);
}
}
static class ResourceDescriptionHandler extends DelegatingHandler {
static final String DESCRIPTION = "description";
public ResourceDescriptionHandler() {
super(DESCRIPTION);
setBufferingChar(true);
}
}
static class ResourceDocumentationHandler extends DelegatingHandler {
static final String DOCUMENTATION = "documentation";
public ResourceDocumentationHandler() {
super(DOCUMENTATION);
setBufferingChar(true);
}
}
static class ResourceLicenseHandler extends DelegatingHandler {
static final String LICENSE = "license";
public ResourceLicenseHandler() {
super(LICENSE);
setBufferingChar(true);
}
}
static class ResourceSizeHandler extends DelegatingHandler {
static final String SIZE = "size";
public ResourceSizeHandler() {
super(SIZE);
setBufferingChar(true);
}
}
static class CapabilityHandler extends DelegatingHandler {
static final String CAPABILITY = "capability";
static final String NAME = "name";
Capability capability;
public CapabilityHandler() {
super(CAPABILITY);
addChild(new CapabilityPropertyHandler(),
new ChildElementHandler<CapabilityPropertyHandler>() {
@Override
public void childHandled(CapabilityPropertyHandler child) {
String name = child.name;
String value = child.value;
String type = child.type;
capability.addProperty(name, value, type);
}
});
}
@Override
protected void handleAttributes(Attributes atts) throws SAXException {
String name = getRequiredAttribute(atts, NAME);
capability = new Capability(name);
}
}
static class CapabilityPropertyHandler extends DelegatingHandler {
static final String CAPABILITY_PROPERTY = "p";
static final String NAME = "n";
static final String VALUE = "v";
static final String TYPE = "t";
String name;
String value;
String type;
public CapabilityPropertyHandler() {
super(CAPABILITY_PROPERTY);
}
@Override
protected void handleAttributes(Attributes atts) throws SAXException {
name = getRequiredAttribute(atts, NAME);
value = getRequiredAttribute(atts, VALUE);
type = atts.getValue(TYPE);
}
}
static class AbstractRequirementHandler extends DelegatingHandler {
static final String NAME = "name";
static final String OPTIONAL = "optional";
static final String MULTIPLE = "multiple";
static final String FILTER = "filter";
Requirement requirement;
OSGiFilter filter;
public AbstractRequirementHandler(String name) {
super(name);
}
@Override
protected void handleAttributes(Attributes atts) throws SAXException {
String name = getRequiredAttribute(atts, NAME);
String filterText = atts.getValue(FILTER);
filter = null;
if (filterText != null) {
try {
filter = OSGiFilterParser.parse(filterText);
} catch (ParseException e) {
throw new SAXParseException("Requirement with ill-formed filter: " + filterText,
getLocator());
}
}
Boolean optional = getOptionalBooleanAttribute(atts, OPTIONAL, null);
Boolean multiple = getOptionalBooleanAttribute(atts, MULTIPLE, null);
requirement = new Requirement(name, filter);
if (optional != null) {
requirement.setOptional(optional);
}
if (multiple != null) {
requirement.setMultiple(multiple);
}
}
}
static class RequireHandler extends AbstractRequirementHandler {
static final String REQUIRE = "require";
public RequireHandler() {
super(REQUIRE);
}
}
static class ExtendHandler extends AbstractRequirementHandler {
static final String EXTEND = "extend";
public ExtendHandler() {
super(EXTEND);
}
}
}