001: // THIS SOFTWARE IS PROVIDED BY SOFTARIS PTY.LTD. AND OTHER METABOSS
002: // CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
003: // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
004: // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTARIS PTY.LTD.
005: // OR OTHER METABOSS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
006: // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
007: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
008: // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
009: // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
010: // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
011: // EVEN IF SOFTARIS PTY.LTD. OR OTHER METABOSS CONTRIBUTORS ARE ADVISED OF THE
012: // POSSIBILITY OF SUCH DAMAGE.
013: //
014: // Copyright 2000-2005 © Softaris Pty.Ltd. All Rights Reserved.
015: package com.metaboss.sdlctools.applications.anttasks;
016:
017: import java.io.File;
018: import java.util.HashMap;
019: import java.util.Iterator;
020: import java.util.List;
021: import java.util.Map;
022: import java.util.Properties;
023:
024: import javax.jmi.reflect.JmiException;
025:
026: import org.apache.tools.ant.BuildException;
027: import org.apache.tools.ant.Project;
028:
029: import com.metaboss.sdlctools.models.ModelRepository;
030: import com.metaboss.sdlctools.models.ModelRepositoryException;
031: import com.metaboss.sdlctools.models.metabossmodel.MetaBossModelPackage;
032: import com.metaboss.sdlctools.models.metabossmodel.ModelElement;
033: import com.metaboss.util.ObjectUtils;
034:
035: /**
036: * The abstract MetaBoss Model Tool task. Automatically manages a single model loaded from the directory
037: * <p>In addition to attributes supported by base class task, this task supports
038: * following attributes:
039: * <table border="1" cellpadding="2" cellspacing="0">
040: * <tr>
041: * <th>Attribute Name</th>
042: * <th>Attribute Description</th>
043: * <th>Required</th>
044: * </tr>
045: * <tr>
046: * <td valign="top">modeldir</td>
047: * <td valign="top">The mandatory path to the directory where model is stored.(It has to
048: * point to the directory where top level Model.xml file is)
049: * </td>
050: * <td valign="top">Yes if task requires to load the model (most of the MetaBoss tasks are)</td>
051: * </tr>
052: * <tr>
053: * <td valign="top">ref</td>
054: * <td valign="top">The optional reference of the root element of the model. This is the
055: * specification of the element this task will be working on.
056: * </td>
057: * <td valign="top">Yes if task requires element to be specified</td>
058: * </tr>
059: * </table></p>
060: * <p>This task also supports following subelements:
061: * <table border="1" cellpadding="2" cellspacing="0">
062: * <tr>
063: * <th>SubElement Name</th>
064: * <th>SubElement Description</th>
065: * <th>Occurrs</th>
066: * </tr>
067: * <tr>
068: * <td valign="top">param</td>
069: * <td valign="top">Zero or more of these elements can be specified. Each one contains
070: * name-value pair to be passed as a parameter to the tool invoked in this task.
071: * </td>
072: * <td valign="top">Zero or more times</td>
073: * </tr>
074: * <tr>
075: * <td valign="top">env</td>
076: * <td valign="top">Zero or more of these elements can be specified. Each one contains
077: * name-value pair to be set into system environment before tool is invoked in this task.
078: * </td>
079: * <td valign="top">Zero or more times</td>
080: * </tr>
081: * </table></p>
082: */
083: public abstract class MetaBossModelToolTask extends MetaBossTask {
084: // The directory to read themodel from
085: private File mModelDir = null;
086: // The name of the model
087: private String mModelName = null;
088: // The flag directing whether the model should be opened
089: private boolean mUsesExistingModel = false;
090: // The top level package of the model
091: private MetaBossModelPackage mModelRootPackage = null;
092: // Optional root model element associated with this builder
093: private ModelElement mRootModelElement = null;
094: // Storage for the parameters to be passed as an arguments to the generator
095: private Properties mInvocationParameters = new Properties();
096: // Storage for the parameters to be set in the environment before running the generator
097: private Properties mInvocationEnvironment = new Properties();
098:
099: /** The only constructor available for the subclasses.
100: * @param pUsesExistingModel if it is set to true - the model stored in the directory
101: * pointed by the 'modeldir' attribute will be automatically opened - this is typical for the
102: * task using the existing models. If this is set to false than this task will ensure that the model
103: * does not exist at the specified directory and it is not loaded - this is typical for tasks
104: * creating the new models.
105: */
106: public MetaBossModelToolTask(boolean pUsesExistingModel) {
107: mUsesExistingModel = pUsesExistingModel;
108: }
109:
110: /** The hidden default constructor */
111: private MetaBossModelToolTask() {
112: }
113:
114: /** The setter for the "modeldir" attribute */
115: public void setModeldir(File pModelDir) throws BuildException {
116: mModelDir = pModelDir;
117: mModelName = mModelDir.getAbsolutePath() + File.separator
118: + "Model.xml";
119: if (mUsesExistingModel) {
120: try {
121: // Open the model
122: getLogger().info(
123: "Loading MetaBossEnterpriseModel from "
124: + mModelDir.getAbsolutePath()
125: + " file.");
126: ModelRepository lModelRepository = AntMetaBossUtils
127: .getModelRepository();
128: if (!lModelRepository.containsModel(mModelName))
129: lModelRepository.openModel(mModelName, new File(
130: mModelName),
131: ModelRepository.METAMODEL_NAME_METABOSS);
132: getLogger().info(
133: "Successfully loaded MetaBossEnterpriseModel from "
134: + mModelDir.getAbsolutePath()
135: + " file.");
136: } catch (ModelRepositoryException e) {
137: throw new BuildException(
138: "Error while opening the model : "
139: + e.getMessage());
140: }
141: }
142: }
143:
144: /** The setter for the "ref" attribute. At the moment only systemref is allowed */
145: public void setRef(String pRef) throws BuildException {
146: mRootModelElement = getModelElement(
147: pRef,
148: new Class[] { com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.System.class });
149: }
150:
151: /** Adds input parameter to be passed to the tool when it is invoked */
152: public void addConfiguredParam(NameValuePairType pParameter)
153: throws BuildException {
154: if (pParameter.getName() == null
155: || pParameter.getName().length() == 0)
156: throw new BuildException(
157: "Invocation parameter must have a non-empty name");
158: if (mInvocationParameters.put(pParameter.getName(), pParameter
159: .getValue()) != null)
160: throw new BuildException(
161: "Each invocation parameter must have a unique name. The name '"
162: + pParameter.getName()
163: + "' appears to have been used more than once.");
164: }
165:
166: /** Adds environment setting to be set in the system environment while tool is running */
167: public void addConfiguredEnv(NameValuePairType pEnvironment)
168: throws BuildException {
169: if (pEnvironment.getName() == null
170: || pEnvironment.getName().length() == 0)
171: throw new BuildException(
172: "Environment entry must have a non-empty name");
173: if (mInvocationEnvironment.put(pEnvironment.getName(),
174: pEnvironment.getValue()) != null)
175: throw new BuildException(
176: "Each environment entry must have a unique name. The name '"
177: + pEnvironment.getName()
178: + "' appears to have been used more than once.");
179: }
180:
181: /** The getter for the "modeldir" attribute */
182: public File getModelDir() throws BuildException {
183: if (mModelDir == null)
184: throw new BuildException(
185: "Missing 'modeldir' attribute, which is mandatory for <"
186: + getTaskName() + "> task.");
187: return mModelDir;
188: }
189:
190: /** The getter for the name of the model. Only works after "modeldir" attribute is set */
191: public String getModelName() throws BuildException {
192: if (mModelName == null)
193: throw new BuildException(
194: "Missing 'modeldir' attribute, which is mandatory for <"
195: + getTaskName() + "> task.");
196: return mModelName;
197: }
198:
199: /** The getter for the root package of the model. Only works after "modeldir" attribute is set */
200: public MetaBossModelPackage getModelRootPackage()
201: throws BuildException {
202: try {
203: return (MetaBossModelPackage) AntMetaBossUtils
204: .getModelRepository()
205: .getModelExtent(getModelName());
206: } catch (ModelRepositoryException e) {
207: throw new BuildException("Error while opening the model : "
208: + e.getMessage());
209: }
210: }
211:
212: /** The getter for the optional root element for the whole task */
213: public ModelElement getRootModelElement() throws BuildException {
214: return mRootModelElement;
215: }
216:
217: /** Finds model element with given reference or throws exception if none exists.
218: * Automatically verifies if returned element is one of the desired type.
219: * @param pModelElementRef - model element ref
220: * @param pExpectedClasses - array of expected java classes. This parameter is ignored if
221: * it is null or zero-length. Otherwise it is used to check the type of found class.
222: * @return found model element. If expected classes paramenter was given -
223: * the returned element is vetted against list of allowed classes. Never returns null
224: * @throws BuildException in case of troubles including the case when model element was not found or found model element is not of the expected type */
225: public ModelElement getModelElement(String pModelElementRef,
226: Class[] pExpectedClasses) throws BuildException {
227: try {
228: ModelElement lModelElement = getModelRootPackage()
229: .getModelElement().getByRef(pModelElementRef);
230: if (pExpectedClasses == null
231: || pExpectedClasses.length == 0)
232: return lModelElement; // Unchecked model element
233: if (!ObjectUtils
234: .isInstance(lModelElement, pExpectedClasses)) {
235: // Build the list of expected class names to be used in error message
236: StringBuffer lTypeNames = new StringBuffer();
237: for (int i = 0; i < pExpectedClasses.length; i++) {
238: if (i > 0)
239: lTypeNames.append(",");
240: lTypeNames.append("'");
241: lTypeNames.append(pExpectedClasses[i].getName());
242: lTypeNames.append("'");
243: }
244: if (pExpectedClasses.length == 1)
245: throw new BuildException(
246: "Returned model element type mismatch. Expected type "
247: + lTypeNames + ". Found instance "
248: + lModelElement.toString());
249: else
250: throw new BuildException(
251: "Returned model element type mismatch. Expected one of the types "
252: + lTypeNames + ". Found instance "
253: + lModelElement.toString());
254: }
255: return lModelElement; // Verified model element
256: } catch (JmiException e) {
257: throw new BuildException("Caught model exception : "
258: + e.getMessage());
259: }
260: }
261:
262: /** Finds all model elements matching given xpath.
263: * Automatically verifies if returned element is one of the desired type.
264: * @param pModelElementXPath - the xpath to use
265: * @param pExpectedClasses - array of expected java classes. This parameter is ignored if
266: * it is null or zero-length. Otherwise it is used to check the type of found class.
267: * @return found model elements. If expected classes paramenter was given -
268: * the returned element is vetted against list of allowed classes. May return zer-length array
269: * @throws BuildException in case of trouble */
270: public ModelElement[] findModelElementsByXPath(
271: ModelElement pContextElement, String pModelElementXPath,
272: Class[] pExpectedClasses) throws BuildException {
273: try {
274: List lMatchingElements = pContextElement != null ? AntMetaBossUtils
275: .getModelRepository().searchByXPath(
276: pContextElement, pModelElementXPath)
277: : AntMetaBossUtils.getModelRepository()
278: .searchByXPath(getModelName(),
279: pModelElementXPath);
280: if (lMatchingElements == null
281: || lMatchingElements.size() == 0)
282: return new ModelElement[0];
283: // We have got some elements returned. Ensure that they are of the right type
284: // Now iterate through the matching elements and ensure that each and every one of them is matching
285: for (Iterator lIter = lMatchingElements.iterator(); lIter
286: .hasNext();) {
287: Object lObject = lIter.next();
288: if (!ObjectUtils.isInstance(lObject, pExpectedClasses)) {
289: // Build the list of expected class names to be used in error message
290: StringBuffer lTypeNames = new StringBuffer();
291: for (int i = 0; i < pExpectedClasses.length; i++) {
292: if (i > 0)
293: lTypeNames.append(",");
294: lTypeNames.append("'");
295: lTypeNames
296: .append(pExpectedClasses[i].getName());
297: lTypeNames.append("'");
298: }
299: if (pExpectedClasses.length == 1)
300: throw new BuildException(
301: "Returned model element type mismatch. Expected type "
302: + lTypeNames
303: + ". Found instance "
304: + lObject.getClass().getName());
305: else
306: throw new BuildException(
307: "Returned model element type mismatch. Expected one of the types "
308: + lTypeNames
309: + ". Found instance "
310: + lObject.getClass().getName());
311: }
312: }
313: // Return verified model elements
314: return (ModelElement[]) lMatchingElements
315: .toArray(new ModelElement[lMatchingElements.size()]);
316: } catch (ModelRepositoryException e) {
317: throw new BuildException("Caught model exception : "
318: + e.getMessage());
319: } catch (JmiException e) {
320: throw new BuildException("Caught model exception : "
321: + e.getMessage());
322: }
323: }
324:
325: /** Finds model element with given reference or return null if none exists.
326: * Automatically verifies if returned element is one of the desired type.
327: * @param pModelElementRef - model element ref
328: * @param pExpectedClasses - array of expected java classes. This parameter is ignored if
329: * it is null or zero-length. Otherwise it is used to check the type of found class.
330: * @return found model element or null if element with specified ref was not found.
331: * If expected classes paramenter was given - the returned element is vetted against list of allowed classes.
332: * @throws BuildException in case of troubles including the case when found model element is not of the expected type */
333: public ModelElement findModelElement(String pModelElementRef,
334: Class[] pExpectedClasses) throws BuildException {
335: try {
336: ModelElement lModelElement = getModelRootPackage()
337: .getModelElement().findByRef(pModelElementRef);
338: if (lModelElement != null || pExpectedClasses == null
339: || pExpectedClasses.length == 0)
340: return lModelElement; // Unchecked model element
341: StringBuffer lTypeNames = new StringBuffer();
342: for (int i = 0; i < pExpectedClasses.length; i++) {
343: if (pExpectedClasses[i].isInstance(lModelElement))
344: return lModelElement;
345: if (i > 0)
346: lTypeNames.append(",");
347: lTypeNames.append("'");
348: lTypeNames.append(pExpectedClasses[i].getName());
349: lTypeNames.append("'");
350: }
351: if (pExpectedClasses.length == 1)
352: throw new BuildException(
353: "Returned model element type mismatch. Expected type "
354: + lTypeNames + ". Found instance "
355: + lModelElement.toString());
356: else
357: throw new BuildException(
358: "Returned model element type mismatch. Expected one of the types "
359: + lTypeNames + ". Found instance "
360: + lModelElement.toString());
361: } catch (JmiException e) {
362: throw new BuildException("Caught model exception : "
363: + e.getMessage());
364: }
365: }
366:
367: /** Returns the set of zero or more parameters to be passed to the tool when it is invoked */
368: protected Properties getInvocationParameters() {
369: return mInvocationParameters;
370: }
371:
372: /** Returns the set of zero or more environment settings to be set in the system environment while tool is running */
373: protected Properties getInvocationEnvironment() {
374: return mInvocationEnvironment;
375: }
376:
377: // This task is designed for override by the derived concrete tool invocation classes
378: public abstract void runTool() throws Exception;
379:
380: // The method actually executing the task
381: public void execute() throws BuildException {
382: try {
383: boolean lNeedToRestoreDefaultModelName = false;
384: String lOldDefaultModelName = null;
385: Map lOriginalEnvironmentProperties = new HashMap(); // Need to keep nulls
386: try {
387: if (mUsesExistingModel) {
388: log("Setting default model to " + getModelName(),
389: Project.MSG_VERBOSE);
390: // Save the default model name. Keep separate flag, so even if previous default model was null it will be restored
391: lOldDefaultModelName = AntMetaBossUtils
392: .getModelRepository().setDefaultModel(
393: getModelName());
394: lNeedToRestoreDefaultModelName = true;
395: }
396: // Set the additional environment variables if they were given
397: for (Iterator lIter = getInvocationEnvironment()
398: .entrySet().iterator(); lIter.hasNext();) {
399: Map.Entry lEnvironmentEntry = (Map.Entry) lIter
400: .next();
401: lOriginalEnvironmentProperties.put(
402: lEnvironmentEntry.getKey(), System
403: .setProperty(
404: (String) lEnvironmentEntry
405: .getKey(),
406: (String) lEnvironmentEntry
407: .getValue()));
408: }
409:
410: runTool();
411: } finally {
412: // Restore the default model name if necessary
413: if (lNeedToRestoreDefaultModelName) {
414: if (lOldDefaultModelName != null)
415: log("Setting default model to "
416: + lOldDefaultModelName,
417: Project.MSG_VERBOSE);
418: else
419: log("Setting default model to nothing",
420: Project.MSG_VERBOSE);
421: AntMetaBossUtils.getModelRepository()
422: .setDefaultModel(lOldDefaultModelName);
423: }
424: // Restore the additional environment variables if they were given
425: for (Iterator lIter = lOriginalEnvironmentProperties
426: .entrySet().iterator(); lIter.hasNext();) {
427: Map.Entry lOriginalEnvironmentEntry = (Map.Entry) lIter
428: .next();
429: if (lOriginalEnvironmentEntry.getValue() != null)
430: System.setProperty(
431: (String) lOriginalEnvironmentEntry
432: .getKey(),
433: (String) lOriginalEnvironmentEntry
434: .getValue());
435: else
436: System.getProperties().remove(
437: lOriginalEnvironmentEntry.getKey());
438: }
439: }
440: } catch (Throwable t) {
441: handleException(t);
442: }
443: }
444: }
|