001package org.andromda.ant.task; 002 003import java.io.FileNotFoundException; 004import java.net.URL; 005import java.util.Map; 006import org.andromda.core.AndroMDA; 007import org.andromda.core.common.ResourceUtils; 008import org.apache.commons.lang.StringUtils; 009import org.apache.commons.lang.exception.ExceptionUtils; 010import org.apache.tools.ant.BuildException; 011import org.apache.tools.ant.taskdefs.MatchingTask; 012 013/** 014 * <p/> This class wraps the AndroMDA model processor so that AndroMDA can be 015 * used as an Ant task. Represents the <code><andromda></code> custom 016 * task which can be called from an Ant build script. 017 * </p> 018 * 019 * @author <a href="http://www.mbohlen.de">Matthias Bohlen </a> 020 * @author <a href="http://www.amowers.com">Anthony Mowers </a> 021 * @author Chad Brandon 022 * @see org.andromda.core.AndroMDA 023 */ 024public class AndroMDAGenTask 025 extends MatchingTask 026{ 027 /** 028 * Initialize the context class loader. 029 */ 030 static 031 { 032 initializeContextClassLoader(); 033 } 034 035 /** 036 * Stores the configuration URI. 037 */ 038 private URL configurationUri; 039 040 /** 041 * Sets the URI to the configuration file. 042 * 043 * @param configurationUri 044 */ 045 public void setConfigurationUri(final URL configurationUri) 046 { 047 this.configurationUri = configurationUri; 048 } 049 050 /** 051 * <p/> 052 * Starts the generation of source code from an object model. </p> 053 * <p/> 054 * This is the main entry point of the application when running Ant. It is called by ant whenever the surrounding 055 * task is executed (which could be multiple times). </p> 056 * 057 * @throws BuildException if something goes wrong 058 */ 059 public void execute() 060 throws BuildException 061 { 062 // initialize before the execute as well in case we 063 // want to execute more than once 064 initializeContextClassLoader(); 065 try 066 { 067 if (this.configurationUri == null) 068 { 069 throw new BuildException("Configuration is not a valid URI --> '" + this.configurationUri + '\''); 070 } 071 final AndroMDA andromda = AndroMDA.newInstance(); 072 if (andromda != null) 073 { 074 andromda.run( 075 this.replaceProperties(ResourceUtils.getContents(configurationUri))); 076 andromda.shutdown(); 077 } 078 } 079 catch (Throwable throwable) 080 { 081 final Throwable cause = ExceptionUtils.getCause(throwable); 082 if (cause != null) 083 { 084 throwable = cause; 085 } 086 if (throwable instanceof FileNotFoundException) 087 { 088 throw new BuildException("No configuration could be loaded from --> '" + configurationUri + '\''); 089 } 090 throw new BuildException(throwable); 091 } 092 finally 093 { 094 // Set the context class loader back ot its system class loaders 095 // so that any processes running after won't be trying to use 096 // the ContextClassLoader for this class. 097 Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader()); 098 } 099 } 100 101 /** 102 * Replaces all properties having the style 103 * <code>${some.property}</code> with the value 104 * of the specified property if there is one. 105 * 106 * @param string the fileContents to perform replacement on. 107 * @return replaced properties 108 */ 109 protected String replaceProperties(String string) 110 { 111 @SuppressWarnings("unchecked") 112 final Map<String, Object> properties = this.getProject().getProperties(); 113 if (properties != null) 114 { 115 for (Map.Entry<String, Object> entry : properties.entrySet()) 116 { 117 final String name = entry.getKey(); 118 final String value = (String)entry.getValue(); 119 final String property = "${" + name + '}'; 120 string = StringUtils.replace(string, property, value); 121 } 122 } 123 124 // remove any left over property references 125 string = this.removePropertyReferences(string); 126 return string; 127 } 128 129 /** 130 * The property reference pattern. 131 */ 132 private static final String PROPERTY_REFERENCE = "\\$\\{.*\\}"; 133 134 /** 135 * Removes any ${some.property} type references from the string 136 * and returns the modifed string. 137 * @param string the string from which to remove the property 138 * references 139 * 140 * @return the modified string. 141 */ 142 public String removePropertyReferences(String string) 143 { 144 if (string != null) 145 { 146 string = string.replaceAll(PROPERTY_REFERENCE, ""); 147 } 148 return string; 149 } 150 151 /** 152 * Set the context class loader so that any classes using it (the contextContextClassLoader) have access to the 153 * correct loader. 154 */ 155 private static void initializeContextClassLoader() 156 { 157 Thread.currentThread().setContextClassLoader(AndroMDAGenTask.class.getClassLoader()); 158 } 159}