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.builder.tools;
016:
017: import java.io.File;
018: import java.io.FileOutputStream;
019: import java.io.IOException;
020: import java.text.SimpleDateFormat;
021: import java.util.ArrayList;
022: import java.util.Arrays;
023: import java.util.Date;
024: import java.util.HashSet;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.Properties;
029: import java.util.Set;
030: import java.util.TreeMap;
031: import java.util.TreeSet;
032:
033: import org.apache.tools.ant.BuildException;
034: import org.apache.tools.ant.Project;
035: import org.apache.tools.ant.taskdefs.Jar;
036: import org.apache.tools.ant.taskdefs.Manifest;
037: import org.apache.tools.ant.taskdefs.ManifestException;
038: import org.apache.tools.ant.types.FileSet;
039: import org.apache.tools.ant.types.PatternSet;
040:
041: import com.metaboss.licensing.LicenseService;
042: import com.metaboss.sdlctools.applications.anttasks.builder.MetaBossBuilderTask;
043: import com.metaboss.sdlctools.applications.anttasks.builder.ToolInvocationDefinition;
044: import com.metaboss.util.DirectoryUtils;
045: import com.metaboss.util.PropertiesUtils;
046:
047: /** This definition is responsible for invocation of the Java compiler */
048: public class JarPackagerInvocationDefinition extends
049: ToolInvocationDefinition {
050: public static String VERSION_PROPERTIES_FILE_NAME = "metaboss.version.properties";
051: public static String CONTENTS_PROPERTIES_FILE_NAME = "metaboss.contents.properties";
052: private static boolean sClassInitialised = false;
053: private static Object sClassInitialisationSemaphore = new Object();
054: private static LicenseService sLicenseService = null;
055: private static SimpleDateFormat sManifestDateFormat = null;
056: private static Manifest sDefaultManifest = null;
057: private static Properties sVersionProperties = null;
058: private String mDestFileName = null;
059: private Set mClassIncludes = new HashSet(); // Set of strings to include from classdir
060: private Set mClassExcludes = new HashSet(); // Set of strings to exclude from classdir
061: private Set mGensrcIncludes = new HashSet(); // Set of strings to include from gendir
062: private Set mGensrcExcludes = new HashSet(); // Set of strings to exclude from gendir
063: private List mFileSetIncludes = new ArrayList(); // Set of arbitrary file sets to include
064: private Map mJarContentsMap = new TreeMap();
065:
066: // Pseudo class initialiser. Main feature that we can throw exception from here (unable to do that from native java class initialiser)
067: protected static void initialiseClassIfNecessary()
068: throws BuildException {
069: if (!sClassInitialised) {
070: synchronized (sClassInitialisationSemaphore) {
071: if (!sClassInitialised) {
072: try {
073: javax.naming.Context lCtx = new javax.naming.InitialContext();
074: sLicenseService = (LicenseService) lCtx
075: .lookup(LicenseService.COMPONENT_URL);
076: } catch (javax.naming.NamingException e) {
077: throw new BuildException(
078: "Unable to initialise MetaBoss licensing mechanism.",
079: e);
080: }
081: sManifestDateFormat = new SimpleDateFormat(
082: "dd MMM yyyy");
083: // Build default manifest once
084: try {
085: sDefaultManifest = new Manifest();
086: // --- Add product details
087: sDefaultManifest
088: .addConfiguredAttribute(new Manifest.Attribute(
089: sLicenseService
090: .getProductName()
091: + "-Version",
092: sLicenseService
093: .getProductName()
094: + " "
095: + sLicenseService
096: .getProductVersion()
097: + " ("
098: + sLicenseService
099: .getManufacturerName()
100: + ")"));
101: // --- Add build details
102: sDefaultManifest
103: .addConfiguredAttribute(new Manifest.Attribute(
104: "Built-By", sLicenseService
105: .getAuthorName()));
106: sDefaultManifest
107: .addConfiguredAttribute(new Manifest.Attribute(
108: "Built-Date",
109: sManifestDateFormat
110: .format(new Date())));
111: } catch (ManifestException e) {
112: throw new BuildException(
113: "Unexpected exception has occurred.", e);
114: }
115:
116: // Initialise metaboss version properties file
117: sVersionProperties = new Properties();
118: sVersionProperties
119: .put(
120: "com.metaboss.release.id.majorversion",
121: PropertiesUtils
122: .getMandatorySystemProperty("com.metaboss.release.id.majorversion"));
123: sVersionProperties
124: .put(
125: "com.metaboss.release.id.minorversion",
126: PropertiesUtils
127: .getMandatorySystemProperty("com.metaboss.release.id.minorversion"));
128: sVersionProperties
129: .put(
130: "com.metaboss.release.id.buildnumber",
131: PropertiesUtils
132: .getMandatorySystemProperty("com.metaboss.release.id.buildnumber"));
133:
134: sClassInitialised = true;
135: }
136: }
137: }
138: }
139:
140: /** Public constructor for the invocation */
141: public JarPackagerInvocationDefinition(
142: MetaBossBuilderTask pOwnerTask) throws BuildException {
143: super (pOwnerTask, "Package jar archive file");
144: initialiseClassIfNecessary();
145: }
146:
147: // Override to return better description if possible
148: public String getToolInvocationName() {
149: if (mDestFileName == null)
150: return super .getToolInvocationName();
151: return "Package " + getDestinationFile().getAbsolutePath()
152: + " archive file";
153: }
154:
155: /** Sets the destination archive file name */
156: public void setDestFileName(String pDestFileName) {
157: mDestFileName = pDestFileName;
158: }
159:
160: /** Sets the destination archive file name */
161: public File getDestinationFile() {
162: if (mDestFileName == null)
163: throw new BuildException(
164: "Missing DestFileName, which is mandatory for jar packager invocation.");
165: return new File(getOwnerTask().getLibDir().getAbsolutePath()
166: + File.separator + mDestFileName);
167: }
168:
169: /** Adds list of file set includes */
170: public void addFileSetIncludes(FileSet[] pFileSetIncludes) {
171: mFileSetIncludes.addAll(Arrays.asList(pFileSetIncludes));
172: }
173:
174: /** Adds single file set include */
175: public void addFileSetInclude(FileSet pFileSetIncludes) {
176: mFileSetIncludes.add(pFileSetIncludes);
177: }
178:
179: /** Adds list of class includes */
180: public void addClassIncludes(String[] pClassIncludes) {
181: mClassIncludes.addAll(Arrays.asList(pClassIncludes));
182: }
183:
184: /** Adds single class include */
185: public void addClassInclude(String pClassInclude) {
186: mClassIncludes.add(pClassInclude);
187: }
188:
189: /** Adds list of class excludes */
190: public void addClassExcludes(String[] pClassExcludes) {
191: mClassExcludes.addAll(Arrays.asList(pClassExcludes));
192: }
193:
194: /** Adds single class exclude */
195: public void addClassExclude(String pClassExclude) {
196: mClassExcludes.add(pClassExclude);
197: }
198:
199: /** Adds list of gensrc includes */
200: public void addGensrcIncludes(String[] pGensrcIncludes) {
201: mGensrcIncludes.addAll(Arrays.asList(pGensrcIncludes));
202: }
203:
204: /** Adds single gensrc include */
205: public void addGensrcInclude(String pGensrcInclude) {
206: mGensrcIncludes.add(pGensrcInclude);
207: }
208:
209: /** Adds list of gensrc excludes */
210: public void addGensrcExcludes(String[] pGensrcExcludes) {
211: mGensrcExcludes.addAll(Arrays.asList(pGensrcExcludes));
212: }
213:
214: /** Adds single gensrc exclude */
215: public void addGensrcExclude(String pGensrcExclude) {
216: mGensrcExcludes.add(pGensrcExclude);
217: }
218:
219: /** Adds single jar contents information entry */
220: public void addJarContentsEntry(String pGeneratorId,
221: String pModelElementRef) {
222: Set lGeneratedElementsSet = (Set) mJarContentsMap
223: .get(pGeneratorId);
224: if (lGeneratedElementsSet == null)
225: mJarContentsMap.put(pGeneratorId,
226: lGeneratedElementsSet = new TreeSet());
227: lGeneratedElementsSet.add(pModelElementRef);
228: }
229:
230: /** Adds whole map of information entries */
231: public void addJarContents(Map pJarContents) {
232: for (Iterator lJarContentsIter = pJarContents.entrySet()
233: .iterator(); lJarContentsIter.hasNext();) {
234: Map.Entry lContentsEntry = (Map.Entry) lJarContentsIter
235: .next();
236: String lGeneratorId = (String) lContentsEntry.getKey();
237: Set lModelElementRefsSet = (Set) lContentsEntry.getValue();
238: Set lGeneratedElementsSet = (Set) mJarContentsMap
239: .get(lGeneratorId);
240: if (lGeneratedElementsSet == null)
241: mJarContentsMap.put(lGeneratorId,
242: lGeneratedElementsSet = new TreeSet());
243: lGeneratedElementsSet.addAll(lModelElementRefsSet);
244: }
245: }
246:
247: /** Overridden to compare details of the invocation */
248: public boolean equals(Object pOther) {
249: if (this == pOther)
250: return true;
251: if (pOther instanceof JarPackagerInvocationDefinition) {
252: JarPackagerInvocationDefinition lOther = (JarPackagerInvocationDefinition) pOther;
253: // Compare class includes
254: if (mClassIncludes.size() != lOther.mClassIncludes.size())
255: return false;
256: for (Iterator lIncludesIterator = lOther.mClassIncludes
257: .iterator(); lIncludesIterator.hasNext();) {
258: if (!mClassIncludes.contains(lIncludesIterator.next()))
259: return false;
260: }
261: // Compare class excludes
262: if (mClassExcludes.size() != lOther.mClassExcludes.size())
263: return false;
264: for (Iterator lExcludesIterator = lOther.mClassExcludes
265: .iterator(); lExcludesIterator.hasNext();) {
266: if (!mClassExcludes.contains(lExcludesIterator.next()))
267: return false;
268: }
269: if (mDestFileName != null && lOther.mDestFileName == null)
270: return false;
271: if (mDestFileName == null && lOther.mDestFileName != null)
272: return false;
273: if (mDestFileName != null
274: && lOther.mDestFileName != null
275: && mDestFileName.equals(lOther.mDestFileName) == false)
276: return false;
277: return true; // Everything appears to be in order
278: }
279: return false;
280: }
281:
282: /** This method will have to invoke the generator */
283: public void invoke() throws BuildException {
284: try {
285: File lMetaDataTempDir = null;
286: try {
287: MetaBossBuilderTask lOwnerTask = getOwnerTask();
288: Project lThisProject = getOwnerTask().getProject();
289: // Now create and execute the java compiler task
290: Jar lJarTask = (Jar) lThisProject.createTask("jar");
291: lJarTask.setTaskName(lOwnerTask.getTaskName());
292: lJarTask.setDestFile(getDestinationFile());
293: // Clases fileset. Only if there is anything to do
294: if (mClassIncludes.isEmpty() == false
295: || mClassExcludes.isEmpty() == false) {
296: FileSet lClassesFileSet = new FileSet();
297: lClassesFileSet.setProject(lThisProject);
298: lClassesFileSet.setDir(lOwnerTask.getClassDir());
299: for (Iterator lIncludesIterator = mClassIncludes
300: .iterator(); lIncludesIterator.hasNext();) {
301: PatternSet.NameEntry lIncludeNameEntry = lClassesFileSet
302: .createInclude();
303: String lInclude = (String) lIncludesIterator
304: .next();
305: lIncludeNameEntry.setName(lInclude);
306: }
307: // Class Excludes
308: for (Iterator lExcludesIterator = mClassExcludes
309: .iterator(); lExcludesIterator.hasNext();) {
310: PatternSet.NameEntry lExcludeNameEntry = lClassesFileSet
311: .createExclude();
312: String lExclude = (String) lExcludesIterator
313: .next();
314: lExcludeNameEntry.setName(lExclude);
315: }
316: lJarTask.addFileset(lClassesFileSet);
317: }
318:
319: // Sources fileset. Only if there is anything to do
320: if (mGensrcIncludes.isEmpty() == false
321: || mGensrcExcludes.isEmpty() == false) {
322: FileSet lGensrcFileSet = new FileSet();
323: lGensrcFileSet.setProject(lThisProject);
324: lGensrcFileSet.setDir(lOwnerTask.getGenDir());
325: for (Iterator lIncludesIterator = mGensrcIncludes
326: .iterator(); lIncludesIterator.hasNext();) {
327: PatternSet.NameEntry lIncludeNameEntry = lGensrcFileSet
328: .createInclude();
329: lIncludeNameEntry
330: .setName((String) lIncludesIterator
331: .next());
332: }
333: // Class Excludes
334: for (Iterator lExcludesIterator = mGensrcExcludes
335: .iterator(); lExcludesIterator.hasNext();) {
336: PatternSet.NameEntry lExcludeNameEntry = lGensrcFileSet
337: .createExclude();
338: lExcludeNameEntry
339: .setName((String) lExcludesIterator
340: .next());
341: }
342: lJarTask.addFileset(lGensrcFileSet);
343: }
344: // Other filesets
345: for (Iterator lFileSetIncludesIterator = mFileSetIncludes
346: .iterator(); lFileSetIncludesIterator.hasNext();) {
347: FileSet lIncludedFileSet = (FileSet) lFileSetIncludesIterator
348: .next();
349: lJarTask.addFileset(lIncludedFileSet);
350: }
351:
352: // Add manifest to the jar
353: lJarTask.addConfiguredManifest(sDefaultManifest);
354:
355: // Create temporary directory to store files in
356: lMetaDataTempDir = DirectoryUtils.createTempDir(
357: "metaboss", "");
358:
359: // Create metaboss.version.properties file
360: {
361: File lVersionPropertiesFile = new File(
362: lMetaDataTempDir.getAbsolutePath()
363: + File.separator
364: + VERSION_PROPERTIES_FILE_NAME);
365: FileOutputStream lVersionPropertiesFileOutputStream = new FileOutputStream(
366: lVersionPropertiesFile);
367: sVersionProperties
368: .store(
369: lVersionPropertiesFileOutputStream,
370: "This file contains the version information of the MetaBoss release it was built with.");
371: lVersionPropertiesFileOutputStream.flush();
372: lVersionPropertiesFileOutputStream.close();
373: // Declare the fileset to the jar
374: FileSet lVersionFileSet = new FileSet();
375: lVersionFileSet.setProject(lThisProject);
376: lVersionFileSet.setDir(lMetaDataTempDir);
377: lVersionFileSet.createInclude().setName(
378: VERSION_PROPERTIES_FILE_NAME);
379: lJarTask.addFileset(lVersionFileSet);
380: }
381:
382: // See if we need to create metaboss.contents.properties file in the root directory
383: if (!mJarContentsMap.isEmpty()) {
384: //First we need to build the list of properties to save
385: // the format of the key is Generator:<generator id>.<index>
386: // the format of the value is ModelRef:<model element reference>
387: Properties lProperties = new Properties();
388: for (Iterator lJarContentsIter = mJarContentsMap
389: .entrySet().iterator(); lJarContentsIter
390: .hasNext();) {
391: Map.Entry lContentsEntry = (Map.Entry) lJarContentsIter
392: .next();
393: String lGeneratorId = (String) lContentsEntry
394: .getKey();
395: Set lGeneratedElementRefs = (Set) lContentsEntry
396: .getValue();
397: int lNextEntryIndex = 1;
398: for (Iterator lGeneratedElementRefsIterator = lGeneratedElementRefs
399: .iterator(); lGeneratedElementRefsIterator
400: .hasNext();) {
401: String lGeneratedElementRef = (String) lGeneratedElementRefsIterator
402: .next();
403: lProperties
404: .put(
405: lGeneratorId
406: + "."
407: + Integer
408: .toString(lNextEntryIndex++),
409: lGeneratedElementRef);
410: }
411: }
412: // Save this property fiel in the temp directory
413: File lContentsPropertiesFile = new File(
414: lMetaDataTempDir.getAbsolutePath()
415: + File.separator
416: + CONTENTS_PROPERTIES_FILE_NAME);
417: FileOutputStream lContentsPropertiesFileOutputStream = new FileOutputStream(
418: lContentsPropertiesFile);
419: lProperties
420: .store(
421: lContentsPropertiesFileOutputStream,
422: "This file lists contents of this archive in terms of generators and model elements these generators have worked on.");
423: lContentsPropertiesFileOutputStream.flush();
424: lContentsPropertiesFileOutputStream.close();
425: // Declare the fileset to the jar
426: FileSet lContentsFileSet = new FileSet();
427: lContentsFileSet.setProject(lThisProject);
428: lContentsFileSet.setDir(lMetaDataTempDir);
429: lContentsFileSet.createInclude().setName(
430: CONTENTS_PROPERTIES_FILE_NAME);
431: lJarTask.addFileset(lContentsFileSet);
432: }
433: // Execute the task
434: lJarTask.execute();
435: } finally {
436: if (lMetaDataTempDir != null
437: && lMetaDataTempDir.exists())
438: DirectoryUtils.deleteDirectory(lMetaDataTempDir);
439: }
440: } catch (ManifestException e) {
441: throw new BuildException(
442: "Unexpected exception has occurred.", e);
443: } catch (IOException e) {
444: throw new BuildException(
445: "Unexpected exception has occurred.", e);
446: }
447: }
448: }
|