com.sun.tools.jxc.ConfigReader Maven / Gradle / Ivy
The newest version!
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.tools.jxc;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.bind.SchemaOutputResolver;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;
import javax.xml.validation.ValidatorHandler;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.declaration.TypeDeclaration;
import com.sun.tools.jxc.gen.config.Config;
import com.sun.tools.jxc.gen.config.Schema;
import com.sun.tools.xjc.SchemaCache;
import com.sun.tools.xjc.api.Reference;
import com.sun.tools.xjc.util.ForkContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
/**
* This reads the config files passed by the user to apt
* and obtains a list of classes that need to be included
* for a particular config from the set of classes passed
* by the user to apt.
*
* @author Bhakti Mehta ([email protected])
*/
public final class ConfigReader {
/**
* The set of classes to be passed to XJC
*
*/
private final Set classesToBeIncluded = new HashSet();;
/**
* The SchemaOutputResolver used to generate the schemas
*/
private final SchemaOutputResolver schemaOutputResolver;
private final AnnotationProcessorEnvironment env;
/**
*
* @param classes
* The set of classes passed to the AnnotationProcessor
* @param xmlFile
* The configuration file.
* @throws SAXException
* If this is thrown, the error has already been reported.
* @throws IOException
* If any IO errors occur.
*/
public ConfigReader( AnnotationProcessorEnvironment env, Collection extends TypeDeclaration> classes, File xmlFile, ErrorHandler errorHandler)throws SAXException,IOException{
this.env = env;
Config config = parseAndGetConfig(xmlFile,errorHandler);
checkAllClasses(config,classes);
String path = xmlFile.getAbsolutePath();
String xmlPath = path.substring(0,path.lastIndexOf(File.separatorChar));
schemaOutputResolver = createSchemaOutputResolver(config,xmlPath);
}
/**
* This creates creates a regular expression
* for the user pattern , matches the input classes
* passed by the user and returns the final
* list of classes that need to be included for a config file
* after applying those patterns
*
*/
public Collection getClassesToBeIncluded() {
return classesToBeIncluded;
}
private void checkAllClasses(Config config ,Collection extends TypeDeclaration> rootClasses){
List includeRegexList = config.getClasses().getIncludes();
List excludeRegexList = config.getClasses().getExcludes();
OUTER:
for (TypeDeclaration typeDecl : rootClasses) {
String qualifiedName = typeDecl.getQualifiedName();
for (Pattern pattern : excludeRegexList) {
boolean match = checkPatternMatch(qualifiedName, pattern);
if (match)
continue OUTER; // excluded
}
for (Pattern pattern : includeRegexList) {
boolean match = checkPatternMatch(qualifiedName, pattern);
if (match) {
classesToBeIncluded.add(new Reference(typeDecl,env));
break;
}
}
}
}
/**
* This returns the SchemaOutputResolver to generate the schemas
*/
public SchemaOutputResolver getSchemaOutputResolver(){
return schemaOutputResolver;
}
private SchemaOutputResolver createSchemaOutputResolver(Config config, String xmlpath) {
File baseDir = new File(xmlpath, config.getBaseDir().getPath());
SchemaOutputResolverImpl schemaOutputResolver = new SchemaOutputResolverImpl (baseDir);
for( Schema schema : (List)config.getSchema() ) {
String namespace = schema.getNamespace();
File location = schema.getLocation();
schemaOutputResolver.addSchemaInfo(namespace,location);
}
return schemaOutputResolver;
}
/**
* This will check if the qualified name matches the pattern
*
* @param qualifiedName
* The qualified name of the TypeDeclaration
* @param pattern
* The pattern obtained from the users input
*
*/
private boolean checkPatternMatch(String qualifiedName, Pattern pattern) {
Matcher matcher = pattern.matcher(qualifiedName);
return matcher.matches();
}
/**
* Lazily parsed schema for the binding file.
*/
private static SchemaCache configSchema = new SchemaCache(Config.class.getResource("config.xsd"));
/**
* Parses an xml config file and returns a Config object.
*
* @param xmlFile
* The xml config file which is passed by the user to apt
* @return
* A non null Config object
*/
private Config parseAndGetConfig (File xmlFile, ErrorHandler errorHandler) throws SAXException, IOException {
XMLReader reader;
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
reader = factory.newSAXParser().getXMLReader();
} catch (ParserConfigurationException e) {
// in practice this will never happen
throw new Error(e);
}
NGCCRuntimeEx runtime = new NGCCRuntimeEx(errorHandler);
// set up validator
ValidatorHandler validator = configSchema.newValidator();
validator.setErrorHandler(errorHandler);
// the validator will receive events first, then the parser.
reader.setContentHandler(new ForkContentHandler(validator,runtime));
reader.setErrorHandler(errorHandler);
Config config = new Config(runtime);
runtime.setRootHandler(config);
reader.parse(new InputSource(xmlFile.toURL().toExternalForm()));
runtime.reset();
return config;
}
/**
* Controls where the JAXB RI puts the generates
* schema files.
* @author
* Bhakti Mehta ([email protected])
*/
private static final class SchemaOutputResolverImpl extends SchemaOutputResolver{
/**
* Directory to which we put the rest of the files.
* Never be null.
*/
private final File baseDir;
/**
* Namespace URI to the location of the schema.
* This captures what the user specifies.
*/
private final Map schemas = new HashMap();
/**
* Decides where the schema file (of the given namespace URI)
* will be written, and return it as a {@link Result} object.
*
*/
public Result createOutput( String namespaceUri, String suggestedFileName ) {
// the user's preference takes a precedence
if(schemas.containsKey(namespaceUri)) {
File loc = schemas.get(namespaceUri);
if(loc==null) return null; // specifically not to generate a schema
// create directories if necessary. we've already checked that the baseDir
// exists, so this should be no surprise to users.
loc.getParentFile().mkdirs();
return new StreamResult(loc); // generate into a file the user specified.
}
// if the user didn't say anything about this namespace,
// generate it into the default directory with a default name.
File schemaFile = new File (baseDir, suggestedFileName);
// The systemId for the result will be schemaFile
return new StreamResult(schemaFile);
}
public SchemaOutputResolverImpl(File baseDir) {
assert baseDir!=null;
this.baseDir = baseDir;
}
public void addSchemaInfo(String namespaceUri, File location) {
if (namespaceUri == null )
//generate elements in no namespace
namespaceUri = "";
schemas.put(namespaceUri, location);
}
}
}