diff -r 88b85470e72c -r f50545b5e2f1 src/share/jaxws_classes/com/sun/tools/internal/jxc/ConfigReader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/jaxws_classes/com/sun/tools/internal/jxc/ConfigReader.java Tue Mar 06 16:09:35 2012 -0800 @@ -0,0 +1,283 @@ +/* + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.internal.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 javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import com.sun.tools.internal.jxc.gen.config.Config; +import com.sun.tools.internal.jxc.gen.config.Schema; +import com.sun.tools.internal.xjc.SchemaCache; +import com.sun.tools.internal.xjc.api.Reference; +import com.sun.tools.internal.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 annotation processing + * 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 annotation processing. + * + * @author Bhakti Mehta (bhakti.mehta@sun.com) + */ +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 ProcessingEnvironment 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(ProcessingEnvironment env, Collection 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 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 rootClasses) { + + List includeRegexList = config.getClasses().getIncludes(); + List excludeRegexList = config.getClasses().getExcludes(); + + OUTER: + for (TypeElement typeDecl : rootClasses) { + + String qualifiedName = typeDecl.getQualifiedName().toString(); + + 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 annotation processing + * @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 (bhakti.mehta@sun.com) + */ + 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); + + } + + } +}