View Javadoc
1   package org.apache.maven.doxia.xsd;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.Reader;
26  import java.net.JarURLConnection;
27  import java.net.URL;
28  import java.util.Collections;
29  import java.util.Enumeration;
30  import java.util.Hashtable;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.Locale;
34  import java.util.Map;
35  import java.util.jar.JarEntry;
36  import java.util.jar.JarFile;
37  
38  import org.apache.maven.doxia.parser.AbstractXmlParser;
39  
40  import org.codehaus.plexus.util.FileUtils;
41  import org.codehaus.plexus.util.IOUtil;
42  import org.codehaus.plexus.util.ReaderFactory;
43  import org.codehaus.plexus.util.SelectorUtils;
44  import org.codehaus.plexus.util.xml.XmlUtil;
45  
46  import org.xml.sax.EntityResolver;
47  
48  /**
49   * Abstract class to validate XML files with DTD or XSD mainly for Doxia namespaces.
50   *
51   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
52   * @version $Id$
53   * @since 1.0
54   */
55  public abstract class AbstractXmlValidatorTest
56      extends AbstractXmlValidator
57  {
58  
59      /** Simple cache mechanism to load test documents. */
60      private static final Map<String,String> CACHE_DOXIA_TEST_DOCUMENTS = new Hashtable<String,String>();
61  
62      /** Maven resource in the doxia-test-docs-XXX.jar */
63      private static final String MAVEN_RESOURCE_PATH = "META-INF/maven/org.apache.maven.doxia/doxia-test-docs/";
64  
65      // ----------------------------------------------------------------------
66      // Protected methods
67      // ----------------------------------------------------------------------
68  
69      /**
70       * @return a non null patterns to includes specific test files.
71       * @see AbstractXmlValidatorTest#getTestDocuments()
72       */
73      protected abstract String[] getIncludes();
74  
75      /**
76       * @return a map of test resources filtered by patterns from {@link #getIncludes()}.
77       * @throws IOException if any
78       * @see #getIncludes()
79       * @see #getAllTestDocuments()
80       */
81      protected Map<String, String> getTestDocuments()
82          throws IOException
83      {
84          if ( getIncludes() == null )
85          {
86              return Collections.emptyMap();
87          }
88  
89          Map<String,String> testDocs = getAllTestDocuments();
90          Map<String,String> ret = new Hashtable<String,String>();
91          ret.putAll( testDocs );
92          for ( Iterator<String> it = testDocs.keySet().iterator(); it.hasNext(); )
93          {
94              String key = it.next();
95  
96              for ( int i = 0; i < getIncludes().length; i++ )
97              {
98                  if ( !SelectorUtils.matchPath( getIncludes()[i], key.toLowerCase( Locale.ENGLISH ) ) )
99                  {
100                     ret.remove( key );
101                 }
102             }
103         }
104 
105         return ret;
106     }
107 
108     /**
109      * Returns the EntityResolver that is used by the XMLReader for validation.
110      * By default a {@link AbstractXmlParser.CachedFileEntityResolver} is used,
111      * but implementations should override this for performance reasons.
112      *
113      * @return an EntityResolver. Not null.
114      *
115      * @since 1.2
116      */
117     protected EntityResolver getEntityResolver()
118     {
119         return new AbstractXmlParser.CachedFileEntityResolver();
120     }
121 
122     /**
123      * Find test resources in the <code>doxia-test-docs-XXX.jar</code> or in an IDE project.
124      *
125      * @return a map of test resources defined as follow:
126      * <ul>
127      *   <li>key, the full url of test documents,
128      *      i.e. <code>jar:file:/.../doxia-test-docs-XXX.jar!/path/to/resource</code></li>
129      *   <li>value, the content for the resource defined by the key</li>
130      * </ul>
131      * @throws IOException if any
132      */
133     protected static Map<String,String> getAllTestDocuments()
134         throws IOException
135     {
136         if ( CACHE_DOXIA_TEST_DOCUMENTS != null && !CACHE_DOXIA_TEST_DOCUMENTS.isEmpty() )
137         {
138             return Collections.unmodifiableMap( CACHE_DOXIA_TEST_DOCUMENTS );
139         }
140 
141         URL testJar = AbstractXmlValidatorTest.class.getClassLoader().getResource( MAVEN_RESOURCE_PATH );
142         if ( testJar == null )
143         {
144             // maybe in an IDE project
145             testJar = AbstractXmlValidatorTest.class.getClassLoader().getResource( "doxia-site" );
146 
147             if ( testJar == null )
148             {
149                 throw new RuntimeException(
150                         "Could not find the Doxia test documents artefact i.e. doxia-test-docs-XXX.jar" );
151             }
152         }
153 
154         if ( testJar.toString().startsWith( "jar" ))
155             {
156             JarURLConnection conn = (JarURLConnection) testJar.openConnection();
157             JarFile jarFile = conn.getJarFile();
158             for ( Enumeration<JarEntry> e = jarFile.entries(); e.hasMoreElements(); )
159             {
160                 JarEntry entry = e.nextElement();
161 
162                 if ( entry.getName().startsWith( "META-INF" ) )
163                 {
164                     continue;
165                 }
166                 if ( entry.isDirectory() )
167                 {
168                     continue;
169                 }
170 
171                 InputStream in = null;
172                 try
173                 {
174                     in = AbstractXmlValidatorTest.class.getClassLoader().getResource( entry.getName() ).openStream();
175                     String content = IOUtil.toString( in, "UTF-8" );
176                     CACHE_DOXIA_TEST_DOCUMENTS.put( "jar:" + conn.getJarFileURL() + "!/" + entry.getName(), content );
177                 }
178                 finally
179                 {
180                     IOUtil.close( in );
181                 }
182             }
183         }
184         else
185         {
186             // IDE projects
187             File testDocsDir = FileUtils.toFile( testJar ).getParentFile();
188 
189             List<File> files = FileUtils.getFiles( testDocsDir, "**/*.*", FileUtils.getDefaultExcludesAsString(), true );
190             for ( Iterator<File> it = files.iterator(); it.hasNext();)
191             {
192                 File file = new File( it.next().toString() );
193 
194                 if ( file.getAbsolutePath().contains( "META-INF" ) )
195                 {
196                     continue;
197                 }
198 
199                 Reader reader = null;
200                 if ( XmlUtil.isXml( file ))
201                 {
202                     reader = ReaderFactory.newXmlReader( file );
203                 }
204                 else
205                 {
206                     reader = ReaderFactory.newReader( file, "UTF-8" );
207                 }
208 
209                 String content = IOUtil.toString( reader );
210                 CACHE_DOXIA_TEST_DOCUMENTS.put( file.toURI().toString(), content );
211             }
212         }
213 
214         return Collections.unmodifiableMap( CACHE_DOXIA_TEST_DOCUMENTS );
215     }
216 }