package org.objectstyle.wolips.thirdparty.velocity; import java.io.BufferedOutputStream; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.security.MessageDigest; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.exception.MethodInvocationException; import org.apache.velocity.exception.ParseErrorException; import org.apache.velocity.exception.ResourceNotFoundException; import org.apache.velocity.runtime.RuntimeConstants; import org.apache.velocity.runtime.resource.loader.FileResourceLoader; import org.eclipse.core.runtime.IPath; import org.objectstyle.wolips.thirdparty.velocity.resourceloader.ResourceLoader; import org.osgi.framework.Bundle; public class WOLipsVelocityUtils { /** * Creates a configured VelocityEngine. * * @param templateFamilyName * the name of the template family (the common folder name that * contains the templates) * @param templateBundle * the bundle of the calling plugin * @param customTemplatePath * the custom template path to load with * @param projectPath * the project path to prepend if the customTemplatePath is * relative * @param insideEclipse * if true, this engine should load resources from eclipse * bundles * @param resourceLoaderClass * the custom resource loader if not running inside eclipse * @return an initialized VelocityEngine * @throws Exception * if velocity engine creation fails */ public static VelocityEngine createVelocityEngine(String templateFamilyName, Bundle templateBundle, String customTemplatePath, IPath projectPath, boolean insideEclipse, Class resourceLoaderClass) throws Exception { StringBuffer templatePaths = new StringBuffer(); templatePaths.append("."); if (customTemplatePath != null && customTemplatePath.length() > 0) { templatePaths.append(","); File templateFolder = new File(customTemplatePath); if (!templateFolder.isAbsolute() && projectPath != null) { templateFolder = new File(projectPath.toFile(), customTemplatePath); } templatePaths.append(templateFolder.getAbsolutePath()); } templatePaths.append(","); templatePaths.append(new File("/Library/Application Support/TBLips/" + templateFamilyName).getAbsolutePath()); templatePaths.append(","); templatePaths.append(new File(System.getProperty("user.home"), "Documents and Settings/Application Data/TBLips/" + templateFamilyName).getAbsolutePath()); templatePaths.append(","); templatePaths.append(new File(System.getProperty("user.home"), "Documents and Settings/AppData/Local/TBLips/" + templateFamilyName).getAbsolutePath()); templatePaths.append(","); templatePaths.append(new File(System.getProperty("user.home"), "Library/Application Support/TBLips/" + templateFamilyName).getAbsolutePath()); Thread thread = Thread.currentThread(); ClassLoader loader = thread.getContextClassLoader(); thread.setContextClassLoader(resourceLoaderClass.getClassLoader()); try { VelocityEngine velocityEngine = new VelocityEngine(); velocityEngine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, org.apache.velocity.runtime.log.NullLogSystem.class.getName()); velocityEngine.setProperty("resource.loader", "file,wolips"); velocityEngine.setProperty("file.resource.loader.class", FileResourceLoader.class.getName()); velocityEngine.setProperty("file.resource.loader.path", templatePaths.toString()); if (insideEclipse) { velocityEngine.setProperty("wolips.resource.loader.class", ResourceLoader.class.getName()); if (templateBundle != null) { velocityEngine.setProperty("wolips.resource.loader.bundle", templateBundle); } } else if (resourceLoaderClass != null) { velocityEngine.setProperty("wolips.resource.loader.class", resourceLoaderClass.getName()); } velocityEngine.init(); return velocityEngine; } finally { thread.setContextClassLoader(loader); } } public static String writeTemplateToString(VelocityEngine engine, VelocityContext context, String templateName, ByteArrayOutputStream newFileContentsStream) throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, Exception { Template template; try { template = engine.getTemplate(templateName, "UTF-8"); } catch (ResourceNotFoundException e) { throw new Exception("Failed to load the template '" + templateName + "'. Check your model's eogen file to make sure that it specifies the correct template folder and template names."); } Writer newFileContentsWriter = new BufferedWriter(new OutputStreamWriter(newFileContentsStream, "UTF-8")); try { template.merge(context, newFileContentsWriter); } finally { newFileContentsWriter.close(); } String newFileContentsStr = newFileContentsStream.toString("UTF-8"); if (newFileContentsStr != null) { if (newFileContentsStr.contains("<%")) { throw new IOException("You are attempting to use an old EOGenerator template with Velocity EOGenerator."); } else if (newFileContentsStr.contains("<wo:")) { throw new IOException("You are attempting to use a JavaEOGenerator template with Velocity EOGenerator."); } else if (newFileContentsStr.contains("<tb:")) { throw new IOException("You are attempting to use a JavaEOGenerator template with Velocity EOGenerator."); } } return newFileContentsStr; } public static String writeTemplateToString(VelocityEngine engine, VelocityContext context, String templateName) throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, Exception { return writeTemplateToString(engine, context, templateName, new ByteArrayOutputStream()); } public static void writeTemplate(VelocityEngine engine, VelocityContext context, String templateName, OutputStream outputStream) throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, Exception { ByteArrayOutputStream newFileContentsStream = new ByteArrayOutputStream(); String newFileContentsStr = WOLipsVelocityUtils.writeTemplateToString(engine, context, templateName, newFileContentsStream); BufferedWriter newFileBufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream)); try { newFileBufferedWriter.write(newFileContentsStr); } finally { newFileBufferedWriter.close(); } } public static void writeTemplate(VelocityEngine engine, VelocityContext context, String templateName, File outputFile) throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, Exception { ByteArrayOutputStream newFileContentsStream = new ByteArrayOutputStream(); String newFileContentsStr = WOLipsVelocityUtils.writeTemplateToString(engine, context, templateName, newFileContentsStream); if (!outputFile.getParentFile().exists()) { if (!outputFile.getParentFile().mkdirs()) { throw new IOException("Unable to create the folder " + outputFile.getParentFile() + "."); } } boolean templateChanged = true; if (!outputFile.exists()) { BufferedWriter newFileBufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile), "UTF-8")); try { newFileBufferedWriter.write(newFileContentsStr); } finally { newFileBufferedWriter.close(); } } else { byte[] newFileContents = newFileContentsStream.toByteArray(); if (outputFile.exists()) { FileInputStream fis = new FileInputStream(outputFile); int bytesRemaining = (int) outputFile.length(); if (bytesRemaining == newFileContents.length) { byte[] oldFileContents; try { ByteArrayOutputStream bos = new ByteArrayOutputStream((int) outputFile.length()); byte[] buf = new byte[4096]; while (bytesRemaining > 0) { int bytesRead = fis.read(buf, 0, Math.min(buf.length, bytesRemaining)); bos.write(buf, 0, bytesRead); bytesRemaining -= bytesRead; } oldFileContents = bos.toByteArray(); } finally { fis.close(); } MessageDigest md5 = MessageDigest.getInstance("MD5"); byte[] oldMD5 = md5.digest(oldFileContents); md5.reset(); byte[] newMD5 = md5.digest(newFileContents); md5.reset(); if (oldMD5.length == newMD5.length) { templateChanged = false; for (int i = 0; !templateChanged && i < oldMD5.length; i++) { if (oldMD5[i] != newMD5[i]) { templateChanged = true; } } } } } if (templateChanged) { FileOutputStream newFileStream = new FileOutputStream(outputFile); BufferedOutputStream newFileBufferedStream = new BufferedOutputStream(newFileStream); try { newFileBufferedStream.write(newFileContents); } finally { newFileBufferedStream.close(); } } else { // System.out.println("EOGenerator.writeTemplate: skipping " + // outputFile); } } } }