All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nuiton.eugene.GeneratorTask Maven / Gradle / Ivy

The newest version!
/*
 * #%L
 * EUGene :: Ant task
 * 
 * $Id: GeneratorTask.java 1012 2010-11-28 11:24:27Z tchemit $
 * $HeadURL: http://svn.nuiton.org/svn/eugene/tags/eugene-2.4.2/ant-eugene-task/src/main/java/org/nuiton/eugene/GeneratorTask.java $
 * %%
 * Copyright (C) 2006 - 2010 CodeLutin
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as 
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program 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 Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */

package org.nuiton.eugene;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.ServiceLoader;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.URIResolver;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.MatchingTask;
import org.nuiton.eugene.models.Model;
import org.nuiton.eugene.models.object.ObjectModel;
import org.nuiton.eugene.models.object.ObjectModelReader;
import org.nuiton.eugene.models.state.StateModel;
import org.nuiton.eugene.models.state.StateModelReader;
import org.nuiton.util.FileUtil;
import org.nuiton.util.Resource;
import org.nuiton.util.ZipUtil;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * Ant generator Task.
 * 
 * Exemple d'utilisation dans ant :
 * 
 * 
 * < -- Define eugene task (classpath must contains templates) -->
 * <taskdef name="generator" classname="org.nuiton.eugene.GeneratorTask"
 *      classpath="${compile.classpath}" />
 *      
 * <target name="generate" description="generate">
 *      <generator srcdir="${modelDir}" destdir="${targetgen}"
 *          resolver="org.nuiton.exemple.ResourceResolver"
 *          templates="org.nuiton.example.JavaBeanGenerator"
 *          properties="defaultPackage=org.nuiton,fullPackagePath=org.nuiton,extraPackages=org.nuiton" />
 * </target>
 * 
* * Created: 14 janv. 2004 * * @author Benjamin Poussin Copyright Code Lutin * @version $Revision: 1012 $ * * Mise a jour: $Date: 2010-11-28 12:24:27 +0100 (Sun, 28 Nov 2010) $ par : * */ public class GeneratorTask extends MatchingTask { // GeneratorTask /** Template used in generation (comma separated). */ protected String templates; /** Model directory. */ protected File srcDir; /** Single model file. */ protected File srcFile; /** Destination directory. */ protected File destDir; /** * Transformation to do on model (comma separated). * * Values are : *
    *
  • object (transform into object model) *
  • state (transform into state model) *
*/ protected String transformations = "object"; /** URI Resolver. */ protected String resolver; /** * Additional generator properties. * * Values are : *
    *
  • fullPackagePath : full package path *
  • extraPackages : extra package path *
  • defaultPackage (extra generated model files) *
*/ protected Properties properties = new Properties(); /** Overwrite already existing generated files. */ protected boolean overwrite; /** Encoding. Default to UTF-8. */ protected String encoding = "UTF-8"; /** Generation directory (default to 'build') */ protected String buildDirectory = "build"; /** * Set templates (fully-qualified-name) to use * * (comma-separated). * * @param templates template to use. */ public void setTemplates(String templates) { this.templates = templates; } /** * Transformation to do. * * Values are : *
    *
  • object (transform into object model) *
  • state (transform into state model) *
* * @param transformations transformations */ public void setTransformations(String transformations) { this.transformations = transformations; } /** * Permet d'ajouter des properties. exemple: toto=1,package=org.nuiton * * @param properties properties */ public void setProperties(String properties) { String[] props = properties.split(","); for (String prop : props) { String[] pv = prop.split("="); this.properties.put(pv[0], pv[1]); } } /** * Set overwrite value. * * @param overwrite overwrite value */ public void setOverwrite(boolean overwrite) { this.overwrite = overwrite; } /** * Set encoding. * * @param encoding encoding */ public void setEncoding(String encoding) { this.encoding = encoding; } /** * Set source directory. * * @param srcDir source directory */ public void setSrcdir(File srcDir) { this.srcDir = srcDir; } /** * Set source file. * * @param srcFile source file */ public void setSrcfile(File srcFile) { this.srcFile = srcFile; } /** * Set destination directory * * @param destDir destination directory */ public void setDestdir(File destDir) { this.destDir = destDir; } /** * Set build directory. * * @param buildDirectory build directory */ public void setBuilddirectory(String buildDirectory) { this.buildDirectory = buildDirectory; } /** * Set URI resolver (FQN). * * @param resolver uri resolver */ public void setResolver(String resolver) { this.resolver = resolver; } @Override public void execute() throws BuildException { // check if (templates == null) { throw new BuildException("templates attribute must be set!", getLocation()); } if (destDir == null) { throw new BuildException("destDir attribute must be set!", getLocation()); } if (!destDir.isDirectory()) { throw new BuildException("destination directory \"" + destDir + "\" does not exist or is not a directory", getLocation()); } if (srcFile == null && srcDir == null) { throw new BuildException( "srcFile or srcDir attribute must be set!", getLocation()); } if (srcFile != null && !srcFile.isFile()) { throw new BuildException("src file \"" + srcFile + "\" does not exist or is not a file", getLocation()); } String[] templateGenerators = templates.split(","); Template[] generators = new Template[templateGenerators.length]; for (int i = 0; i < templateGenerators.length; i++) { String templateName = templateGenerators[i].trim(); try { Template template = (Template) Class.forName(templateName).newInstance(); generators[i] = template; properties.put(Template.PROP_OVERWRITE, overwrite); properties.setProperty(Template.PROP_ENCODING, encoding); template.getConfiguration().getProperties().putAll(properties); } catch (ClassCastException e) { log("Generator don't inherit Template Class", e, Project.MSG_ERR); } catch (ClassNotFoundException e) { log("Unable to find generator " + templateName, e, Project.MSG_ERR); } catch (InstantiationException e) { log("Unable to instanciate template " + templateName, e, Project.MSG_ERR); } catch (IllegalAccessException e) { log("Unable to parse input file " + templateName, e, Project.MSG_ERR); } } if (srcFile != null) { // generate the source files doExecute(srcFile, destDir, generators); } else { DirectoryScanner scanner; scanner = getDirectoryScanner(srcDir); // Process all the files marked for styling String[] includedFilenames = scanner.getIncludedFiles(); List includedFiles = new ArrayList( includedFilenames.length); for (String includedFilename : includedFilenames) { includedFiles.add(new File(srcDir, includedFilename)); } doExecute(includedFiles, destDir, generators); } } /** * Equivalent to * doExecute(new File[] { srcFile }, destDir, generators). * * @param srcFile file to apply generator to * @param destDir destination directory * @param generators generators to apply * @throws BuildException if can't generate */ protected void doExecute(File srcFile, File destDir, Template[] generators) throws BuildException { doExecute(Collections.singletonList(srcFile), destDir, generators); } /** * Execute generation on specified files. * * @param srcFiles files to apply generator to * @param destDir destination directory * @param generators generators to apply * @throws BuildException if can't generate * @throws BuildException if io errors while generation */ protected void doExecute(List srcFiles, File destDir, Template[] generators) throws BuildException { List modelFiles = doConvertFiles(srcFiles, destDir); for (Template generator : generators) { if (generator != null) { File[] modelFilesArray = modelFiles.toArray(new File[modelFiles.size()]); log("Applying " + generator.getClass().getSimpleName() + " on " + Arrays.toString(modelFilesArray), Project.MSG_INFO); String[] transformationsArray = transformations.split(","); for (String transformation : transformationsArray) { if ("object".equals(transformation)) { ModelReader objectModelReader = new ObjectModelReader(); try { ObjectModel model = objectModelReader.read(modelFilesArray); generator.applyTemplate(model, destDir); } catch (IOException e) { throw new BuildException( "Can't apply template on object model", e); } } else if ("state".equals(transformation)) { ModelReader stateModelReader = new StateModelReader(); try { Model model = stateModelReader.read(modelFilesArray); generator.applyTemplate(model, destDir); } catch (IOException e) { throw new BuildException( "Can't apply template on state model", e); } } } } } } /** * Convert srcFiles and return only eugene models files. * * Do following convertions : - unzip archive (zipped files) - xslt * transformation (xmi files) - do nothing on model files * * @param srcFiles * @param destDir * @return model file list */ protected List doConvertFiles(List srcFiles, File destDir) { List result = new ArrayList(); // transform tranformations list String[] transformationsArray = transformations.split(","); for (File file : srcFiles) { File currentFile = file; // unzip if needed // after loop file is xmi if (isArchiveFile(currentFile)) { File unzipDirectory = new File(buildDirectory, "xmi"); if (unzipDirectory.exists()) { unzipDirectory.mkdirs(); } // log log("Unzip " + currentFile.getAbsolutePath() + " into " + unzipDirectory.getAbsolutePath(), Project.MSG_INFO); try { ZipUtil.uncompress(file, unzipDirectory); } catch (IOException e) { throw new BuildException("Error on unzip archive", e); } String xmiName = currentFile.getName().substring(0, currentFile.getName().lastIndexOf('.')) + ".xmi"; currentFile = new File(unzipDirectory, xmiName); } // transform file if needed // after loop file is model (object, state, ui) if (isXmiFile(currentFile)) { String xmiVersion = getXmiVersion(currentFile); if (xmiVersion != null) { // model directory File outputDirectory = new File(buildDirectory, "models"); outputDirectory.mkdirs(); // single model name String modelName = currentFile.getName().substring(0, currentFile.getName().lastIndexOf('.')); // copy .properties file String propertyPath = currentFile.getParent(); File propertyFile = new File(propertyPath, modelName + ".properties"); if (propertyFile.exists()) { File propertyOutputFile = new File(outputDirectory, propertyFile.getName()); try { FileUtil.copy(propertyFile, propertyOutputFile); } catch (IOException ioe) { log("Cannot copy .properties file", ioe, Project.MSG_ERR); } } for (String transformation : transformationsArray) { // object if (transformation.trim().equalsIgnoreCase("object")) { File outputFile = new File(outputDirectory, modelName + ".objectmodel"); if (xmiVersion.equals("1.2")) { log("Apply XMI 1.2 to object model XSLT on " + currentFile.getAbsolutePath(), Project.MSG_INFO); executeXSLT(currentFile, outputFile, "xmi1.2ToObjectModel.xsl"); } else if (xmiVersion.equals("2.1")) { log("Apply XMI 2.1 to object model XSLT on " + currentFile.getAbsolutePath(), Project.MSG_INFO); executeXSLT(currentFile, outputFile, "xmi2.1ToObjectModel.xsl"); } // can have more than one model file // for one xmi result.add(outputFile); } // state else if (transformation.trim() .equalsIgnoreCase("state")) { File outputFile = new File(outputDirectory, modelName + ".statemodel"); if (xmiVersion.equals("1.2")) { log("Apply XMI 1.2 to state model XSLT on " + currentFile.getAbsolutePath(), Project.MSG_INFO); executeXSLT(currentFile, outputFile, "xmi1.2ToStateModel.xsl"); } else if (xmiVersion.equals("2.1")) { throw new BuildException( "State model transformation is not " + "supported for xmi 2.1"); } // can have more than one model file // for one xmi result.add(outputFile); } } } else { throw new BuildException( "Can't get xmi version from file : " + currentFile.getAbsolutePath()); } } // others files // we can have model files or non model file else if (isModelFile(currentFile)) { result.add(currentFile); } } return result; } /** * Test if file is an archive. * * @param file file to test * @return test result */ protected boolean isArchiveFile(File file) { String fileName = file.getName(); boolean result = fileName.endsWith(".zargo") || fileName.endsWith(".zuml"); return result; } /** * Test if file is a xmi. * * @param file file to test * @return test result */ protected boolean isXmiFile(File file) { String fileName = file.getName(); boolean result = fileName.endsWith(".uml") || fileName.endsWith(".xmi"); return result; } /** * Test if file is a model * * @param file file to test * @return test result */ protected boolean isModelFile(File file) { String fileName = file.getName(); boolean result = fileName.endsWith(".objectmodel") || fileName.endsWith(".statemodel"); return result; } /** * Try to find xmi version on a file. * * @param xmiFile file to inspect * @return version or null if version can't have been found */ protected String getXmiVersion(File xmiFile) { String version = null; SAXParserFactory factory = SAXParserFactory.newInstance(); try { SAXParser parser = factory.newSAXParser(); XmiVersionHandler handler = new XmiVersionHandler(); parser.parse(xmiFile, handler); version = handler.getVersion(); } catch (ParserConfigurationException e) { log("Can't parse file as xmi", e, Project.MSG_DEBUG); } catch (SAXException e) { log("Can't parse file as xmi", e, Project.MSG_DEBUG); } catch (IOException e) { log("Can't parse file as xmi", e, Project.MSG_DEBUG); } return version; } /** * Sax handler to find xmi version into xmi document. */ protected class XmiVersionHandler extends DefaultHandler { public String version; public XmiVersionHandler() { } public String getVersion() { return version; } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.equals("XMI")) { version = attributes.getValue("xmi.version"); log("XMI version found : " + version, Project.MSG_DEBUG); } if (version == null) { version = attributes.getValue("xmi:version"); log("XMI version found : " + version, Project.MSG_DEBUG); } } } /** * Do XSLT transformation on given file using specific stylesheet. * * @param xmiFile xmi file to transform * @param modelFile result of transformation * @param stylesheet stylesheet to use */ protected void executeXSLT(File xmiFile, File modelFile, String stylesheet) { // Transformation XSL try { // Load Transformer with service loader Iterator itTransformerFactory = ServiceLoader .load(TransformerFactory.class/*, urlLoader*/).iterator(); if (!itTransformerFactory.hasNext()) { throw new BuildException("No XSLT Transformer found"); } TransformerFactory transformerFactory = itTransformerFactory.next(); URL uxsl = Resource.getURL(stylesheet); StreamSource stylesource = new StreamSource(uxsl.openStream()); Transformer transformer = transformerFactory .newTransformer(stylesource); if (properties.containsKey("fullPackagePath")) { transformer.setParameter("fullPackagePath", properties .getProperty("fullPackagePath")); } if (properties.containsKey("extraPackages")) { transformer.setParameter("extraPackages", properties .getProperty("extraPackages")); } if (resolver != null && !resolver.isEmpty()) { Class clazz = (Class) Class.forName(resolver/*, true, urlLoader*/); URIResolver tresolver = null; // Try to set the base using the constructor try { // Look for a constructor with a String parameter (base) Constructor withBaseConstructor = clazz .getConstructor(String.class); // Set the xmi folder as the base String base = xmiFile.getParentFile().getAbsolutePath(); // Instantiate tresolver = (URIResolver) withBaseConstructor .newInstance(base); } catch (Exception eee) { log("Unable to instantiate resolver with String parameter", eee, Project.MSG_WARN); } // If resolver is still not created, create it using the default // constructor if (tresolver == null) { tresolver = (URIResolver) clazz.newInstance(); } transformer.setURIResolver(tresolver); } transformer.transform(new StreamSource(xmiFile.getAbsolutePath()), new StreamResult(modelFile.getAbsolutePath())); } catch (TransformerException e) { throw new BuildException("Transformation exception (xslt)", e); } catch (MalformedURLException e) { throw new BuildException("Invalid jar url", e); } catch (InstantiationException e) { throw new BuildException("Can't init resolver", e); } catch (IllegalAccessException e) { throw new BuildException("Can't access resolver", e); } catch (ClassNotFoundException e) { throw new BuildException("Can't find resolver", e); } catch (IOException e) { throw new BuildException( "Error while trying to access stylesheet", e); } catch (SecurityException e) { throw new BuildException( "Error while trying to access stylesheet", e); } } } // GeneratorTask




© 2015 - 2024 Weber Informatics LLC | Privacy Policy