All Downloads are FREE. Search and download functionalities are using the official Maven repository.

aQute.bnd.osgi.repository.XMLResourceParser Maven / Gradle / Ivy

There is a newer version: 7.0.0
Show newest version
package aQute.bnd.osgi.repository;

import java.io.File;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import org.osgi.resource.Resource;
import org.osgi.service.repository.ContentNamespace;

import aQute.bnd.header.Attrs;
import aQute.bnd.osgi.Processor;
import aQute.bnd.osgi.resource.CapReqBuilder;
import aQute.bnd.osgi.resource.ResourceBuilder;
import aQute.lib.strings.Strings;
import aQute.libg.gzip.GZipUtils;

public class XMLResourceParser extends Processor {
	final static XMLInputFactory inputFactory = XMLInputFactory.newInstance();

	static {
		inputFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, true);
		inputFactory.setProperty(XMLInputFactory.IS_VALIDATING, false);
		inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
	}

	private static final String		NS_URI				= "http://www.osgi.org/xmlns/repository/v1.0.0";
	private static final String		TAG_REPOSITORY		= "repository";
	private static final String		TAG_REFERRAL		= "referral";
	private static final String		TAG_RESOURCE		= "resource";
	private static final String		TAG_CAPABILITY		= "capability";
	private static final String		TAG_REQUIREMENT		= "requirement";
	private static final String		TAG_ATTRIBUTE		= "attribute";
	private static final String		TAG_DIRECTIVE		= "directive";

	private static final String		ATTR_REFERRAL_URL	= "url";
	private static final String		ATTR_REFERRAL_DEPTH	= "depth";

	private static final String		ATTR_NAMESPACE		= "namespace";

	private static final String		ATTR_NAME			= "name";
	private static final String		ATTR_VALUE			= "value";
	private static final String		ATTR_TYPE			= "type";

	final private List	resources			= new ArrayList<>();
	final private XMLStreamReader	reader;
	final private Set			traversed;
	final private String			what;
	@SuppressWarnings("unused")
	final private URI				url;

	private int						depth;

	public static List getResources(URI uri) throws Exception {
		try (XMLResourceParser parser = new XMLResourceParser(uri)) {
			return parser.parse();
		}
	}

	public XMLResourceParser(URI url) throws Exception {
		this(url.toURL().openStream(), url.toString(), url);
	}

	public XMLResourceParser(InputStream in, String what, URI uri) throws Exception {
		this(in, what, 100, new HashSet(), uri);
	}

	public void setDepth(int n) {
		this.depth = n;
	}

	public XMLResourceParser(InputStream in, String what, int depth, Set traversed, URI url) throws Exception {
		this.what = what;
		this.depth = depth;
		this.traversed = traversed;
		this.url = url;
		reader = inputFactory.createXMLStreamReader(GZipUtils.detectCompression(in));
	}

	public XMLResourceParser(File location) throws Exception {
		this(location.toURI());
	}

	List getResources() {
		if (!isOk())
			return null;

		return resources;
	}

	public List parse() throws Exception {
		if (!check(reader.hasNext(), "No content found"))
			return null;

		next();

		if (!check(reader.isStartElement(), "Expected a start element at the root, is %s", reader.getEventType()))
			return null;

		String name = reader.getLocalName();
		if (!check(TAG_REPOSITORY.equals(name), "Invalid tag name of top element, expected %s, got %s", TAG_REPOSITORY,
				name))
			return null;

		String nsUri = reader.getNamespaceURI();
		if (nsUri != null) {
			check(NS_URI.equals(nsUri), "Incorrect namespace. Expected %s, got %s", NS_URI, nsUri);
		}

		next(); // either start resource/referral or end

		while (reader.isStartElement()) {
			String localName = reader.getLocalName();
			if (localName.equals(TAG_REFERRAL))
				parseReferral();
			else if (localName.equals(TAG_RESOURCE))
				parseResource(resources);
			else {
				check(false, "Unexpected element %s", localName);
				next();
			}
		}

		check(reader.isEndElement() && reader.getLocalName().equals(TAG_REPOSITORY),
				"Expected to be at the end but are on %s", reader.getLocalName());
		return getResources();
	}

	public void next() throws XMLStreamException {
		report();
		reader.nextTag();
	}

	private void report() {
		int type = reader.getEventType();
		switch (type) {
			case XMLStreamConstants.START_DOCUMENT :
			case XMLStreamConstants.START_ELEMENT :
			case XMLStreamConstants.END_ELEMENT :
				break;
			default :
				trace("** unknown element, event type %s", type);
				break;
		}
	}

	private void parseReferral() throws Exception {
		if (--depth < 0)
			error("Too deep, traversed %s", traversed);
		else {
			String depthString = reader.getAttributeValue(NS_URI, ATTR_REFERRAL_DEPTH);
			String urlString = reader.getAttributeValue(NS_URI, ATTR_REFERRAL_URL);

			if (check(urlString != null, "Expected URL in referral")) {
				// TODO resolve url
				URI url = this.url.resolve(urlString);
				traversed.add(url);

				int depth = 100;
				if (depthString != null) {
					depth = Integer.parseInt(depthString);
				}
				InputStream in = url.toURL().openStream();
				try (XMLResourceParser referralParser = new XMLResourceParser(in, urlString, depth, traversed, url);) {
					referralParser.parse();
					resources.addAll(referralParser.resources);
				}

			}
		}
		tagEnd(TAG_REFERRAL);
	}

	private void tagEnd(String tag) throws XMLStreamException {
		if (!check(reader.isEndElement(), "Expected end element, got %s for %s (%s)", reader.getEventType(), tag,
				reader.getLocalName())) {
			trace("oops, invalid end %s", tag);
		}
		next();
	}

	private void parseResource(List resources) throws Exception {
		ResourceBuilder resourceBuilder = new ResourceBuilder();

		next();
		while (reader.isStartElement()) {
			parseCapabilityOrRequirement(resourceBuilder);
		}
		Resource resource = resourceBuilder.build();
		resources.add(resource);
		tagEnd(TAG_RESOURCE);
	}

	private void parseCapabilityOrRequirement(ResourceBuilder resourceBuilder) throws Exception {
		String name = reader.getLocalName();
		check(TAG_REQUIREMENT.equals(name) || TAG_CAPABILITY.equals(name), "Expected <%s> or <%s> tag, got <%s>",
				TAG_REQUIREMENT, TAG_CAPABILITY, name);

		String namespace = reader.getAttributeValue(null, ATTR_NAMESPACE);

		CapReqBuilder capReqBuilder = new CapReqBuilder(namespace);

		next();
		while (reader.isStartElement()) {
			parseAttributesOrDirectives(capReqBuilder);
		}

		if (TAG_REQUIREMENT.equals(name)) {
			resourceBuilder.addRequirement(capReqBuilder);
		} else {
			resourceBuilder.addCapability(capReqBuilder);
		}

		tagEnd(name);
	}

	private void parseAttributesOrDirectives(CapReqBuilder capReqBuilder) throws Exception {
		String name = reader.getLocalName();
		switch (name) {
			case TAG_ATTRIBUTE :
				parseAttribute(capReqBuilder);
				break;

			case TAG_DIRECTIVE :
				parseDirective(capReqBuilder);
				break;

			default :
				check(false, "Invalid tag, expected either <%s> or <%s>, got <%s>", TAG_ATTRIBUTE, TAG_DIRECTIVE);
		}
		next();
		tagEnd(name);
	}

	private boolean check(boolean check, String format, Object... args) {

		if (check)
			return true;

		String message = Strings.format(format, args);
		error("%s: %s", what, message);

		return false;
	}

	private void parseAttribute(CapReqBuilder capReqBuilder) throws Exception {
		String attributeName = reader.getAttributeValue(null, ATTR_NAME);
		String attributeValue = reader.getAttributeValue(null, ATTR_VALUE);
		String attributeType = reader.getAttributeValue(null, ATTR_TYPE);

		if (isContent(capReqBuilder) && attributeName.equals("url")) {
			attributeValue = url.resolve(attributeValue).toString();
		}

		Object value = Attrs.convert(attributeType, attributeValue);
		capReqBuilder.addAttribute(attributeName, value);
	}

	private boolean isContent(CapReqBuilder capReqBuilder) {
		return ContentNamespace.CONTENT_NAMESPACE.equals(capReqBuilder.getNamespace());
	}

	private void parseDirective(CapReqBuilder capReqBuilder) throws XMLStreamException {
		String attributeName = reader.getAttributeValue(null, ATTR_NAME);
		String attributeValue = reader.getAttributeValue(null, ATTR_VALUE);
		String attributeType = reader.getAttributeValue(null, ATTR_TYPE);

		check(attributeType == null, "Expected a directive to have no type: %s:%s=%s", attributeName, attributeType,
				attributeValue);

		capReqBuilder.addDirective(attributeName, attributeValue);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy