aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.tools.internal.jxc; aoqi@0: aoqi@0: import com.sun.tools.internal.jxc.ap.Options; aoqi@0: import java.io.File; aoqi@0: import java.io.IOException; aoqi@0: import java.util.Collection; aoqi@0: import java.util.HashMap; aoqi@0: import java.util.HashSet; aoqi@0: import java.util.List; aoqi@0: import java.util.Map; aoqi@0: import java.util.Set; aoqi@0: import java.util.regex.Matcher; aoqi@0: import java.util.regex.Pattern; aoqi@0: aoqi@0: import javax.xml.bind.SchemaOutputResolver; aoqi@0: import javax.xml.parsers.ParserConfigurationException; aoqi@0: import javax.xml.parsers.SAXParserFactory; aoqi@0: import javax.xml.transform.Result; aoqi@0: import javax.xml.transform.stream.StreamResult; aoqi@0: import javax.xml.validation.ValidatorHandler; aoqi@0: aoqi@0: import javax.annotation.processing.ProcessingEnvironment; aoqi@0: import javax.lang.model.element.TypeElement; aoqi@0: import com.sun.tools.internal.jxc.gen.config.Config; aoqi@0: import com.sun.tools.internal.jxc.gen.config.Schema; aoqi@0: import com.sun.tools.internal.xjc.SchemaCache; aoqi@0: import com.sun.tools.internal.xjc.api.Reference; aoqi@0: import com.sun.tools.internal.xjc.util.ForkContentHandler; aoqi@0: aoqi@0: import com.sun.xml.internal.bind.v2.util.XmlFactory; aoqi@0: import org.xml.sax.ErrorHandler; aoqi@0: import org.xml.sax.InputSource; aoqi@0: import org.xml.sax.SAXException; aoqi@0: import org.xml.sax.XMLReader; aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * This reads the config files passed by the user to annotation processing aoqi@0: * and obtains a list of classes that need to be included aoqi@0: * for a particular config from the set of classes passed aoqi@0: * by the user to annotation processing. aoqi@0: * aoqi@0: * @author Bhakti Mehta (bhakti.mehta@sun.com) aoqi@0: */ aoqi@0: public final class ConfigReader { aoqi@0: aoqi@0: /** aoqi@0: * The set of classes to be passed to XJC aoqi@0: * aoqi@0: */ aoqi@0: private final Set classesToBeIncluded = new HashSet(); aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * The SchemaOutputResolver used to generate the schemas aoqi@0: */ aoqi@0: private final SchemaOutputResolver schemaOutputResolver; aoqi@0: aoqi@0: private final ProcessingEnvironment env; aoqi@0: aoqi@0: /** aoqi@0: * aoqi@0: * @param classes aoqi@0: * The set of classes passed to the AnnotationProcessor aoqi@0: * @param xmlFile aoqi@0: * The configuration file. aoqi@0: * @throws SAXException aoqi@0: * If this is thrown, the error has already been reported. aoqi@0: * @throws IOException aoqi@0: * If any IO errors occur. aoqi@0: */ aoqi@0: public ConfigReader(ProcessingEnvironment env, Collection classes, File xmlFile, ErrorHandler errorHandler) throws SAXException, IOException { aoqi@0: this.env = env; aoqi@0: Config config = parseAndGetConfig(xmlFile, errorHandler, env.getOptions().containsKey(Options.DISABLE_XML_SECURITY)); aoqi@0: checkAllClasses(config,classes); aoqi@0: String path = xmlFile.getAbsolutePath(); aoqi@0: String xmlPath = path.substring(0,path.lastIndexOf(File.separatorChar)); aoqi@0: schemaOutputResolver = createSchemaOutputResolver(config,xmlPath); aoqi@0: aoqi@0: } aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * This creates a regular expression aoqi@0: * for the user pattern , matches the input classes aoqi@0: * passed by the user and returns the final aoqi@0: * list of classes that need to be included for a config file aoqi@0: * after applying those patterns aoqi@0: * aoqi@0: */ aoqi@0: public Collection getClassesToBeIncluded() { aoqi@0: return classesToBeIncluded; aoqi@0: } aoqi@0: aoqi@0: private void checkAllClasses(Config config, Collection rootClasses) { aoqi@0: aoqi@0: List includeRegexList = config.getClasses().getIncludes(); aoqi@0: List excludeRegexList = config.getClasses().getExcludes(); aoqi@0: aoqi@0: OUTER: aoqi@0: for (TypeElement typeDecl : rootClasses) { aoqi@0: aoqi@0: String qualifiedName = typeDecl.getQualifiedName().toString(); aoqi@0: aoqi@0: for (Pattern pattern : excludeRegexList) { aoqi@0: boolean match = checkPatternMatch(qualifiedName, pattern); aoqi@0: if (match) aoqi@0: continue OUTER; // excluded aoqi@0: } aoqi@0: aoqi@0: for (Pattern pattern : includeRegexList) { aoqi@0: boolean match = checkPatternMatch(qualifiedName, pattern); aoqi@0: if (match) { aoqi@0: classesToBeIncluded.add(new Reference(typeDecl,env)); aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * This returns the SchemaOutputResolver to generate the schemas aoqi@0: */ aoqi@0: public SchemaOutputResolver getSchemaOutputResolver(){ aoqi@0: return schemaOutputResolver; aoqi@0: } aoqi@0: aoqi@0: private SchemaOutputResolver createSchemaOutputResolver(Config config, String xmlpath) { aoqi@0: File baseDir = new File(xmlpath, config.getBaseDir().getPath()); aoqi@0: SchemaOutputResolverImpl outResolver = new SchemaOutputResolverImpl (baseDir); aoqi@0: aoqi@0: for( Schema schema : (List)config.getSchema() ) { aoqi@0: String namespace = schema.getNamespace(); aoqi@0: File location = schema.getLocation(); aoqi@0: outResolver.addSchemaInfo(namespace,location); aoqi@0: } aoqi@0: return outResolver; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * This will check if the qualified name matches the pattern aoqi@0: * aoqi@0: * @param qualifiedName aoqi@0: * The qualified name of the TypeDeclaration aoqi@0: * @param pattern aoqi@0: * The pattern obtained from the users input aoqi@0: * aoqi@0: */ aoqi@0: private boolean checkPatternMatch(String qualifiedName, Pattern pattern) { aoqi@0: Matcher matcher = pattern.matcher(qualifiedName); aoqi@0: return matcher.matches(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * Lazily parsed schema for the binding file. aoqi@0: */ aoqi@0: private static SchemaCache configSchema = new SchemaCache(Config.class.getResource("config.xsd")); aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * Parses an xml config file and returns a Config object. aoqi@0: * aoqi@0: * @param xmlFile aoqi@0: * The xml config file which is passed by the user to annotation processing aoqi@0: * @return aoqi@0: * A non null Config object aoqi@0: */ aoqi@0: private Config parseAndGetConfig (File xmlFile, ErrorHandler errorHandler, boolean disableSecureProcessing) throws SAXException, IOException { aoqi@0: XMLReader reader; aoqi@0: try { aoqi@0: SAXParserFactory factory = XmlFactory.createParserFactory(disableSecureProcessing); aoqi@0: reader = factory.newSAXParser().getXMLReader(); aoqi@0: } catch (ParserConfigurationException e) { aoqi@0: // in practice this will never happen aoqi@0: throw new Error(e); aoqi@0: } aoqi@0: NGCCRuntimeEx runtime = new NGCCRuntimeEx(errorHandler); aoqi@0: aoqi@0: // set up validator aoqi@0: ValidatorHandler validator = configSchema.newValidator(); aoqi@0: validator.setErrorHandler(errorHandler); aoqi@0: aoqi@0: // the validator will receive events first, then the parser. aoqi@0: reader.setContentHandler(new ForkContentHandler(validator,runtime)); aoqi@0: aoqi@0: reader.setErrorHandler(errorHandler); aoqi@0: Config config = new Config(runtime); aoqi@0: runtime.setRootHandler(config); aoqi@0: reader.parse(new InputSource(xmlFile.toURL().toExternalForm())); aoqi@0: runtime.reset(); aoqi@0: aoqi@0: return config; aoqi@0: } aoqi@0: /** aoqi@0: * Controls where the JAXB RI puts the generates aoqi@0: * schema files. aoqi@0: * @author aoqi@0: * Bhakti Mehta (bhakti.mehta@sun.com) aoqi@0: */ aoqi@0: private static final class SchemaOutputResolverImpl extends SchemaOutputResolver{ aoqi@0: aoqi@0: /** aoqi@0: * Directory to which we put the rest of the files. aoqi@0: * Never be null. aoqi@0: */ aoqi@0: private final File baseDir; aoqi@0: aoqi@0: /** aoqi@0: * Namespace URI to the location of the schema. aoqi@0: * This captures what the user specifies. aoqi@0: */ aoqi@0: private final Map schemas = new HashMap(); aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * Decides where the schema file (of the given namespace URI) aoqi@0: * will be written, and return it as a {@link Result} object. aoqi@0: * aoqi@0: */ aoqi@0: public Result createOutput( String namespaceUri, String suggestedFileName ) { aoqi@0: aoqi@0: // the user's preference takes a precedence aoqi@0: if(schemas.containsKey(namespaceUri)) { aoqi@0: File loc = schemas.get(namespaceUri); aoqi@0: if(loc==null) return null; // specifically not to generate a schema aoqi@0: aoqi@0: // create directories if necessary. we've already checked that the baseDir aoqi@0: // exists, so this should be no surprise to users. aoqi@0: loc.getParentFile().mkdirs(); aoqi@0: aoqi@0: return new StreamResult(loc); // generate into a file the user specified. aoqi@0: } aoqi@0: aoqi@0: // if the user didn't say anything about this namespace, aoqi@0: // generate it into the default directory with a default name. aoqi@0: aoqi@0: File schemaFile = new File (baseDir, suggestedFileName); aoqi@0: // The systemId for the result will be schemaFile aoqi@0: return new StreamResult(schemaFile); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: public SchemaOutputResolverImpl(File baseDir) { aoqi@0: assert baseDir!=null; aoqi@0: this.baseDir = baseDir; aoqi@0: } aoqi@0: aoqi@0: public void addSchemaInfo(String namespaceUri, File location) { aoqi@0: if (namespaceUri == null ) aoqi@0: //generate elements in no namespace aoqi@0: namespaceUri = ""; aoqi@0: schemas.put(namespaceUri, location); aoqi@0: aoqi@0: } aoqi@0: aoqi@0: } aoqi@0: }