/* * Copyright (C) 2012 The Android Open Source Project * * Licensed 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 com.motorola.studio.android.model.manifest.parser; import java.io.IOException; import java.io.StringReader; import java.util.LinkedList; import java.util.List; import org.apache.xerces.parsers.DOMParser; import org.eclipse.jface.text.IDocument; import org.eclipse.osgi.util.NLS; import org.w3c.dom.Comment; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import com.motorola.studio.android.common.exception.AndroidException; import com.motorola.studio.android.common.log.StudioLogger; import com.motorola.studio.android.common.utilities.i18n.UtilitiesNLS; import com.motorola.studio.android.model.manifest.dom.AndroidManifestNode; import com.motorola.studio.android.model.manifest.dom.AndroidManifestNode.NodeType; /** * Abstract class used to parse an AndroidManifest.xml file */ public abstract class AndroidManifestParser extends AndroidManifestNodeParser { /** * The nodes present on the xml file root */ protected List<AndroidManifestNode> rootNodes = new LinkedList<AndroidManifestNode>(); /** * Parses an IDocument object containing the AndroidManifest.xml into a DOM * * @param document the IDocument object * @throws SAXException When a parsing error occurs * @throws IOException When a reading error occurs */ public void parseDocument(IDocument document) throws AndroidException { Node node; DOMParser domParser = new DOMParser(); rootNodes.clear(); StringReader stringReader = null; try { stringReader = new StringReader(document.get()); domParser.parse(new InputSource(stringReader)); } catch (SAXException e) { String errMsg = NLS.bind(UtilitiesNLS.EXC_AndroidManifestNodeParser_ErrorParsingTheXMLFile, e.getLocalizedMessage()); StudioLogger.error(AndroidManifestParser.class, errMsg, e); throw new AndroidException(errMsg); } catch (IOException e) { String errMsg = NLS.bind(UtilitiesNLS.EXC_AndroidManifestNodeParser_ErrorReadingTheXMLContent, e.getLocalizedMessage()); StudioLogger.error(AndroidManifestParser.class, errMsg, e); throw new AndroidException(errMsg); } finally { if (stringReader != null) { stringReader.close(); } } NodeList children = domParser.getDocument().getChildNodes(); for (int i = 0; i < children.getLength(); i++) { node = children.item(i); parseNode(node, null); } } /** * Parses a XML Node * * @param element The XML Node * @param rootNode The XML Node parent (An AndroidManifestNode that has been parsed) */ private void parseNode(Node node, AndroidManifestNode rootNode) { AndroidManifestNode amNode; NodeType nodeType = identifyNode(node); Node xmlNode; NodeList xmlChildNodes; NamedNodeMap attributes = node.getAttributes(); switch (nodeType) { case Manifest: amNode = parseManifestNode(attributes); break; case UsesPermission: amNode = parseUsesPermissionNode(attributes); break; case Permission: amNode = parsePermissionNode(attributes); break; case PermissionTree: amNode = parsePermissionTreeNode(attributes); break; case PermissionGroup: amNode = parsePermissionGroupNode(attributes); break; case Instrumentation: amNode = parseInstrumentationNode(attributes); break; case UsesSdk: amNode = parseUsesSdkNode(attributes); break; case Application: amNode = parseApplicationNode(attributes); break; case Activity: amNode = parseActivityNode(attributes); break; case IntentFilter: amNode = parseIntentFilterNode(attributes); break; case Action: amNode = parseActionNode(attributes); break; case Category: amNode = parseCategoryNode(attributes); break; case Data: amNode = parseDataNode(attributes); break; case MetaData: amNode = parseMetadataNode(attributes); break; case ActivityAlias: amNode = parseActivityAliasNode(attributes); break; case Service: amNode = parseServiceNode(attributes); break; case Receiver: amNode = parseReceiverNode(attributes); break; case Provider: amNode = parseProviderNode(attributes); break; case GrantUriPermission: amNode = parseGrantUriPermissionNode(attributes); break; case UsesLibrary: amNode = parseUsesLibraryNode(attributes); break; case UsesFeature: amNode = parseUsesFeatureNode(attributes); break; case Comment: amNode = parseCommentNode((Comment) node); break; default: amNode = parseUnknownNode(node.getNodeName(), attributes); } xmlChildNodes = node.getChildNodes(); for (int i = 0; i < xmlChildNodes.getLength(); i++) { xmlNode = xmlChildNodes.item(i); if ((xmlNode instanceof Element) || (xmlNode instanceof Comment)) { parseNode(xmlNode, amNode); } } if (rootNode == null) { rootNodes.add(amNode); } else { rootNode.addChild(amNode); } } /** * Identifies a XML Node type as an AndroidManifestNode type. * * @param xmlNode The XML Node * @return The corresponding AndroidManifestNode type to the XML Node */ private NodeType identifyNode(Node xmlNode) { NodeType identifiedType = NodeType.Unknown; String nodeName = xmlNode.getNodeName(); String thisNodeName; if (xmlNode instanceof Comment) { identifiedType = NodeType.Comment; } else { for (NodeType nodeType : NodeType.values()) { thisNodeName = AndroidManifestNode.getNodeName(nodeType); if (thisNodeName.equalsIgnoreCase(nodeName)) { identifiedType = nodeType; break; } } } return identifiedType; } }