From de9d1b17e9cb89fb6f239e591d3092d98a251a2f Mon Sep 17 00:00:00 2001 From: Simon Steiner Date: Tue, 5 Mar 2024 14:31:47 +0000 Subject: FOP-3160: Rename tools to avoid conflicts with core module --- fop-core/pom.xml | 2 +- fop-events/pom.xml | 2 +- .../fop/eventtools/EventConventionException.java | 37 +++ .../fop/eventtools/EventProducerCollector.java | 200 +++++++++++++++ .../fop/eventtools/EventProducerCollectorTask.java | 283 +++++++++++++++++++++ .../apache/fop/tools/EventConventionException.java | 37 --- .../apache/fop/tools/EventProducerCollector.java | 200 --------------- .../fop/tools/EventProducerCollectorTask.java | 283 --------------------- fop/build.xml | 2 +- 9 files changed, 523 insertions(+), 523 deletions(-) create mode 100644 fop-events/src/main/java/org/apache/fop/eventtools/EventConventionException.java create mode 100644 fop-events/src/main/java/org/apache/fop/eventtools/EventProducerCollector.java create mode 100644 fop-events/src/main/java/org/apache/fop/eventtools/EventProducerCollectorTask.java delete mode 100644 fop-events/src/main/java/org/apache/fop/tools/EventConventionException.java delete mode 100644 fop-events/src/main/java/org/apache/fop/tools/EventProducerCollector.java delete mode 100644 fop-events/src/main/java/org/apache/fop/tools/EventProducerCollectorTask.java diff --git a/fop-core/pom.xml b/fop-core/pom.xml index a041e727d..19a6fa90d 100644 --- a/fop-core/pom.xml +++ b/fop-core/pom.xml @@ -283,7 +283,7 @@ - + diff --git a/fop-events/pom.xml b/fop-events/pom.xml index 15e4e9947..1eeea6db0 100644 --- a/fop-events/pom.xml +++ b/fop-events/pom.xml @@ -78,7 +78,7 @@ - + diff --git a/fop-events/src/main/java/org/apache/fop/eventtools/EventConventionException.java b/fop-events/src/main/java/org/apache/fop/eventtools/EventConventionException.java new file mode 100644 index 000000000..63aceb21d --- /dev/null +++ b/fop-events/src/main/java/org/apache/fop/eventtools/EventConventionException.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.eventtools; + +/** + * This exception is used to indicate a violation of the conventions for event producers. + */ +public class EventConventionException extends Exception { + + private static final long serialVersionUID = 117244726033986628L; + + /** + * Creates a new EventConventionException + * @param message the error message + */ + public EventConventionException(String message) { + super(message); + } + +} diff --git a/fop-events/src/main/java/org/apache/fop/eventtools/EventProducerCollector.java b/fop-events/src/main/java/org/apache/fop/eventtools/EventProducerCollector.java new file mode 100644 index 000000000..fc72ffc47 --- /dev/null +++ b/fop-events/src/main/java/org/apache/fop/eventtools/EventProducerCollector.java @@ -0,0 +1,200 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.eventtools; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.apache.fop.events.EventProducer; +import org.apache.fop.events.model.EventMethodModel; +import org.apache.fop.events.model.EventModel; +import org.apache.fop.events.model.EventProducerModel; +import org.apache.fop.events.model.EventSeverity; + +import com.thoughtworks.qdox.JavaDocBuilder; +import com.thoughtworks.qdox.model.DefaultDocletTagFactory; +import com.thoughtworks.qdox.model.DocletTag; +import com.thoughtworks.qdox.model.DocletTagFactory; +import com.thoughtworks.qdox.model.JavaClass; +import com.thoughtworks.qdox.model.JavaMethod; +import com.thoughtworks.qdox.model.JavaParameter; +import com.thoughtworks.qdox.model.Type; + +/** + * Finds EventProducer interfaces and builds the event model for them. + */ +class EventProducerCollector { + + private static final String CLASSNAME_EVENT_PRODUCER = EventProducer.class.getName(); + private static final Map> PRIMITIVE_MAP; + + static { + Map> m = new java.util.HashMap>(); + m.put("boolean", Boolean.class); + m.put("byte", Byte.class); + m.put("char", Character.class); + m.put("short", Short.class); + m.put("int", Integer.class); + m.put("long", Long.class); + m.put("float", Float.class); + m.put("double", Double.class); + PRIMITIVE_MAP = Collections.unmodifiableMap(m); + } + + private DocletTagFactory tagFactory; + private List models = new java.util.ArrayList(); + + /** + * Creates a new EventProducerCollector. + */ + EventProducerCollector() { + this.tagFactory = createDocletTagFactory(); + } + + /** + * Creates the {@link DocletTagFactory} to be used by the collector. + * @return the doclet tag factory + */ + protected DocletTagFactory createDocletTagFactory() { + return new DefaultDocletTagFactory(); + } + + /** + * Scans a file and processes it if it extends the {@link EventProducer} interface. + * @param src the source file (a Java source file) + * @return true if the file contained an EventProducer interface + * @throws IOException if an I/O error occurs + * @throws EventConventionException if the EventProducer conventions are violated + * @throws ClassNotFoundException if a required class cannot be found + */ + public boolean scanFile(File src) + throws IOException, EventConventionException, ClassNotFoundException { + JavaDocBuilder builder = new JavaDocBuilder(this.tagFactory); + builder.addSource(src); + JavaClass[] classes = builder.getClasses(); + boolean eventProducerFound = false; + for (JavaClass clazz : classes) { + if (clazz.isInterface() && implementsInterface(clazz, CLASSNAME_EVENT_PRODUCER)) { + processEventProducerInterface(clazz); + eventProducerFound = true; + } + } + return eventProducerFound; + } + + private boolean implementsInterface(JavaClass clazz, String intf) { + JavaClass[] classes = clazz.getImplementedInterfaces(); + for (JavaClass cl : classes) { + if (cl.getFullyQualifiedName().equals(intf)) { + return true; + } + } + return false; + } + + /** + * Processes an EventProducer interface and creates an EventProducerModel from it. + * @param clazz the EventProducer interface + * @throws EventConventionException if the event producer conventions are violated + * @throws ClassNotFoundException if a required class cannot be found + */ + protected void processEventProducerInterface(JavaClass clazz) + throws EventConventionException, ClassNotFoundException { + EventProducerModel prodMeta = new EventProducerModel(clazz.getFullyQualifiedName()); + JavaMethod[] methods = clazz.getMethods(true); + for (JavaMethod method : methods) { + EventMethodModel methodMeta = createMethodModel(method); + prodMeta.addMethod(methodMeta); + } + EventModel model = new EventModel(); + model.addProducer(prodMeta); + models.add(model); + } + + private EventMethodModel createMethodModel(JavaMethod method) + throws EventConventionException, ClassNotFoundException { + JavaClass clazz = method.getParentClass(); + //Check EventProducer conventions + if (!method.getReturnType().isVoid()) { + throw new EventConventionException("All methods of interface " + + clazz.getFullyQualifiedName() + " must have return type 'void'!"); + } + String methodSig = clazz.getFullyQualifiedName() + "." + method.getCallSignature(); + JavaParameter[] params = method.getParameters(); + if (params.length < 1) { + throw new EventConventionException("The method " + methodSig + + " must have at least one parameter: 'Object source'!"); + } + Type firstType = params[0].getType(); + if (firstType.isPrimitive() || !"source".equals(params[0].getName())) { + throw new EventConventionException("The first parameter of the method " + methodSig + + " must be: 'Object source'!"); + } + + //build method model + DocletTag tag = method.getTagByName("event.severity"); + EventSeverity severity; + if (tag != null) { + severity = EventSeverity.valueOf(tag.getValue()); + } else { + severity = EventSeverity.INFO; + } + EventMethodModel methodMeta = new EventMethodModel( + method.getName(), severity); + if (params.length > 1) { + for (int j = 1, cj = params.length; j < cj; j++) { + JavaParameter p = params[j]; + Class type; + JavaClass pClass = p.getType().getJavaClass(); + if (p.getType().isPrimitive()) { + type = PRIMITIVE_MAP.get(pClass.getName()); + if (type == null) { + throw new UnsupportedOperationException( + "Primitive datatype not supported: " + pClass.getName()); + } + } else { + String className = pClass.getFullyQualifiedName(); + type = Class.forName(className); + } + methodMeta.addParameter(type, p.getName()); + } + } + Type[] exceptions = method.getExceptions(); + if (exceptions != null && exceptions.length > 0) { + //We only use the first declared exception because that is always thrown + JavaClass cl = exceptions[0].getJavaClass(); + methodMeta.setExceptionClass(cl.getFullyQualifiedName()); + methodMeta.setSeverity(EventSeverity.FATAL); //In case it's not set in the comments + } + return methodMeta; + } + + /** + * Returns the event model that has been accumulated. + * @return the event model. + */ + public List getModels() { + return this.models; + } + +} diff --git a/fop-events/src/main/java/org/apache/fop/eventtools/EventProducerCollectorTask.java b/fop-events/src/main/java/org/apache/fop/eventtools/EventProducerCollectorTask.java new file mode 100644 index 000000000..5dc64750e --- /dev/null +++ b/fop-events/src/main/java/org/apache/fop/eventtools/EventProducerCollectorTask.java @@ -0,0 +1,283 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.eventtools; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.List; + +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.URIResolver; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.w3c.dom.Node; + +import org.apache.commons.io.IOUtils; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.types.selectors.FilenameSelector; + +import org.apache.fop.events.model.EventModel; +import org.apache.fop.events.model.EventProducerModel; + +/** + * Ant task which inspects a file set for Java interfaces which extend the + * {@link org.apache.fop.events.EventProducer} interface. For all such interfaces an event model + * file and a translation file for the human-readable messages generated by the events is + * created and/or updated. + */ +public class EventProducerCollectorTask extends Task { + + private List filesets = new java.util.ArrayList(); + private File destDir; + private File translationFile; + + /** {@inheritDoc} */ + public void execute() throws BuildException { + try { + EventProducerCollector collector = new EventProducerCollector(); + long lastModified = processFileSets(collector); + for (EventModel model : collector.getModels()) { + File parentDir = getParentDir(model); + if (!parentDir.exists() && !parentDir.mkdirs()) { + throw new BuildException( + "Could not create target directory for event model file: " + parentDir); + } + File modelFile = new File(parentDir, "event-model.xml"); + if (!modelFile.exists() || lastModified > modelFile.lastModified()) { + model.saveToXML(modelFile); + log("Event model written to " + modelFile); + } + if (getTranslationFile() != null) { + // TODO Remove translation file creation facility? + if (!getTranslationFile().exists() + || lastModified > getTranslationFile().lastModified()) { + updateTranslationFile(modelFile); + } + } + } + } catch (ClassNotFoundException e) { + throw new BuildException(e); + } catch (EventConventionException ece) { + throw new BuildException(ece); + } catch (IOException ioe) { + throw new BuildException(ioe); + } + } + + private static final String MODEL2TRANSLATION = "model2translation.xsl"; + private static final String MERGETRANSLATION = "merge-translation.xsl"; + + private File getParentDir(EventModel model) { + Iterator iter = model.getProducers(); + assert iter.hasNext(); + EventProducerModel producer = (EventProducerModel) iter.next(); + assert !iter.hasNext(); + String interfaceName = producer.getInterfaceName(); + int startLocalName = interfaceName.lastIndexOf("."); + if (startLocalName < 0) { + return destDir; + } else { + String dirname = interfaceName.substring(0, startLocalName); + dirname = dirname.replace('.', File.separatorChar); + return new File(destDir, dirname); + } + } + + /** + * Updates the translation file with new entries for newly found event producer methods. + * @param modelFile the model file to use + * @throws IOException if an I/O error occurs + */ + protected void updateTranslationFile(File modelFile) throws IOException { + try { + boolean resultExists = getTranslationFile().exists(); + SAXTransformerFactory tFactory + = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); + + //Generate fresh generated translation file as template + Source src = new StreamSource(modelFile.toURI().toURL().toExternalForm()); + StreamSource xslt1 = new StreamSource( + getClass().getResourceAsStream(MODEL2TRANSLATION)); + if (xslt1.getInputStream() == null) { + throw new FileNotFoundException(MODEL2TRANSLATION + " not found"); + } + DOMResult domres = new DOMResult(); + Transformer transformer = tFactory.newTransformer(xslt1); + transformer.transform(src, domres); + final Node generated = domres.getNode(); + + Node sourceDocument; + if (resultExists) { + //Load existing translation file into memory (because we overwrite it later) + src = new StreamSource(getTranslationFile().toURI().toURL().toExternalForm()); + domres = new DOMResult(); + transformer = tFactory.newTransformer(); + transformer.transform(src, domres); + sourceDocument = domres.getNode(); + } else { + //Simply use generated as source document + sourceDocument = generated; + } + + //Generate translation file (with potentially new translations) + src = new DOMSource(sourceDocument); + + //The following triggers a bug in older Xalan versions + //Result res = new StreamResult(getTranslationFile()); + OutputStream out = new java.io.FileOutputStream(getTranslationFile()); + out = new java.io.BufferedOutputStream(out); + Result res = new StreamResult(out); + try { + StreamSource xslt2 = new StreamSource( + getClass().getResourceAsStream(MERGETRANSLATION)); + if (xslt2.getInputStream() == null) { + throw new FileNotFoundException(MERGETRANSLATION + " not found"); + } + transformer = tFactory.newTransformer(xslt2); + transformer.setURIResolver(new URIResolver() { + public Source resolve(String href, String base) throws TransformerException { + if ("my:dom".equals(href)) { + return new DOMSource(generated); + } + return null; + } + }); + if (resultExists) { + transformer.setParameter("generated-url", "my:dom"); + } + transformer.transform(src, res); + if (resultExists) { + log("Translation file updated: " + getTranslationFile()); + } else { + log("Translation file generated: " + getTranslationFile()); + } + } finally { + IOUtils.closeQuietly(out); + } + } catch (TransformerException te) { + throw new IOException(te.getMessage()); + } + } + + /** + * Processes the file sets defined for the task. + * @param collector the collector to use for collecting the event producers + * @return the time of the latest modification of any of the files inspected + * @throws IOException if an I/O error occurs + * @throws EventConventionException if the EventProducer conventions are violated + * @throws ClassNotFoundException if a required class cannot be found + */ + protected long processFileSets(EventProducerCollector collector) + throws IOException, EventConventionException, ClassNotFoundException { + long lastModified = 0; + for (FileSet fs : filesets) { + DirectoryScanner ds = fs.getDirectoryScanner(getProject()); + String[] srcFiles = ds.getIncludedFiles(); + File directory = fs.getDir(getProject()); + for (String filename : srcFiles) { + File src = new File(directory, filename); + boolean eventProducerFound = collector.scanFile(src); + if (eventProducerFound) { + lastModified = Math.max(lastModified, src.lastModified()); + } + } + } + return lastModified; + } + + /** + * Adds a file set. + * @param set the file set + */ + public void addFileset(FileSet set) { + filesets.add(set); + } + + /** + * Sets the destination directory for the event models. + * + * @param destDir the destination directory + */ + public void setDestDir(File destDir) { + if (!destDir.isDirectory()) { + throw new IllegalArgumentException("destDir must be a directory"); + } + this.destDir = destDir; + } + + /** + * Sets the translation file for the event producer methods. + * @param f the translation file + */ + public void setTranslationFile(File f) { + this.translationFile = f; + } + + /** + * Returns the translation file for the event producer methods. + * @return the translation file + */ + public File getTranslationFile() { + return this.translationFile; + } + + /** + * Command-line interface for testing purposes. + * @param args the command-line arguments + */ + public static void main(String[] args) { + try { + Project project = new Project(); + + EventProducerCollectorTask generator = new EventProducerCollectorTask(); + generator.setProject(project); + project.setName("Test"); + FileSet fileset = new FileSet(); + fileset.setDir(new File("test/java")); + + FilenameSelector selector = new FilenameSelector(); + selector.setName("**/*.java"); + fileset.add(selector); + generator.addFileset(fileset); + + File targetDir = new File("build/codegen1"); + targetDir.mkdirs(); + + generator.setTranslationFile(new File("out1.xml")); + generator.execute(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/fop-events/src/main/java/org/apache/fop/tools/EventConventionException.java b/fop-events/src/main/java/org/apache/fop/tools/EventConventionException.java deleted file mode 100644 index 363850b95..000000000 --- a/fop-events/src/main/java/org/apache/fop/tools/EventConventionException.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.tools; - -/** - * This exception is used to indicate a violation of the conventions for event producers. - */ -public class EventConventionException extends Exception { - - private static final long serialVersionUID = 117244726033986628L; - - /** - * Creates a new EventConventionException - * @param message the error message - */ - public EventConventionException(String message) { - super(message); - } - -} diff --git a/fop-events/src/main/java/org/apache/fop/tools/EventProducerCollector.java b/fop-events/src/main/java/org/apache/fop/tools/EventProducerCollector.java deleted file mode 100644 index 2351fc870..000000000 --- a/fop-events/src/main/java/org/apache/fop/tools/EventProducerCollector.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.tools; - -import java.io.File; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.apache.fop.events.EventProducer; -import org.apache.fop.events.model.EventMethodModel; -import org.apache.fop.events.model.EventModel; -import org.apache.fop.events.model.EventProducerModel; -import org.apache.fop.events.model.EventSeverity; - -import com.thoughtworks.qdox.JavaDocBuilder; -import com.thoughtworks.qdox.model.DefaultDocletTagFactory; -import com.thoughtworks.qdox.model.DocletTag; -import com.thoughtworks.qdox.model.DocletTagFactory; -import com.thoughtworks.qdox.model.JavaClass; -import com.thoughtworks.qdox.model.JavaMethod; -import com.thoughtworks.qdox.model.JavaParameter; -import com.thoughtworks.qdox.model.Type; - -/** - * Finds EventProducer interfaces and builds the event model for them. - */ -class EventProducerCollector { - - private static final String CLASSNAME_EVENT_PRODUCER = EventProducer.class.getName(); - private static final Map> PRIMITIVE_MAP; - - static { - Map> m = new java.util.HashMap>(); - m.put("boolean", Boolean.class); - m.put("byte", Byte.class); - m.put("char", Character.class); - m.put("short", Short.class); - m.put("int", Integer.class); - m.put("long", Long.class); - m.put("float", Float.class); - m.put("double", Double.class); - PRIMITIVE_MAP = Collections.unmodifiableMap(m); - } - - private DocletTagFactory tagFactory; - private List models = new java.util.ArrayList(); - - /** - * Creates a new EventProducerCollector. - */ - EventProducerCollector() { - this.tagFactory = createDocletTagFactory(); - } - - /** - * Creates the {@link DocletTagFactory} to be used by the collector. - * @return the doclet tag factory - */ - protected DocletTagFactory createDocletTagFactory() { - return new DefaultDocletTagFactory(); - } - - /** - * Scans a file and processes it if it extends the {@link EventProducer} interface. - * @param src the source file (a Java source file) - * @return true if the file contained an EventProducer interface - * @throws IOException if an I/O error occurs - * @throws EventConventionException if the EventProducer conventions are violated - * @throws ClassNotFoundException if a required class cannot be found - */ - public boolean scanFile(File src) - throws IOException, EventConventionException, ClassNotFoundException { - JavaDocBuilder builder = new JavaDocBuilder(this.tagFactory); - builder.addSource(src); - JavaClass[] classes = builder.getClasses(); - boolean eventProducerFound = false; - for (JavaClass clazz : classes) { - if (clazz.isInterface() && implementsInterface(clazz, CLASSNAME_EVENT_PRODUCER)) { - processEventProducerInterface(clazz); - eventProducerFound = true; - } - } - return eventProducerFound; - } - - private boolean implementsInterface(JavaClass clazz, String intf) { - JavaClass[] classes = clazz.getImplementedInterfaces(); - for (JavaClass cl : classes) { - if (cl.getFullyQualifiedName().equals(intf)) { - return true; - } - } - return false; - } - - /** - * Processes an EventProducer interface and creates an EventProducerModel from it. - * @param clazz the EventProducer interface - * @throws EventConventionException if the event producer conventions are violated - * @throws ClassNotFoundException if a required class cannot be found - */ - protected void processEventProducerInterface(JavaClass clazz) - throws EventConventionException, ClassNotFoundException { - EventProducerModel prodMeta = new EventProducerModel(clazz.getFullyQualifiedName()); - JavaMethod[] methods = clazz.getMethods(true); - for (JavaMethod method : methods) { - EventMethodModel methodMeta = createMethodModel(method); - prodMeta.addMethod(methodMeta); - } - EventModel model = new EventModel(); - model.addProducer(prodMeta); - models.add(model); - } - - private EventMethodModel createMethodModel(JavaMethod method) - throws EventConventionException, ClassNotFoundException { - JavaClass clazz = method.getParentClass(); - //Check EventProducer conventions - if (!method.getReturnType().isVoid()) { - throw new EventConventionException("All methods of interface " - + clazz.getFullyQualifiedName() + " must have return type 'void'!"); - } - String methodSig = clazz.getFullyQualifiedName() + "." + method.getCallSignature(); - JavaParameter[] params = method.getParameters(); - if (params.length < 1) { - throw new EventConventionException("The method " + methodSig - + " must have at least one parameter: 'Object source'!"); - } - Type firstType = params[0].getType(); - if (firstType.isPrimitive() || !"source".equals(params[0].getName())) { - throw new EventConventionException("The first parameter of the method " + methodSig - + " must be: 'Object source'!"); - } - - //build method model - DocletTag tag = method.getTagByName("event.severity"); - EventSeverity severity; - if (tag != null) { - severity = EventSeverity.valueOf(tag.getValue()); - } else { - severity = EventSeverity.INFO; - } - EventMethodModel methodMeta = new EventMethodModel( - method.getName(), severity); - if (params.length > 1) { - for (int j = 1, cj = params.length; j < cj; j++) { - JavaParameter p = params[j]; - Class type; - JavaClass pClass = p.getType().getJavaClass(); - if (p.getType().isPrimitive()) { - type = PRIMITIVE_MAP.get(pClass.getName()); - if (type == null) { - throw new UnsupportedOperationException( - "Primitive datatype not supported: " + pClass.getName()); - } - } else { - String className = pClass.getFullyQualifiedName(); - type = Class.forName(className); - } - methodMeta.addParameter(type, p.getName()); - } - } - Type[] exceptions = method.getExceptions(); - if (exceptions != null && exceptions.length > 0) { - //We only use the first declared exception because that is always thrown - JavaClass cl = exceptions[0].getJavaClass(); - methodMeta.setExceptionClass(cl.getFullyQualifiedName()); - methodMeta.setSeverity(EventSeverity.FATAL); //In case it's not set in the comments - } - return methodMeta; - } - - /** - * Returns the event model that has been accumulated. - * @return the event model. - */ - public List getModels() { - return this.models; - } - -} diff --git a/fop-events/src/main/java/org/apache/fop/tools/EventProducerCollectorTask.java b/fop-events/src/main/java/org/apache/fop/tools/EventProducerCollectorTask.java deleted file mode 100644 index 8796280fd..000000000 --- a/fop-events/src/main/java/org/apache/fop/tools/EventProducerCollectorTask.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.tools; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Iterator; -import java.util.List; - -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.URIResolver; -import javax.xml.transform.dom.DOMResult; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.sax.SAXTransformerFactory; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - -import org.w3c.dom.Node; - -import org.apache.commons.io.IOUtils; -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.DirectoryScanner; -import org.apache.tools.ant.Project; -import org.apache.tools.ant.Task; -import org.apache.tools.ant.types.FileSet; -import org.apache.tools.ant.types.selectors.FilenameSelector; - -import org.apache.fop.events.model.EventModel; -import org.apache.fop.events.model.EventProducerModel; - -/** - * Ant task which inspects a file set for Java interfaces which extend the - * {@link org.apache.fop.events.EventProducer} interface. For all such interfaces an event model - * file and a translation file for the human-readable messages generated by the events is - * created and/or updated. - */ -public class EventProducerCollectorTask extends Task { - - private List filesets = new java.util.ArrayList(); - private File destDir; - private File translationFile; - - /** {@inheritDoc} */ - public void execute() throws BuildException { - try { - EventProducerCollector collector = new EventProducerCollector(); - long lastModified = processFileSets(collector); - for (EventModel model : collector.getModels()) { - File parentDir = getParentDir(model); - if (!parentDir.exists() && !parentDir.mkdirs()) { - throw new BuildException( - "Could not create target directory for event model file: " + parentDir); - } - File modelFile = new File(parentDir, "event-model.xml"); - if (!modelFile.exists() || lastModified > modelFile.lastModified()) { - model.saveToXML(modelFile); - log("Event model written to " + modelFile); - } - if (getTranslationFile() != null) { - // TODO Remove translation file creation facility? - if (!getTranslationFile().exists() - || lastModified > getTranslationFile().lastModified()) { - updateTranslationFile(modelFile); - } - } - } - } catch (ClassNotFoundException e) { - throw new BuildException(e); - } catch (EventConventionException ece) { - throw new BuildException(ece); - } catch (IOException ioe) { - throw new BuildException(ioe); - } - } - - private static final String MODEL2TRANSLATION = "model2translation.xsl"; - private static final String MERGETRANSLATION = "merge-translation.xsl"; - - private File getParentDir(EventModel model) { - Iterator iter = model.getProducers(); - assert iter.hasNext(); - EventProducerModel producer = (EventProducerModel) iter.next(); - assert !iter.hasNext(); - String interfaceName = producer.getInterfaceName(); - int startLocalName = interfaceName.lastIndexOf("."); - if (startLocalName < 0) { - return destDir; - } else { - String dirname = interfaceName.substring(0, startLocalName); - dirname = dirname.replace('.', File.separatorChar); - return new File(destDir, dirname); - } - } - - /** - * Updates the translation file with new entries for newly found event producer methods. - * @param modelFile the model file to use - * @throws IOException if an I/O error occurs - */ - protected void updateTranslationFile(File modelFile) throws IOException { - try { - boolean resultExists = getTranslationFile().exists(); - SAXTransformerFactory tFactory - = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); - - //Generate fresh generated translation file as template - Source src = new StreamSource(modelFile.toURI().toURL().toExternalForm()); - StreamSource xslt1 = new StreamSource( - getClass().getResourceAsStream(MODEL2TRANSLATION)); - if (xslt1.getInputStream() == null) { - throw new FileNotFoundException(MODEL2TRANSLATION + " not found"); - } - DOMResult domres = new DOMResult(); - Transformer transformer = tFactory.newTransformer(xslt1); - transformer.transform(src, domres); - final Node generated = domres.getNode(); - - Node sourceDocument; - if (resultExists) { - //Load existing translation file into memory (because we overwrite it later) - src = new StreamSource(getTranslationFile().toURI().toURL().toExternalForm()); - domres = new DOMResult(); - transformer = tFactory.newTransformer(); - transformer.transform(src, domres); - sourceDocument = domres.getNode(); - } else { - //Simply use generated as source document - sourceDocument = generated; - } - - //Generate translation file (with potentially new translations) - src = new DOMSource(sourceDocument); - - //The following triggers a bug in older Xalan versions - //Result res = new StreamResult(getTranslationFile()); - OutputStream out = new java.io.FileOutputStream(getTranslationFile()); - out = new java.io.BufferedOutputStream(out); - Result res = new StreamResult(out); - try { - StreamSource xslt2 = new StreamSource( - getClass().getResourceAsStream(MERGETRANSLATION)); - if (xslt2.getInputStream() == null) { - throw new FileNotFoundException(MERGETRANSLATION + " not found"); - } - transformer = tFactory.newTransformer(xslt2); - transformer.setURIResolver(new URIResolver() { - public Source resolve(String href, String base) throws TransformerException { - if ("my:dom".equals(href)) { - return new DOMSource(generated); - } - return null; - } - }); - if (resultExists) { - transformer.setParameter("generated-url", "my:dom"); - } - transformer.transform(src, res); - if (resultExists) { - log("Translation file updated: " + getTranslationFile()); - } else { - log("Translation file generated: " + getTranslationFile()); - } - } finally { - IOUtils.closeQuietly(out); - } - } catch (TransformerException te) { - throw new IOException(te.getMessage()); - } - } - - /** - * Processes the file sets defined for the task. - * @param collector the collector to use for collecting the event producers - * @return the time of the latest modification of any of the files inspected - * @throws IOException if an I/O error occurs - * @throws EventConventionException if the EventProducer conventions are violated - * @throws ClassNotFoundException if a required class cannot be found - */ - protected long processFileSets(EventProducerCollector collector) - throws IOException, EventConventionException, ClassNotFoundException { - long lastModified = 0; - for (FileSet fs : filesets) { - DirectoryScanner ds = fs.getDirectoryScanner(getProject()); - String[] srcFiles = ds.getIncludedFiles(); - File directory = fs.getDir(getProject()); - for (String filename : srcFiles) { - File src = new File(directory, filename); - boolean eventProducerFound = collector.scanFile(src); - if (eventProducerFound) { - lastModified = Math.max(lastModified, src.lastModified()); - } - } - } - return lastModified; - } - - /** - * Adds a file set. - * @param set the file set - */ - public void addFileset(FileSet set) { - filesets.add(set); - } - - /** - * Sets the destination directory for the event models. - * - * @param destDir the destination directory - */ - public void setDestDir(File destDir) { - if (!destDir.isDirectory()) { - throw new IllegalArgumentException("destDir must be a directory"); - } - this.destDir = destDir; - } - - /** - * Sets the translation file for the event producer methods. - * @param f the translation file - */ - public void setTranslationFile(File f) { - this.translationFile = f; - } - - /** - * Returns the translation file for the event producer methods. - * @return the translation file - */ - public File getTranslationFile() { - return this.translationFile; - } - - /** - * Command-line interface for testing purposes. - * @param args the command-line arguments - */ - public static void main(String[] args) { - try { - Project project = new Project(); - - EventProducerCollectorTask generator = new EventProducerCollectorTask(); - generator.setProject(project); - project.setName("Test"); - FileSet fileset = new FileSet(); - fileset.setDir(new File("test/java")); - - FilenameSelector selector = new FilenameSelector(); - selector.setName("**/*.java"); - fileset.add(selector); - generator.addFileset(fileset); - - File targetDir = new File("build/codegen1"); - targetDir.mkdirs(); - - generator.setTranslationFile(new File("out1.xml")); - generator.execute(); - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/fop/build.xml b/fop/build.xml index 781128dd8..45a45af63 100644 --- a/fop/build.xml +++ b/fop/build.xml @@ -325,7 +325,7 @@ list of possible build targets. - + -- cgit v1.2.3