/* * 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 * * http://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.felix.bundlerepository.impl; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import org.kxml2.io.KXmlParser; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; /** * Repository XML xml based on StaX */ public class PullParser extends RepositoryParser { public PullParser() { } public RepositoryImpl parseRepository(InputStream is, String repositoryURI) throws Exception { XmlPullParser reader = new KXmlParser(); // The spec-based Repository XML uses namespaces, so switch this on... reader.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); reader.setInput(is, null); int event = reader.nextTag(); if (event != XmlPullParser.START_TAG || !REPOSITORY.equals(reader.getName())) { throw new Exception("Expected element 'repository' at the root of the document"); } RepositoryImpl repo; if ("http://www.osgi.org/xmlns/repository/v1.0.0".equals(reader.getNamespace())) // TODO there are a bunch of other methods here that create a parser, should they be updated too? // at the very least they should be made namespace-aware too, so that parsing is the same no matter // how its initiated. return SpecXMLPullParser.parse(reader, repositoryURI); else // We're parsing the old repo = parse(reader); repo.setURI(repositoryURI); return repo; } public RepositoryImpl parseRepository(Reader r) throws Exception { XmlPullParser reader = new KXmlParser(); reader.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); reader.setInput(r); int event = reader.nextTag(); if (event != XmlPullParser.START_TAG || !REPOSITORY.equals(reader.getName())) { throw new Exception("Expected element 'repository' at the root of the document"); } return parse(reader); } public ResourceImpl parseResource(Reader r) throws Exception { XmlPullParser reader = new KXmlParser(); reader.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); reader.setInput(r); int event = reader.nextTag(); if (event != XmlPullParser.START_TAG || !RESOURCE.equals(reader.getName())) { throw new Exception("Expected element 'resource'"); } return parseResource(reader); } public CapabilityImpl parseCapability(Reader r) throws Exception { XmlPullParser reader = new KXmlParser(); reader.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); reader.setInput(r); int event = reader.nextTag(); if (event != XmlPullParser.START_TAG || !CAPABILITY.equals(reader.getName())) { throw new Exception("Expected element 'capability'"); } return parseCapability(reader); } public PropertyImpl parseProperty(Reader r) throws Exception { XmlPullParser reader = new KXmlParser(); reader.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); reader.setInput(r); int event = reader.nextTag(); if (event != XmlPullParser.START_TAG || !P.equals(reader.getName())) { throw new Exception("Expected element 'p'"); } return parseProperty(reader); } public RequirementImpl parseRequirement(Reader r) throws Exception { XmlPullParser reader = new KXmlParser(); reader.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); reader.setInput(r); int event = reader.nextTag(); if (event != XmlPullParser.START_TAG || !REQUIRE.equals(reader.getName())) { throw new Exception("Expected element 'require'"); } return parseRequire(reader); } public RepositoryImpl parse(XmlPullParser reader) throws Exception { RepositoryImpl repository = new RepositoryImpl(); for (int i = 0, nb = reader.getAttributeCount(); i < nb; i++) { String name = reader.getAttributeName(i); String value = reader.getAttributeValue(i); if (NAME.equals(name)) { repository.setName(value); } else if (LASTMODIFIED.equals(name)) { repository.setLastModified(value); } } int event; while ((event = reader.nextTag()) == XmlPullParser.START_TAG) { String element = reader.getName(); if (REFERRAL.equals(element)) { Referral referral = parseReferral(reader); repository.addReferral(referral); } else if (RESOURCE.equals(element)) { ResourceImpl resource = parseResource(reader); repository.addResource(resource); } else { ignoreTag(reader); } } // Sanity check sanityCheckEndElement(reader, event, REPOSITORY); return repository; } static void sanityCheckEndElement(XmlPullParser reader, int event, String element) { if (event != XmlPullParser.END_TAG || !element.equals(reader.getName())) { throw new IllegalStateException("Unexpected state while finishing element " + element); } } public Referral parseReferral(XmlPullParser reader) throws Exception { Referral referral = new Referral(); for (int i = 0, nb = reader.getAttributeCount(); i < nb; i++) { String name = reader.getAttributeName(i); String value = reader.getAttributeValue(i); if (DEPTH.equals(name)) { referral.setDepth(value); } else if (URL.equals(name)) { referral.setUrl(value); } } sanityCheckEndElement(reader, reader.nextTag(), REFERRAL); return referral; } public ResourceImpl parseResource(XmlPullParser reader) throws Exception { ResourceImpl resource = new ResourceImpl(); try { for (int i = 0, nb = reader.getAttributeCount(); i < nb; i++) { resource.put(reader.getAttributeName(i), reader.getAttributeValue(i)); } int event; while ((event = reader.nextTag()) == XmlPullParser.START_TAG) { String element = reader.getName(); if (CATEGORY.equals(element)) { String category = parseCategory(reader); resource.addCategory(category); } else if (CAPABILITY.equals(element)) { CapabilityImpl capability = parseCapability(reader); resource.addCapability(capability); } else if (REQUIRE.equals(element)) { RequirementImpl requirement = parseRequire(reader); resource.addRequire(requirement); } else { StringBuffer sb = null; String type = reader.getAttributeValue(null, "type"); while ((event = reader.next()) != XmlPullParser.END_TAG) { switch (event) { case XmlPullParser.START_TAG: throw new Exception("Unexpected element inside <require/> element"); case XmlPullParser.TEXT: if (sb == null) { sb = new StringBuffer(); } sb.append(reader.getText()); break; } } if (sb != null) { resource.put(element, sb.toString().trim(), type); } } } // Sanity check if (event != XmlPullParser.END_TAG || !RESOURCE.equals(reader.getName())) { throw new Exception("Unexpected state"); } return resource; } catch (Exception e) { throw new Exception("Error while parsing resource " + resource.getId() + " at line " + reader.getLineNumber() + " and column " + reader.getColumnNumber(), e); } } public String parseCategory(XmlPullParser reader) throws IOException, XmlPullParserException { String id = null; for (int i = 0, nb = reader.getAttributeCount(); i < nb; i++) { if (ID.equals(reader.getAttributeName(i))) { id = reader.getAttributeValue(i); } } sanityCheckEndElement(reader, reader.nextTag(), CATEGORY); return id; } public CapabilityImpl parseCapability(XmlPullParser reader) throws Exception { CapabilityImpl capability = new CapabilityImpl(); for (int i = 0, nb = reader.getAttributeCount(); i < nb; i++) { String name = reader.getAttributeName(i); String value = reader.getAttributeValue(i); if (NAME.equals(name)) { capability.setName(value); } } int event; while ((event = reader.nextTag()) == XmlPullParser.START_TAG) { String element = reader.getName(); if (P.equals(element)) { PropertyImpl prop = parseProperty(reader); capability.addProperty(prop); } else { ignoreTag(reader); } } // Sanity check sanityCheckEndElement(reader, event, CAPABILITY); return capability; } public PropertyImpl parseProperty(XmlPullParser reader) throws Exception { String n = null, t = null, v = null; for (int i = 0, nb = reader.getAttributeCount(); i < nb; i++) { String name = reader.getAttributeName(i); String value = reader.getAttributeValue(i); if (N.equals(name)) { n = value; } else if (T.equals(name)) { t = value; } else if (V.equals(name)) { v = value; } } PropertyImpl prop = new PropertyImpl(n, t, v); // Sanity check sanityCheckEndElement(reader, reader.nextTag(), P); return prop; } public RequirementImpl parseRequire(XmlPullParser reader) throws Exception { RequirementImpl requirement = new RequirementImpl(); for (int i = 0, nb = reader.getAttributeCount(); i < nb; i++) { String name = reader.getAttributeName(i); String value = reader.getAttributeValue(i); if (NAME.equals(name)) { requirement.setName(value); } else if (FILTER.equals(name)) { requirement.setFilter(value); } else if (EXTEND.equals(name)) { requirement.setExtend(Boolean.valueOf(value).booleanValue()); } else if (MULTIPLE.equals(name)) { requirement.setMultiple(Boolean.valueOf(value).booleanValue()); } else if (OPTIONAL.equals(name)) { requirement.setOptional(Boolean.valueOf(value).booleanValue()); } } int event; StringBuffer sb = null; while ((event = reader.next()) != XmlPullParser.END_TAG) { switch (event) { case XmlPullParser.START_TAG: throw new Exception("Unexpected element inside <require/> element"); case XmlPullParser.TEXT: if (sb == null) { sb = new StringBuffer(); } sb.append(reader.getText()); break; } } if (sb != null) { requirement.addText(sb.toString()); } // Sanity check sanityCheckEndElement(reader, event, REQUIRE); return requirement; } static void ignoreTag(XmlPullParser reader) throws IOException, XmlPullParserException { int level = 1; while (level > 0) { int eventType = reader.next(); if (eventType == XmlPullParser.START_TAG) { level++; } else if (eventType == XmlPullParser.END_TAG) { level--; } } } }