/* * 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.chemistry.opencmis.client.bindings.spi.atompub; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.CONTENT_SRC; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.LINK_HREF; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.LINK_REL; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.LINK_TYPE; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_ACL; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_ALLOWABLEACTIONS; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_CHILDREN; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_COLLECTION; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_COLLECTION_TYPE; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_CONTENT; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_ENTRY; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_FEED; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_HTML; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_LINK; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_NUM_ITEMS; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_OBJECT; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_PATH_SEGMENT; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_RELATIVE_PATH_SEGMENT; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_REPOSITORY_INFO; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_SERVICE; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_TEMPLATE_TEMPLATE; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_TEMPLATE_TYPE; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_TYPE; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_URI_TEMPLATE; import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_WORKSPACE; import java.io.InputStream; import java.math.BigInteger; import java.util.HashMap; import java.util.Map; import javax.xml.namespace.QName; import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomAcl; import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomAllowableActions; import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomBase; import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomElement; import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomEntry; import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomFeed; import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomLink; import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.HtmlDoc; import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.RepositoryWorkspace; import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.ServiceDoc; import org.apache.chemistry.opencmis.commons.data.ObjectData; import org.apache.chemistry.opencmis.commons.data.RepositoryInfo; import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition; import org.apache.chemistry.opencmis.commons.impl.IOUtils; import org.apache.chemistry.opencmis.commons.impl.XMLConstants; import org.apache.chemistry.opencmis.commons.impl.XMLConstraints; import org.apache.chemistry.opencmis.commons.impl.XMLConverter; import org.apache.chemistry.opencmis.commons.impl.XMLUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; /** * AtomPub Parser. */ public class AtomPubParser { // public constants public static final String LINK_REL_CONTENT = "@@content@@"; private final InputStream stream; private AtomBase parseResult; public AtomPubParser(InputStream stream) { if (stream == null) { throw new IllegalArgumentException("No stream."); } this.stream = stream; } /** * Parses the stream. */ public void parse() throws XmlPullParserException { XmlPullParser parser = XMLUtils.createParser(stream); try { while (true) { int event = parser.getEventType(); if (event == XmlPullParser.START_TAG) { QName name = new QName(parser.getNamespace(), parser.getName()); if (XMLConstants.NAMESPACE_ATOM.equals(name.getNamespaceURI())) { if (TAG_FEED.equals(name.getLocalPart())) { parseResult = parseFeed(parser); break; } else if (TAG_ENTRY.equals(name.getLocalPart())) { parseResult = parseEntry(parser); break; } } else if (XMLConstants.NAMESPACE_CMIS.equals(name.getNamespaceURI())) { if (TAG_ALLOWABLEACTIONS.equals(name.getLocalPart())) { parseResult = parseAllowableActions(parser); break; } else if (TAG_ACL.equals(name.getLocalPart())) { parseResult = parseACL(parser); break; } } else if (XMLConstants.NAMESPACE_APP.equals(name.getNamespaceURI())) { if (TAG_SERVICE.equals(name.getLocalPart())) { parseResult = parseServiceDoc(parser); break; } } else if (TAG_HTML.equalsIgnoreCase(name.getLocalPart())) { parseResult = new HtmlDoc(); break; } } if (!XMLUtils.next(parser)) { break; } } } finally { // make sure the stream is read and closed in all cases IOUtils.consumeAndClose(stream); } } /** * Return the parse results. */ public AtomBase getResults() { return parseResult; } /** * Parses a service document. */ private static ServiceDoc parseServiceDoc(XmlPullParser parser) throws XmlPullParserException { ServiceDoc result = new ServiceDoc(); XMLUtils.next(parser); while (true) { int event = parser.getEventType(); if (event == XmlPullParser.START_TAG) { QName name = new QName(parser.getNamespace(), parser.getName()); if (XMLConstants.NAMESPACE_APP.equals(name.getNamespaceURI())) { if (TAG_WORKSPACE.equals(name.getLocalPart())) { result.addWorkspace(parseWorkspace(parser)); } else { XMLUtils.skip(parser); } } else { XMLUtils.skip(parser); } } else if (event == XmlPullParser.END_TAG) { break; } else { if (!XMLUtils.next(parser)) { break; } } } return result; } /** * Parses a workspace element in a service document. */ private static RepositoryWorkspace parseWorkspace(XmlPullParser parser) throws XmlPullParserException { RepositoryWorkspace workspace = new RepositoryWorkspace(); XMLUtils.next(parser); while (true) { int event = parser.getEventType(); if (event == XmlPullParser.START_TAG) { AtomElement element = parseWorkspaceElement(parser); // check if we can extract the workspace id if ((element != null) && (element.getObject() instanceof RepositoryInfo)) { workspace.setId(((RepositoryInfo) element.getObject()).getId()); } // add to workspace workspace.addElement(element); } else if (event == XmlPullParser.END_TAG) { break; } else { if (!XMLUtils.next(parser)) { break; } } } XMLUtils.next(parser); return workspace; } /** * Parses an Atom feed. */ private AtomFeed parseFeed(XmlPullParser parser) throws XmlPullParserException { AtomFeed result = new AtomFeed(); XMLUtils.next(parser); while (true) { int event = parser.getEventType(); if (event == XmlPullParser.START_TAG) { QName name = new QName(parser.getNamespace(), parser.getName()); if (XMLConstants.NAMESPACE_ATOM.equals(name.getNamespaceURI())) { if (TAG_LINK.equals(name.getLocalPart())) { result.addElement(parseLink(parser)); } else if (TAG_ENTRY.equals(name.getLocalPart())) { result.addEntry(parseEntry(parser)); } else { XMLUtils.skip(parser); } } else if (XMLConstants.NAMESPACE_RESTATOM.equals(name.getNamespaceURI())) { if (TAG_NUM_ITEMS.equals(name.getLocalPart())) { result.addElement(parseBigInteger(parser)); } else { XMLUtils.skip(parser); } } else { XMLUtils.skip(parser); } } else if (event == XmlPullParser.END_TAG) { break; } else { if (!XMLUtils.next(parser)) { break; } } } XMLUtils.next(parser); return result; } /** * Parses an Atom entry. * * @throws XmlPullParserException */ private AtomEntry parseEntry(XmlPullParser parser) throws XmlPullParserException { AtomEntry result = new AtomEntry(); XMLUtils.next(parser); // walk through all tags in entry while (true) { int event = parser.getEventType(); if (event == XmlPullParser.START_TAG) { AtomElement element = parseElement(parser); if (element != null) { // add to entry result.addElement(element); // find and set object id if (element.getObject() instanceof ObjectData) { result.setId(((ObjectData) element.getObject()).getId()); } else if (element.getObject() instanceof TypeDefinition) { result.setId(((TypeDefinition) element.getObject()).getId()); } } } else if (event == XmlPullParser.END_TAG) { break; } else { if (!XMLUtils.next(parser)) { break; } } } XMLUtils.next(parser); return result; } /** * Parses an Allowable Actions document. */ private static AtomAllowableActions parseAllowableActions(XmlPullParser parser) throws XmlPullParserException { return new AtomAllowableActions(XMLConverter.convertAllowableActions(parser)); } /** * Parses an ACL document. */ private static AtomAcl parseACL(XmlPullParser parser) throws XmlPullParserException { return new AtomAcl(XMLConverter.convertAcl(parser)); } /** * Parses an element. * * @throws XmlPullParserException */ private AtomElement parseElement(XmlPullParser parser) throws XmlPullParserException { QName name = new QName(parser.getNamespace(), parser.getName()); if (XMLConstants.NAMESPACE_RESTATOM.equals(name.getNamespaceURI())) { if (TAG_OBJECT.equals(name.getLocalPart())) { return new AtomElement(name, XMLConverter.convertObject(parser)); } else if (TAG_PATH_SEGMENT.equals(name.getLocalPart()) || TAG_RELATIVE_PATH_SEGMENT.equals(name.getLocalPart())) { return parseText(parser); } else if (TAG_TYPE.equals(name.getLocalPart())) { return new AtomElement(name, XMLConverter.convertTypeDefinition(parser)); } else if (TAG_CHILDREN.equals(name.getLocalPart())) { return parseChildren(parser); } } else if (XMLConstants.NAMESPACE_ATOM.equals(name.getNamespaceURI())) { if (TAG_LINK.equals(name.getLocalPart())) { return parseLink(parser); } else if (TAG_CONTENT.equals(name.getLocalPart())) { return parseAtomContentSrc(parser); } } // we don't know it - skip it XMLUtils.skip(parser); return null; } /** * Parses a children element. */ private AtomElement parseChildren(XmlPullParser parser) throws XmlPullParserException { AtomElement result = null; QName childName = new QName(parser.getNamespace(), parser.getName()); XMLUtils.next(parser); // walk through the children tag while (true) { int event = parser.getEventType(); if (event == XmlPullParser.START_TAG) { QName name = new QName(parser.getNamespace(), parser.getName()); if (XMLConstants.NAMESPACE_ATOM.equals(name.getNamespaceURI())) { if (TAG_FEED.equals(name.getLocalPart())) { result = new AtomElement(childName, parseFeed(parser)); } else { XMLUtils.skip(parser); } } else { XMLUtils.skip(parser); } } else if (event == XmlPullParser.END_TAG) { break; } else { if (!XMLUtils.next(parser)) { break; } } } XMLUtils.next(parser); return result; } /** * Parses a workspace element. */ private static AtomElement parseWorkspaceElement(XmlPullParser parser) throws XmlPullParserException { QName name = new QName(parser.getNamespace(), parser.getName()); if (XMLConstants.NAMESPACE_RESTATOM.equals(name.getNamespaceURI())) { if (TAG_REPOSITORY_INFO.equals(name.getLocalPart())) { return new AtomElement(name, XMLConverter.convertRepositoryInfo(parser)); } else if (TAG_URI_TEMPLATE.equals(name.getLocalPart())) { return parseTemplate(parser); } } else if (XMLConstants.NAMESPACE_ATOM.equals(name.getNamespaceURI())) { if (TAG_LINK.equals(name.getLocalPart())) { return parseLink(parser); } } else if (XMLConstants.NAMESPACE_APP.equals(name.getNamespaceURI())) { if (TAG_COLLECTION.equals(name.getLocalPart())) { return parseCollection(parser); } } // we don't know it - skip it XMLUtils.skip(parser); return null; } /** * Parses a collection tag. */ private static AtomElement parseCollection(XmlPullParser parser) throws XmlPullParserException { QName name = new QName(parser.getNamespace(), parser.getName()); Map<String, String> result = new HashMap<String, String>(); result.put("href", parser.getAttributeValue(null, "href")); XMLUtils.next(parser); while (true) { int event = parser.getEventType(); if (event == XmlPullParser.START_TAG) { QName tagName = new QName(parser.getNamespace(), parser.getName()); if (XMLConstants.NAMESPACE_RESTATOM.equals(tagName.getNamespaceURI()) && TAG_COLLECTION_TYPE.equals(tagName.getLocalPart())) { result.put("collectionType", XMLUtils.readText(parser, XMLConstraints.MAX_STRING_LENGTH)); } else { XMLUtils.skip(parser); } } else if (event == XmlPullParser.END_TAG) { break; } else { if (!XMLUtils.next(parser)) { break; } } } XMLUtils.next(parser); return new AtomElement(name, result); } /** * Parses a template tag. */ private static AtomElement parseTemplate(XmlPullParser parser) throws XmlPullParserException { QName name = new QName(parser.getNamespace(), parser.getName()); Map<String, String> result = new HashMap<String, String>(); XMLUtils.next(parser); while (true) { int event = parser.getEventType(); if (event == XmlPullParser.START_TAG) { QName tagName = new QName(parser.getNamespace(), parser.getName()); if (XMLConstants.NAMESPACE_RESTATOM.equals(tagName.getNamespaceURI())) { if (TAG_TEMPLATE_TEMPLATE.equals(tagName.getLocalPart())) { result.put("template", XMLUtils.readText(parser, XMLConstraints.MAX_STRING_LENGTH)); } else if (TAG_TEMPLATE_TYPE.equals(tagName.getLocalPart())) { result.put("type", XMLUtils.readText(parser, XMLConstraints.MAX_STRING_LENGTH)); } else { XMLUtils.skip(parser); } } else { XMLUtils.skip(parser); } } else if (event == XmlPullParser.END_TAG) { break; } else { if (!XMLUtils.next(parser)) { break; } } } XMLUtils.next(parser); return new AtomElement(name, result); } /** * Parses a link tag. */ private static AtomElement parseLink(XmlPullParser parser) throws XmlPullParserException { QName name = new QName(parser.getNamespace(), parser.getName()); AtomLink result = new AtomLink(); // save attributes for (int i = 0; i < parser.getAttributeCount(); i++) { if (LINK_REL.equals(parser.getAttributeName(i))) { result.setRel(parser.getAttributeValue(i)); } else if (LINK_HREF.equals(parser.getAttributeName(i))) { result.setHref(parser.getAttributeValue(i)); } else if (LINK_TYPE.equals(parser.getAttributeName(i))) { result.setType(parser.getAttributeValue(i)); } } // skip enclosed tags, if any XMLUtils.skip(parser); return new AtomElement(name, result); } /** * Parses a link tag. */ private static AtomElement parseAtomContentSrc(XmlPullParser parser) throws XmlPullParserException { QName name = new QName(parser.getNamespace(), parser.getName()); AtomLink result = new AtomLink(); result.setRel(LINK_REL_CONTENT); // save attributes for (int i = 0; i < parser.getAttributeCount(); i++) { if (CONTENT_SRC.equals(parser.getAttributeName(i))) { result.setHref(parser.getAttributeValue(i)); } } // skip enclosed tags, if any XMLUtils.skip(parser); return new AtomElement(name, result); } /** * Parses a text tag. * * @throws XmlPullParserException */ private static AtomElement parseText(XmlPullParser parser) throws XmlPullParserException { QName name = new QName(parser.getNamespace(), parser.getName()); return new AtomElement(name, XMLUtils.readText(parser, XMLConstraints.MAX_STRING_LENGTH)); } /** * Parses a text tag and convert it into an integer. */ private static AtomElement parseBigInteger(XmlPullParser parser) throws XmlPullParserException { QName name = new QName(parser.getNamespace(), parser.getName()); return new AtomElement(name, new BigInteger(XMLUtils.readText(parser, XMLConstraints.MAX_STRING_LENGTH))); } }