View Javadoc

1   package org.andromda.ant.task;
2   
3   import java.io.FileNotFoundException;
4   import java.net.URL;
5   import java.util.Iterator;
6   import java.util.Map;
7   
8   import org.andromda.core.AndroMDA;
9   import org.andromda.core.common.ResourceUtils;
10  import org.apache.commons.lang.StringUtils;
11  import org.apache.commons.lang.exception.ExceptionUtils;
12  import org.apache.tools.ant.BuildException;
13  import org.apache.tools.ant.taskdefs.MatchingTask;
14  
15  
16  /***
17   * <p/> This class wraps the AndroMDA model processor so that AndroMDA can be
18   * used as an Ant task. Represents the <code>&lt;andromda&gt;</code> custom
19   * task which can be called from an Ant build script.
20   * </p>
21   *
22   * @author <a href="http://www.mbohlen.de">Matthias Bohlen </a>
23   * @author <a href="http://www.amowers.com">Anthony Mowers </a>
24   * @author Chad Brandon
25   * @see org.andromda.core.AndroMDA
26   */
27  public class AndroMDAGenTask
28      extends MatchingTask
29  {
30      /***
31       * Initialize the context class loader.
32       */
33      static
34      {
35          initializeContextClassLoader();
36      }
37  
38      /***
39       * Stores the configuration URI.
40       */
41      private URL configurationUri;
42  
43      /***
44       * Sets the URI to the configuration file.
45       *
46       * @param configurationUri
47       */
48      public void setConfigurationUri(final URL configurationUri)
49      {
50          this.configurationUri = configurationUri;
51      }
52  
53      /***
54       * <p/>
55       * Starts the generation of source code from an object model. </p>
56       * <p/>
57       * This is the main entry point of the application when running Ant. It is called by ant whenever the surrounding
58       * task is executed (which could be multiple times). </p>
59       *
60       * @throws BuildException if something goes wrong
61       */
62      public void execute()
63          throws BuildException
64      {
65          // initialize before the execute as well in case we
66          // want to execute more than once
67          initializeContextClassLoader();
68          try
69          {
70              if (this.configurationUri == null)
71              {
72                  throw new BuildException("Configuration is not a valid URI --> '" + this.configurationUri + "'");
73              }
74              final AndroMDA andromda = AndroMDA.newInstance();
75              if (andromda != null)
76              {
77                  andromda.run(
78                      this.replaceProperties(ResourceUtils.getContents(configurationUri)));
79                  andromda.shutdown();
80              }
81          }
82          catch (Throwable throwable)
83          {
84              final Throwable cause = ExceptionUtils.getCause(throwable);
85              if (cause != null)
86              {
87                  throwable = cause;
88              }
89              if (throwable instanceof FileNotFoundException)
90              {
91                  throw new BuildException("No configuration could be loaded from --> '" + configurationUri + "'");
92              }
93              throw new BuildException(throwable);
94          }
95          finally
96          {
97              // Set the context class loader back ot its system class loaders
98              // so that any processes running after won't be trying to use
99              // the ContextClassLoader for this class.
100             Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
101         }
102     }
103 
104     /***
105      * Replaces all properties having the style
106      * <code>${some.property}</code> with the value
107      * of the specified property if there is one.
108      *
109      * @param fileContents the fileContents to perform replacement on.
110      */
111     protected String replaceProperties(String string)
112     {
113         final Map properties = this.getProject().getProperties();
114         if (properties != null && !properties.isEmpty())
115         {
116             for (final Iterator iterator = properties.keySet().iterator(); iterator.hasNext();)
117             {
118                 final String name = (String)iterator.next();
119                 final String property = "${" + name + "}";
120                 final String value = (String)properties.get(name);
121                 string = StringUtils.replace(string, property, value);
122             }
123         }
124 
125         // remove any left over property references
126         string = this.removePropertyReferences(string);
127         return string;
128     }
129 
130     /***
131      * The property reference pattern.
132      */
133     private static final String PROPERTY_REFERENCE = "//$//{.*//}";
134 
135     /***
136      * Removes any ${some.property} type references from the string
137      * and returns the modifed string.
138      * @param string the string from which to remove the property
139      *        references
140      *
141      * @return the modified string.
142      */
143     public String removePropertyReferences(String string)
144     {
145         if (string != null)
146         {
147             string = string.replaceAll(PROPERTY_REFERENCE, "");
148         }
149         return string;
150     }
151 
152     /***
153      * Set the context class loader so that any classes using it (the contextContextClassLoader) have access to the
154      * correct loader.
155      */
156     private final static void initializeContextClassLoader()
157     {
158         Thread.currentThread().setContextClassLoader(AndroMDAGenTask.class.getClassLoader());
159     }
160 }