001package org.apache.maven.doxia.xsd; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.File; 023import java.io.IOException; 024import java.io.InputStream; 025import java.io.Reader; 026import java.net.JarURLConnection; 027import java.net.URL; 028import java.util.Collections; 029import java.util.Enumeration; 030import java.util.Hashtable; 031import java.util.Iterator; 032import java.util.List; 033import java.util.Locale; 034import java.util.Map; 035import java.util.jar.JarEntry; 036import java.util.jar.JarFile; 037 038import org.apache.maven.doxia.parser.AbstractXmlParser; 039 040import org.codehaus.plexus.util.FileUtils; 041import org.codehaus.plexus.util.IOUtil; 042import org.codehaus.plexus.util.ReaderFactory; 043import org.codehaus.plexus.util.SelectorUtils; 044import org.codehaus.plexus.util.xml.XmlUtil; 045 046import org.xml.sax.EntityResolver; 047 048/** 049 * Abstract class to validate XML files with DTD or XSD mainly for Doxia namespaces. 050 * 051 * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a> 052 * @version $Id$ 053 * @since 1.0 054 */ 055public abstract class AbstractXmlValidatorTest 056 extends AbstractXmlValidator 057{ 058 059 /** Simple cache mechanism to load test documents. */ 060 private static final Map<String,String> CACHE_DOXIA_TEST_DOCUMENTS = new Hashtable<String,String>(); 061 062 /** Maven resource in the doxia-test-docs-XXX.jar */ 063 private static final String MAVEN_RESOURCE_PATH = "META-INF/maven/org.apache.maven.doxia/doxia-test-docs/"; 064 065 // ---------------------------------------------------------------------- 066 // Protected methods 067 // ---------------------------------------------------------------------- 068 069 /** 070 * @return a non null patterns to includes specific test files. 071 * @see AbstractXmlValidatorTest#getTestDocuments() 072 */ 073 protected abstract String[] getIncludes(); 074 075 /** 076 * @return a map of test resources filtered by patterns from {@link #getIncludes()}. 077 * @throws IOException if any 078 * @see #getIncludes() 079 * @see #getAllTestDocuments() 080 */ 081 protected Map<String, String> getTestDocuments() 082 throws IOException 083 { 084 if ( getIncludes() == null ) 085 { 086 return Collections.emptyMap(); 087 } 088 089 Map<String,String> testDocs = getAllTestDocuments(); 090 Map<String,String> ret = new Hashtable<String,String>(); 091 ret.putAll( testDocs ); 092 for ( Iterator<String> it = testDocs.keySet().iterator(); it.hasNext(); ) 093 { 094 String key = it.next(); 095 096 for ( int i = 0; i < getIncludes().length; i++ ) 097 { 098 if ( !SelectorUtils.matchPath( getIncludes()[i], key.toLowerCase( Locale.ENGLISH ) ) ) 099 { 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}