package org.sakaiproject.util;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
/**
* Represents a single Sakai component directory. Given an ID, a base dir,
* and a {@link Compiler}, can generate its own directory layout and can
* generate a near-guaranteed unique Java class and associated bean definition.
* Cannot be instantiated if a component of the same ID has already been
* created below the specified root directory. Cannot invoke {@link #generate()}
* multiple times unless the underlying file system has been edited out-of-band.
*
* @author dmccallum@unicon.net
*
*/
public class Component {
private static final String CLASS_SRC_TEMPLATE =
"package %1$s;\n" +
"public class %2$s { }";
private static final String BEAN_DEF_TEMPLATE =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<!DOCTYPE beans PUBLIC \"-//SPRING//DTD BEAN//EN\" \"http://www.springframework.org/dtd/spring-beans.dtd\">\n" +
"<beans>\n" +
"\t<bean id=\"%1$s\" class=\"%1$s\" />\n" +
"</beans>";
private String id;
private File componentsRootDir;
private File componentDir;
private File webInfDir;
private File classesDir;
private File libDir;
private File srcDir;
private String pkgName;
private String className;
private File srcPkgDir;
private File classSrcFile;
private File beanDefsFile;
private Compiler compiler;
public Component(String id, String componentsRootDir, Compiler compiler) {
if ( id == null ) {
throw new IllegalArgumentException("Must specify an ID");
}
this.id = id;
this.componentsRootDir = new File(componentsRootDir);
if ( !(this.componentsRootDir.exists()) ) {
throw new IllegalArgumentException("Specified components root dir (" + componentsRootDir +
") does not exist");
}
File proposedComponentDir =
new File(componentsRootDir, calcComponentName());
if ( proposedComponentDir.exists() ) {
throw new IllegalArgumentException("Proposed component dir (" + proposedComponentDir +
") already exists");
}
if (compiler == null) {
throw new IllegalArgumentException("Must specify a Compiler");
}
this.compiler = compiler;
}
public String getBeanId() {
return getBeanClass();
}
public String getDir() {
return componentDir.getAbsolutePath();
}
protected String getBeanClass() {
if ( pkgName == null || className == null ) {
return null;
}
return pkgName + "." + className;
}
public void generate() {
if ( componentDir != null && componentDir.exists() ) {
throw new IllegalStateException("Component already exists at " + componentDir);
}
layout();
compile();
}
protected void layout() {
makeComponentDir();
layoutWebapp();
generateJavaSource();
generateBeanDefs();
}
protected void makeComponentDir() {
this.componentDir = mkdir(componentsRootDir, calcComponentName());
}
protected String calcComponentName() {
return "sakai-" + id + "-pack";
}
protected void layoutWebapp() {
String path = componentDir.getPath() + File.separatorChar + "WEB-INF";
webInfDir = mkdir(componentDir, "WEB-INF");
classesDir = mkdir(webInfDir, "classes");
libDir = mkdir(webInfDir, "lib");
}
protected File mkdir(File parent, String name) {
File dir = new File(parent, name);
if (!(dir.mkdirs())) {
throw new IllegalStateException("Unable to create dir at " + dir.getPath());
}
return dir;
}
protected void generateJavaSource() {
srcDir = mkdir(componentDir, "src");
pkgName = getClass().getPackage().getName();
String pkgAsPath =
pkgName.replace(".", File.separator);
srcPkgDir = mkdir(srcDir, pkgAsPath);
className = "ServiceImpl" + id;
String classSrc = String.format(CLASS_SRC_TEMPLATE, pkgName, className);
classSrcFile = writeFile(srcPkgDir, className + ".java", classSrc);
}
protected void generateBeanDefs() {
String beanDefs = String.format(BEAN_DEF_TEMPLATE, getBeanClass());
beanDefsFile = writeFile(webInfDir, "components.xml", beanDefs);
}
protected File writeFile(File parentDir, String filePath, String fileContent) {
File file = new File(parentDir, filePath);
if (!file.exists()) {
try {
if (!(file.createNewFile())) {
throw new IllegalStateException("Unable to create file at " + file);
}
} catch ( IOException e ) {
throw new IllegalStateException("Unable to create file at " + file, e);
}
}
Writer output = null;
try {
output = new BufferedWriter(new FileWriter(file));
output.write( fileContent );
} catch (IOException e) {
throw new IllegalArgumentException("Failed to write to " + file, e);
} finally {
try {
output.close();
} catch ( IOException e ) {
throw new IllegalArgumentException("Failed to close file " + file, e);
}
}
return file;
}
protected void compile() {
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
compiler.compile(classSrcFile, classesDir, out);
out.close();
}
}