/**
* Copyright 2010 CosmoCode GmbH
*
* Licensed 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.
*/
package de.cosmocode.palava.maven.ipcstub;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.log.LogChute;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.codehaus.plexus.util.StringUtils;
import de.cosmocode.palava.ipc.IpcCommand;
/**
* A configured stub generator.
* @author Tobias Sarnowski
*/
public class Generator implements LogChute {
private Log log;
/**
* A configuration unique identifier.
* @parameter
* @required
*/
private String name;
/**
* The scheme to use, e.g. "php"
* @paramter
* @required
*/
private String scheme;
/**
* List of all packages to search commands in.
* @parameter
* @required
*/
private List<String> packages;
/**
* Map of aliases to generate within the stub.
* @parameter
*/
private Map<String, String> aliases;
/**
* Where to store the outputed files.
* @parameter
*/
private String target;
/**
* A coypright notice or something else to include in the stub.
* @parameter
*/
private String legalText;
// use to know the common generation date;
private Date generationDate;
// the engine instance;
private VelocityEngine engine;
// will be set on generate()
private File targetDirectory;
// will be generated on generate()
private Set<GenPackage> rootPackages;
public String getName() {
return name;
}
public String getScheme() {
return scheme;
}
public List<String> getPackages() {
return packages;
}
public Map<String, String> getAliases() {
return aliases;
}
public String getTarget() {
return target;
}
public String getLegalText() {
return legalText;
}
public Set<GenPackage> getRootPackages() {
return rootPackages;
}
private String getResourcePath(String resource) {
return "/ipcstub/" + scheme + "/" + resource + ".vm";
}
public String getGenerationDate() {
return new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z").format(generationDate);
}
/**
* Checks whether this generator contains a valid name, scheme and packages.
*
* @throws MojoFailureException if check failed
*/
public void check() throws MojoFailureException {
if (StringUtils.isBlank(getName())) {
throw new MojoFailureException("no classifier configured for configuration");
}
if (StringUtils.isBlank(getScheme())) {
throw new MojoFailureException("no template configured for configuration '" + getName() + "'");
}
if (getPackages() == null || getPackages().size() == 0) {
throw new MojoFailureException("no packages configured for configuration '" + getName() + "'");
}
}
/**
* Generates the stub files with the given list of IpcCommand classes.
*
* @param currentLog the maven logger
* @param classes all requested IpcCommands
* @param directory the target directory
* @throws MojoExecutionException if execution failed
* @throws MojoFailureException if any fatal error occured
*/
protected void generate(Log currentLog, Set<Class<? extends IpcCommand>> classes, File directory)
throws MojoExecutionException, MojoFailureException {
this.log = currentLog;
this.targetDirectory = target == null ? directory : new File(target);
this.generationDate = new Date();
// initialize the Velocity engine
engine = new VelocityEngine();
engine.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM, this);
engine.setProperty(VelocityEngine.RESOURCE_LOADER, "class");
engine.setProperty("class.resource.loader.class", ClasspathResourceLoader.class.getName());
try {
engine.init();
/* CHECKSTYLE:OFF */
} catch (Exception e) {
/* CHECKSTYLE:ON */
throw new MojoExecutionException("cannot initialize velocity engine", e);
}
// build up tree and informations
rootPackages = GenPackage.getFirstPackages(classes, null);
// find the scheme to use
final String templatePath = getResourcePath("main");
final Template template;
try {
template = engine.getTemplate(templatePath);
/* CHECKSTYLE:OFF */
} catch (Exception e) {
/* CHECKSTYLE:ON */
throw new MojoFailureException("cannot find scheme " + scheme, e);
}
// initialize the context
final VelocityContext ctx = new VelocityContext();
ctx.put("generator", this);
// create the target directory
if (!directory.exists() && !directory.mkdirs()) {
throw new MojoExecutionException("cannot create stub directory: " + directory);
}
// start the generation process within the scheme
final StringWriter writer = new StringWriter();
try {
// scheme have to be in UTF-8
template.merge(ctx, writer);
} catch (IOException e) {
throw new MojoExecutionException("cannot merge template", e);
}
}
@Override
public void init(RuntimeServices runtimeServices) throws Exception {
// nothing to do
}
@Override
public void log(int i, String s) {
switch (i) {
case LogChute.TRACE_ID:
case LogChute.DEBUG_ID:
log.debug(s);
break;
case LogChute.INFO_ID:
log.info(s);
break;
case LogChute.WARN_ID:
log.warn(s);
break;
case LogChute.ERROR_ID:
log.error(s);
break;
default:
}
}
@Override
public void log(int i, String s, Throwable throwable) {
switch (i) {
case LogChute.TRACE_ID:
case LogChute.DEBUG_ID:
log.debug(s, throwable);
break;
case LogChute.INFO_ID:
log.info(s, throwable);
break;
case LogChute.WARN_ID:
log.warn(s, throwable);
break;
case LogChute.ERROR_ID:
log.error(s, throwable);
break;
default:
}
}
@Override
public boolean isLevelEnabled(int i) {
switch (i) {
case LogChute.TRACE_ID:
case LogChute.DEBUG_ID:
return log.isDebugEnabled();
case LogChute.INFO_ID:
return log.isInfoEnabled();
case LogChute.WARN_ID:
return log.isWarnEnabled();
case LogChute.ERROR_ID:
return log.isErrorEnabled();
default:
return false;
}
}
/**
* Generates a file.
*
* @param generatedFileName the file name
* @param templateFile the template file
* @param args the arguments
* @throws MojoExecutionException if execution failed
* @throws MojoFailureException if any fatal error occured
*/
// used by templates
public void generateFile(String generatedFileName, String templateFile, Object args)
throws MojoExecutionException, MojoFailureException {
final File generatedFile = new File(targetDirectory, generatedFileName);
final File parent = new File(generatedFile.getParent());
parent.mkdirs();
Template tpl = null;
try {
tpl = engine.getTemplate(getResourcePath(templateFile));
/* CHECKSTYLE:OFF */
} catch (Exception e) {
/* CHECKSTYLE:ON */
throw new MojoExecutionException("cannot load template " + templateFile, e);
}
final VelocityContext ctx = new VelocityContext();
ctx.put("generator", this);
ctx.put("args", args);
final FileWriter w;
try {
w = new FileWriter(generatedFile);
} catch (IOException e) {
throw new MojoExecutionException("cannot create file " + generatedFile, e);
}
try {
log.info("Generating " + generatedFile + "...");
tpl.merge(ctx, w);
w.close();
} catch (IOException e) {
throw new MojoExecutionException("cannot merge template" + templateFile, e);
}
}
/**
* Includes another file.
*
* @param templateFile the template file
* @return the included file
* @throws MojoExecutionException if execution failed
*/
// used by templates
public String includeFile(String templateFile) throws MojoExecutionException {
final Template template;
try {
template = engine.getTemplate(getResourcePath(templateFile));
/* CHECKSTYLE:OFF */
} catch (Exception e) {
/* CHECKSTYLE:ON */
throw new MojoExecutionException("cannot load template " + templateFile, e);
}
final VelocityContext ctx = new VelocityContext();
ctx.put("generator", this);
final StringWriter writer = new StringWriter();
try {
template.merge(ctx, writer);
} catch (IOException e) {
throw new MojoExecutionException("cannot merge template", e);
}
return writer.toString();
}
}