org.nuiton.eugene.plugin.Xmi2Model Maven / Gradle / Ivy
/* *##%
* EUGene :: Maven plugin
* Copyright (C) 2006 - 2009 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
* .
* ##%*/
package org.nuiton.eugene.plugin;
import org.nuiton.plugin.PluginIOContext;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import javax.xml.transform.Transformer;
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.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.nuiton.plugin.PluginHelper;
import org.nuiton.util.FasterCachedResourceResolver;
import org.nuiton.util.FileUtil;
import org.nuiton.util.Resource;
import org.nuiton.util.ResourceResolver;
import org.nuiton.util.StringUtil;
/**
* Converti les fichiers XMI en fichier Model via une transformation XSLT a
* définir.
*
* Class abstraite sans feuille de style ni extension.
*
* @author ruchaud
* @version $Revision: 755 $
*
* Last update: $Date: 2009-12-15 00:50:27 +0100 (mar., 15 déc. 2009) $
* by : $Author: tchemit $
*/
public abstract class Xmi2Model extends EugeneAbstractMojo {
/**
* Les entrées sorties du plugin.
*
*
*
* En entrée on demande des répertoires où chercher les fichiers xmi a convertir.
*
* En sortie on demande le répertoire ou extraire les xmi et copier les resources.
*
* Par défaut on a les valeurs suivantes :
*
*
* <xmiResources>
*
* <input>target/generated-sources/xmi<\input>
*
* <output>target/generated-sources/models<\output>
*
* </xmiResources>
*
*
*
*
* Note: si {@link #testPhase} est activée, les valeurs par défaut sont :
*
*
* <xmiResources>
*
* <input>target/generated-sources/xmi<\input>
*
* <output>target/generated-sources/test-models<\output>
*
* </xmiResources>
*
*
*
* @parameter
* @since 1.0.0-rc-8
*/
protected PluginIOContext xmiResources;
/**
* Nom du paquetage pour les fichiers générés
*
* @parameter expression="${generator.fullPackagePath}" default-value="${project.groupId}.${project.artifactId}"
* @since 0.50
*/
protected String fullPackagePath;
/**
* Nom du paquetage à généré
*
* @parameter expression="${generator.extractedPackages}" default-value="${project.groupId}.${project.artifactId}"
* @since 0.50
*/
protected String extractedPackages;
/**
* Liste des types de modeles acceptés séparés par des vigules.
*
* @parameter expression="${generator.acceptedXmiTypes}" default-value="xmi,uml"
* @since 1.0.0-rc-4
*/
protected String acceptedXmiTypes;
/**
* Nom du resolver a utiliser
*
* @parameter expression="${generator.resolver}" default-value="org.nuiton.util.ResourceResolver"
* @since 1.0.0-rc-4
*/
protected String resolver;
/**
* An extra directory to be added to the classpath.
*
* @parameter expression="${eugene.extraClassPathDirectory}"
* @since 1.0.0-rc-4
*/
protected File extraClassPathDirectory;
/**
* Get extension.
*
* @return the extension
*/
protected abstract String getExtension();
/**
* Get style sheet.
*
* @param model the model file used to determine the stylesheet to use
* @return the stylesheet name
*/
protected abstract String getStyleSheet(File model);
@Override
public void doAction() throws MojoExecutionException, MojoFailureException {
long t0 = System.nanoTime();
try {
getLog().info("Processing XSL tranformation");
getLog().info(" with fullPackagePath : " + fullPackagePath);
getLog().info(" with extractedPackages : " + extractedPackages);
getLog().info(" with acceptedXmiTypes : " + acceptedXmiTypes);
getLog().info(" with resolver : " + resolver);
TransformerFactory factory = TransformerFactory.newInstance();
ClassLoader fixedClassLoader = fixClassLoader();
String[] includes = getSuffixPattern("*");
String[] acceptedTypesAsArray = getAcceptedTypesAsArray();
for (File dir : xmiResources.getInputs()) {
// recuperation des fichiers a traiter
List files = PluginHelper.getIncludedFiles(dir, includes, null);
// lancement des traitements xsl sur les fichiers trouvés
// dans le repertoire
actionXsl(dir, files, factory, fixedClassLoader, acceptedTypesAsArray);
}
} finally {
getLog().info("xsl done in " + StringUtil.convertTime(System.nanoTime() - t0));
}
getLog().info("Copy resources files");
try {
String[] excludes = getSuffixPattern("**/*");
PluginHelper.copyFiles(xmiResources, null, excludes, overwrite);
} catch (IOException ex) {
throw new MojoExecutionException("could not copy some files for reason " + ex.getMessage(), ex);
}
}
@Override
protected PluginIOContext getResources() {
return xmiResources;
}
@Override
protected PluginIOContext initResources() {
File defaultIn = getFileFromBasedir("target", "generated-sources", "xmi");
File defaultOut = getFileFromBasedir("target", "generated-sources", "models");
File defaultTestIn = getFileFromBasedir("target", "generated-sources", "test-xmi");
File defaultTestOut = getFileFromBasedir("target", "generated-sources", "test-models");
xmiResources = initResources(defaultIn, defaultOut, defaultTestIn, defaultTestOut);
return xmiResources;
}
protected String[] getSuffixPattern(String prefix) {
String[] acceptedSuffixes = getAcceptedTypesAsArray();
int max = acceptedSuffixes.length;
final String[] patterns = new String[max];
for (int i = 0; i < max; i++) {
patterns[i] = prefix + acceptedSuffixes[i];
}
return patterns;
}
protected void actionXsl(File dir, List files, TransformerFactory factory, ClassLoader fixedClassLoader, String[] acceptedSuffixes) throws MojoExecutionException {
for (File file : files) {
try {
if (getLog().isDebugEnabled()) {
getLog().debug("treate file : " + file);
}
// Prepare resolver, stylesheet
URIResolver fileResolver = getUriResolver(file, fixedClassLoader);
String styleSheet = getStyleSheet(file);
URL xsl = Resource.getURL(styleSheet);
//TC-20090820 : using recursive for xmi
// File result = new File(destDirModel, FileUtil.basename(file,
// acceptedSuffixes).concat(".").concat(getExtension()));
String filename = FileUtil.basename(file, acceptedSuffixes).concat(".").concat(getExtension());
String relatifPath = file.getParentFile().getAbsolutePath().substring(dir.getAbsolutePath().length());
File dstDir = xmiResources.getOutput();
if (!relatifPath.isEmpty()) {
dstDir = new File(dstDir, relatifPath);
dstDir.mkdirs();
}
File result = new File(dstDir, filename);
if (!overwrite && file.lastModified() < result.lastModified()) {
getLog().info("file up-to-date : " + result);
continue;
}
if (getLog().isDebugEnabled()) {
getLog().debug("generate " + result);
}
// Create the xsl transformer and set parameters
Transformer transformer = factory.newTransformer(new StreamSource(xsl.openStream()));
transformer.setParameter("fullPackagePath", fullPackagePath);
transformer.setParameter("extraPackages", extractedPackages);
transformer.setURIResolver(fileResolver);
transformer.transform(new StreamSource(file), new StreamResult(
new FileOutputStream(result)));
} catch (Exception e) {
throw new MojoExecutionException(e.getMessage(), e);
}
}
}
/**
* Look for the types declared in property "acceptedXmiTypes", split it
* on ',' and check for the leading '.'.
*
* @return an array with all the accepted xmi types and a leading '.'
*/
protected String[] getAcceptedTypesAsArray() {
String[] splittedTypes = acceptedXmiTypes.split(",");
String[] result = new String[splittedTypes.length];
for (int i = 0; i < splittedTypes.length; i++) {
String type = splittedTypes[i];
if (!type.startsWith(".")) {
type = "." + type;
}
result[i] = type;
}
return result;
}
protected URIResolver getUriResolver(File model, ClassLoader cl) {
URIResolver result = null;
try {
Class> clazz = Class.forName(resolver, true, cl);
// 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 = model.getParentFile().getAbsolutePath();
// Instantiate
result = (URIResolver) withBaseConstructor.newInstance(base);
} catch (Exception eee) {
getLog().warn("Unable to instantiate resolver with String parameter",
eee);
}
// If resolver is still not created, create it using the default
// constructor
if (result == null) {
result = (URIResolver) clazz.newInstance();
}
if (result instanceof ResourceResolver) {
((ResourceResolver) result).setVerbose(verbose);
((ResourceResolver) result).setCl(cl);
if (result instanceof FasterCachedResourceResolver) {
boolean offline = settings.isOffline();
getLog().debug("using offline mode ? : " + offline);
((FasterCachedResourceResolver) result).setOffline(offline);
}
}
} catch (Exception eee) {
getLog().warn("Unable to instantiate resolver using the default constructor", eee);
}
return result;
}
/**
* Prepare le classLoader a utiliser dans le generateur.
*
* Si un {@link #extraClassPathDirectory} a été renseigné, il est rajouté.
*
* Si des références à des sibling modules, ils seront rajoutés aussi.
*
* @return le class loader modifie
* @throws MojoExecutionException if any pb
*/
protected ClassLoader fixClassLoader() throws MojoExecutionException {
Set urlsAsString = new HashSet();
List urls = new ArrayList();
try {
ClassLoader loader;
if (extraClassPathDirectory != null) {
if (verbose) {
getLog().info("Add extra directory in generator's classLoader : " + extraClassPathDirectory);
}
addDirectoryToUrlsList(extraClassPathDirectory,urls,urlsAsString);
}
if (project.getProjectReferences() != null) {
// this case is for multi-module when calling from a parent module
for (Object o : project.getProjectReferences().entrySet()) {
Entry, ?> entry = (Entry, ?>) o;
MavenProject relatedProject = (MavenProject) entry.getValue();
if (verbose) {
getLog().info("Add project reference in generator's classLoader : '" + relatedProject.getArtifact() + "'");
}
//TODO il faudrait peut-etre aussi ajouter les dependances ?
addDirectoryToUrlsList(relatedProject.getArtifact().getFile(), urls, urlsAsString);
}
}
if (!project.getArtifacts().isEmpty()) {
// this is a special case when artifacts were resolved (for example in site phase)
if (verbose) {
getLog().info("Use resolved artifacts to build class-path");
}
for (Object o : project.getArtifacts()) {
Artifact a = (Artifact) o;
if (!a.getScope().equals("provided")) {
addDirectoryToUrlsList(a.getFile(), urls, urlsAsString);
}
}
}
// we ask to add the directory in classloader
loader = getClass().getClassLoader();
if (getLog().isDebugEnabled()) {
getLog().info("original classloader " + loader);
}
if (loader instanceof URLClassLoader) {
// on reinjecte les urls de loader de base
// car sinon on risque de ne pas retrouver les resources...
for (URL u : ((URLClassLoader) loader).getURLs()) {
addUrlToUrlsList(u, urls, urlsAsString);
if (getLog().isDebugEnabled()) {
getLog().debug("original cp entry: " + u);
}
}
// et on force l'utilisation du classloader parent
// s'il existe
if (loader.getParent() != null) {
loader = loader.getParent();
}
}
if (!urls.isEmpty()) {
loader = new URLClassLoader(urls.toArray(new URL[urls.size()]),
loader);
}
if (getLog().isDebugEnabled()) {
for (URL u : urls) {
getLog().debug("cp entry: " + u);
}
}
return loader;
} catch (MalformedURLException e) {
throw new MojoExecutionException(e.getMessage());
} finally {
urls.clear();
urlsAsString.clear();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy