1 package org.andromda.ant.task;
2
3 import java.io.FileNotFoundException;
4 import java.net.URL;
5 import java.util.Map;
6 import org.andromda.core.AndroMDA;
7 import org.andromda.core.common.ResourceUtils;
8 import org.apache.commons.lang.StringUtils;
9 import org.apache.commons.lang.exception.ExceptionUtils;
10 import org.apache.tools.ant.BuildException;
11 import org.apache.tools.ant.taskdefs.MatchingTask;
12
13 /**
14 * <p/> This class wraps the AndroMDA model processor so that AndroMDA can be
15 * used as an Ant task. Represents the <code><andromda></code> custom
16 * task which can be called from an Ant build script.
17 * </p>
18 *
19 * @author <a href="http://www.mbohlen.de">Matthias Bohlen </a>
20 * @author <a href="http://www.amowers.com">Anthony Mowers </a>
21 * @author Chad Brandon
22 * @see org.andromda.core.AndroMDA
23 */
24 public class AndroMDAGenTask
25 extends MatchingTask
26 {
27 /**
28 * Initialize the context class loader.
29 */
30 static
31 {
32 initializeContextClassLoader();
33 }
34
35 /**
36 * Stores the configuration URI.
37 */
38 private URL configurationUri;
39
40 /**
41 * Sets the URI to the configuration file.
42 *
43 * @param configurationUri
44 */
45 public void setConfigurationUri(final URL configurationUri)
46 {
47 this.configurationUri = configurationUri;
48 }
49
50 /**
51 * <p/>
52 * Starts the generation of source code from an object model. </p>
53 * <p/>
54 * This is the main entry point of the application when running Ant. It is called by ant whenever the surrounding
55 * task is executed (which could be multiple times). </p>
56 *
57 * @throws BuildException if something goes wrong
58 */
59 public void execute()
60 throws BuildException
61 {
62 // initialize before the execute as well in case we
63 // want to execute more than once
64 initializeContextClassLoader();
65 try
66 {
67 if (this.configurationUri == null)
68 {
69 throw new BuildException("Configuration is not a valid URI --> '" + this.configurationUri + '\'');
70 }
71 final AndroMDA andromda = AndroMDA.newInstance();
72 if (andromda != null)
73 {
74 andromda.run(
75 this.replaceProperties(ResourceUtils.getContents(configurationUri)));
76 andromda.shutdown();
77 }
78 }
79 catch (Throwable throwable)
80 {
81 final Throwable cause = ExceptionUtils.getCause(throwable);
82 if (cause != null)
83 {
84 throwable = cause;
85 }
86 if (throwable instanceof FileNotFoundException)
87 {
88 throw new BuildException("No configuration could be loaded from --> '" + configurationUri + '\'');
89 }
90 throw new BuildException(throwable);
91 }
92 finally
93 {
94 // Set the context class loader back ot its system class loaders
95 // so that any processes running after won't be trying to use
96 // the ContextClassLoader for this class.
97 Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
98 }
99 }
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 }