| /* |
| * 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 com.adobe.ac.pmd.rules.core; |
| |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.logging.Logger; |
| |
| import javax.xml.XMLConstants; |
| import javax.xml.namespace.NamespaceContext; |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.xpath.XPath; |
| import javax.xml.xpath.XPathExpressionException; |
| import javax.xml.xpath.XPathFactory; |
| |
| import org.w3c.dom.Document; |
| import org.xml.sax.SAXException; |
| |
| import com.adobe.ac.pmd.IFlexViolation; |
| import com.adobe.ac.utils.StackTraceUtils; |
| |
| public abstract class AbstractXpathRelatedRule extends AbstractFlexRule |
| { |
| public class NamespaceContextMap implements NamespaceContext |
| { |
| private final Map< String, String > prefixMap; |
| |
| /** |
| * Constructor that takes a map of XML prefix-namespaceURI values. A |
| * defensive copy is made of the map. An IllegalArgumentException will be |
| * thrown if the map attempts to remap the standard prefixes defined in |
| * the NamespaceContext contract. |
| * |
| * @param prefixMappings a map of prefix:namespaceURI values |
| */ |
| public NamespaceContextMap( final Map< String, String > prefixMappings ) |
| { |
| prefixMap = createPrefixMap( prefixMappings ); |
| } |
| |
| /** |
| * Convenience constructor. |
| * |
| * @param mappingPairs pairs of prefix-namespaceURI values |
| */ |
| public NamespaceContextMap( final String... mappingPairs ) |
| { |
| this( toMap( mappingPairs ) ); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see |
| * javax.xml.namespace.NamespaceContext#getNamespaceURI(java.lang.String) |
| */ |
| public String getNamespaceURI( final String prefix ) |
| { |
| prefixMap.get( prefix ); |
| return prefixMap.get( prefix ); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see javax.xml.namespace.NamespaceContext#getPrefix(java.lang.String) |
| */ |
| public String getPrefix( final String namespaceURI ) |
| { |
| return null; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see javax.xml.namespace.NamespaceContext#getPrefixes(java.lang.String) |
| */ |
| public Iterator< String > getPrefixes( final String namespaceURI ) |
| { |
| return null; |
| } |
| |
| private void addConstant( final Map< String, String > map, |
| final String prefix, |
| final String nsURI ) |
| { |
| map.put( prefix, |
| nsURI ); |
| } |
| |
| private Map< String, String > createPrefixMap( final Map< String, String > prefixMappings ) |
| { |
| final Map< String, String > map = new LinkedHashMap< String, String >( prefixMappings ); |
| addConstant( map, |
| XMLConstants.XML_NS_PREFIX, |
| XMLConstants.XML_NS_URI ); |
| addConstant( map, |
| XMLConstants.XMLNS_ATTRIBUTE, |
| XMLConstants.XMLNS_ATTRIBUTE_NS_URI ); |
| return Collections.unmodifiableMap( map ); |
| } |
| |
| } |
| |
| protected static final Logger LOGGER = Logger.getLogger( AbstractXpathRelatedRule.class.getName() ); |
| |
| private static Map< String, String > toMap( final String... mappingPairs ) |
| { |
| final Map< String, String > prefixMappings = new LinkedHashMap< String, String >( mappingPairs.length / 2 ); |
| for ( int i = 0; i < mappingPairs.length; i++ ) |
| { |
| prefixMappings.put( mappingPairs[ i ], |
| mappingPairs[ ++i ] ); |
| } |
| return prefixMappings; |
| } |
| |
| /** |
| * @param doc |
| * @param xPath |
| * @return |
| * @throws XPathExpressionException |
| */ |
| protected abstract Object evaluate( final Document doc, |
| final XPath xPath ) throws XPathExpressionException; |
| |
| /* |
| * (non-Javadoc) |
| * @see |
| * com.adobe.ac.pmd.rules.core.AbstractFlexRule#findViolationsInCurrentFile() |
| */ |
| @Override |
| protected List< IFlexViolation > findViolationsInCurrentFile() |
| { |
| final ArrayList< IFlexViolation > violations = new ArrayList< IFlexViolation >(); |
| |
| try |
| { |
| final Document doc = buildDocument(); |
| final XPath xPath = buildXPath(); |
| |
| onEvaluated( violations, |
| doc, |
| xPath ); |
| } |
| catch ( final XPathExpressionException e ) |
| { |
| LOGGER.warning( StackTraceUtils.print( getCurrentFile().getFilename(), |
| e ) ); |
| } |
| catch ( final FileNotFoundException e ) |
| { |
| LOGGER.warning( StackTraceUtils.print( getCurrentFile().getFilename(), |
| e ) ); |
| } |
| catch ( final ParserConfigurationException e ) |
| { |
| LOGGER.warning( StackTraceUtils.print( getCurrentFile().getFilename(), |
| e ) ); |
| } |
| catch ( final SAXException e ) |
| { |
| LOGGER.warning( StackTraceUtils.print( getCurrentFile().getFilename(), |
| e ) ); |
| } |
| catch ( final IOException e ) |
| { |
| LOGGER.warning( StackTraceUtils.print( getCurrentFile().getFilename(), |
| e ) ); |
| } |
| |
| return violations; |
| } |
| |
| /** |
| * @return |
| */ |
| protected abstract String getXPathExpression(); |
| |
| /* |
| * (non-Javadoc) |
| * @see |
| * com.adobe.ac.pmd.rules.core.AbstractFlexRule#isConcernedByTheCurrentFile() |
| */ |
| @Override |
| protected boolean isConcernedByTheCurrentFile() |
| { |
| return getCurrentFile().isMxml(); |
| } |
| |
| /** |
| * @param violations |
| * @param doc |
| * @param xPath |
| * @throws XPathExpressionException |
| */ |
| protected abstract void onEvaluated( final List< IFlexViolation > violations, |
| final Document doc, |
| final XPath xPath ) throws XPathExpressionException; |
| |
| private Document buildDocument() throws ParserConfigurationException, |
| SAXException, |
| IOException |
| { |
| final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); |
| factory.setNamespaceAware( true ); |
| final DocumentBuilder builder = factory.newDocumentBuilder(); |
| return builder.parse( getCurrentFile().getFilePath() ); |
| } |
| |
| private XPath buildXPath() |
| { |
| final XPathFactory xPathFactory = XPathFactory.newInstance(); |
| final XPath xPath = xPathFactory.newXPath(); |
| xPath.setNamespaceContext( new NamespaceContextMap( "mx", "http://www.adobe.com/2006/mxml" ) ); |
| return xPath; |
| } |
| |
| } |