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.services.jdktools.impl;
016:
017: import java.io.ByteArrayInputStream;
018: import java.io.ByteArrayOutputStream;
019: import java.io.File;
020: import java.io.FileFilter;
021: import java.io.FileInputStream;
022: import java.io.FileNotFoundException;
023: import java.io.FileOutputStream;
024: import java.io.FileWriter;
025: import java.io.IOException;
026: import java.util.ArrayList;
027: import java.util.jar.JarEntry;
028: import java.util.jar.JarOutputStream;
029: import java.util.zip.ZipEntry;
030: import java.util.zip.ZipInputStream;
031:
032: import com.metaboss.enterprise.bs.BSException;
033: import com.metaboss.enterprise.bs.BSIllegalArgumentException;
034: import com.metaboss.enterprise.bs.BSUndefinedSystemPropertyException;
035: import com.metaboss.enterprise.bs.BSUnexpectedProgramConditionException;
036: import com.metaboss.sdlctools.services.jdktools.BSJavaCompiler;
037: import com.metaboss.sdlctools.services.jdktools.CompilationResult;
038: import com.metaboss.sdlctools.services.jdktools.SourceType;
039: import com.metaboss.util.DirectoryUtils;
040: import com.metaboss.util.StringUtils;
041:
042: public class BSJavaCompilerImpl implements BSJavaCompiler {
043: /** Compiles given source and returns the jar file contents */
044: public CompilationResult compileSource(
045: String pPublicClassOrInterfaceName,
046: String pClassOrInterfaceSource, SourceType pSourceType)
047: throws BSException {
048: try {
049: // Grab the name for the temporary directory where compilation will take place
050: String lBaseDir = DirectoryUtils
051: .getUniqueTempDirectoryAbsolutePath();
052:
053: // Disassemble given class name and generate source directory name and the name of the java class
054: String lSourceBaseDirectoryName = lBaseDir + File.separator
055: + "src";
056: String lSourceRelativeDirectoryName = "";
057: String lSourceDirectoryName = "";
058: String lBaseFileName = "";
059: String lSourceFileName = "";
060: {
061: int lLastDotIndex = pPublicClassOrInterfaceName
062: .lastIndexOf(".");
063: if (lLastDotIndex > 0) {
064: String lPackage = pPublicClassOrInterfaceName
065: .substring(0, lLastDotIndex);
066: String lClass = pPublicClassOrInterfaceName
067: .substring(lLastDotIndex + 1);
068:
069: lSourceRelativeDirectoryName = StringUtils.replace(
070: lPackage, ".", File.separator);
071: lSourceDirectoryName = lSourceBaseDirectoryName
072: + File.separator
073: + lSourceRelativeDirectoryName;
074: lBaseFileName = lClass;
075: lSourceFileName = lBaseFileName + ".java";
076: } else {
077: String lPackage = "";
078: String lClass = pPublicClassOrInterfaceName;
079:
080: lSourceRelativeDirectoryName = "";
081: lSourceDirectoryName = lSourceBaseDirectoryName;
082: lBaseFileName = lClass;
083: lSourceFileName = lBaseFileName + ".java";
084: }
085: }
086:
087: // Make sure we have a new clean base directory
088: DirectoryUtils.ensureNewCleanDirectory(lBaseDir);
089:
090: try {
091: // Save the java source where it belongs
092: saveFile(lSourceDirectoryName, lSourceFileName,
093: pClassOrInterfaceSource);
094: // Now do the actual compile
095: String lCompilerTargetDirectoryName = lBaseDir
096: + "\\classes";
097: DirectoryUtils
098: .ensureNewCleanDirectory(lCompilerTargetDirectoryName);
099: String lCompilerOutput = compile(
100: lCompilerTargetDirectoryName,
101: new String[] { lSourceDirectoryName + "\\"
102: + lSourceFileName }, pSourceType);
103: if (lCompilerOutput != null)
104: return CompilationResult
105: .createCompilerFailure(lCompilerOutput);
106: // Now prepare jar file
107: return CompilationResult
108: .createCompilerSuccess(jarItUp(lCompilerTargetDirectoryName));
109: } finally {
110: // Clean up the directory after ourselves
111: DirectoryUtils.deleteDirectory(new File(lBaseDir));
112: }
113: } catch (IOException e) {
114: throw new BSException(
115: "Error while compiling the source file", e);
116: }
117: }
118:
119: /* Compiles given zip file with source and returns the jar file contents */
120: public CompilationResult compileZippedSource(byte[] pSourceZip,
121: SourceType pSourceType) throws BSException {
122: try {
123: // Grab the name for the temporary directory where compilation will take place
124: String lBaseDirectoryName = DirectoryUtils
125: .getUniqueTempDirectoryAbsolutePath();
126:
127: // Make sure we have a new clean base directory
128: DirectoryUtils.ensureNewCleanDirectory(lBaseDirectoryName);
129: // Flag indicating if directory needs to be cleaned up
130: boolean lDestroyDirectory = false;
131: try {
132: // Unzip the zip file contents in the src directory for compilation or classes directory for passing back
133: String lSourceDirectoryName = lBaseDirectoryName
134: + "\\src";
135: DirectoryUtils
136: .ensureNewCleanDirectory(lSourceDirectoryName);
137: String lTargetDirectoryName = lBaseDirectoryName
138: + "\\classes";
139: DirectoryUtils
140: .ensureNewCleanDirectory(lTargetDirectoryName);
141:
142: ZipInputStream lZipInputStream = new ZipInputStream(
143: new ByteArrayInputStream(pSourceZip));
144: ZipEntry lEntry = null;
145: ArrayList lFilesToCompile = new ArrayList();
146: while ((lEntry = lZipInputStream.getNextEntry()) != null) {
147: String lFileName = null;
148: String lRelativeFileName = lEntry.getName();
149: if (lRelativeFileName.endsWith(".java")) {
150: lFileName = lSourceDirectoryName
151: + (lRelativeFileName
152: .startsWith(File.separator) ? ""
153: : File.separator)
154: + lRelativeFileName;
155: lFilesToCompile.add(lFileName);
156: } else {
157: lFileName = lTargetDirectoryName
158: + (lRelativeFileName
159: .startsWith(File.separator) ? ""
160: : File.separator)
161: + lRelativeFileName;
162: }
163:
164: FileOutputStream lFileStream = null;
165: try {
166: File lFile = new File(lFileName);
167: DirectoryUtils.ensureThereIsDirectory(lFile
168: .getParent());
169: lFileStream = new FileOutputStream(lFileName,
170: false);
171: byte[] lTempBuff = new byte[1000];
172: int lReadLen = 0;
173: while ((lReadLen = lZipInputStream.read(
174: lTempBuff, 0, lTempBuff.length)) > 0)
175: lFileStream.write(lTempBuff, 0, lReadLen);
176: lFileStream.flush();
177: } finally {
178: if (lFileStream != null)
179: lFileStream.close();
180: }
181: }
182:
183: if (lFilesToCompile.size() > 0) {
184: String lCompilerOutput = compile(
185: lTargetDirectoryName,
186: (String[]) lFilesToCompile
187: .toArray(new String[lFilesToCompile
188: .size()]), pSourceType);
189: if (lCompilerOutput != null)
190: return CompilationResult
191: .createCompilerFailure(lCompilerOutput);
192: }
193: // Since there was a success in compilation - no one really needs to see the intermediate directory
194: lDestroyDirectory = true;
195: // Just prepare the jar file without compilation
196: return CompilationResult
197: .createCompilerSuccess(jarItUp(lTargetDirectoryName));
198: } catch (FileNotFoundException e) {
199: throw new BSException(
200: "Error while compiling the zipped source file",
201: e);
202: } finally {
203: // Clean up the directory after ourselves
204: if (lDestroyDirectory)
205: DirectoryUtils.deleteDirectory(new File(
206: lBaseDirectoryName));
207: }
208: } catch (IOException e) {
209: throw new BSException(
210: "Error while compiling the zipped source file", e);
211: }
212: }
213:
214: /* Compiles all java files under given local directory and returns the jar file contents */
215: public CompilationResult compileLocalSource(
216: String pSourceDirAbsolutePath, SourceType pSourceType)
217: throws BSException {
218: try {
219: // Grab the name for the temporary directory where compilation will take place
220: String lBaseDirectoryName = DirectoryUtils
221: .getUniqueTempDirectoryAbsolutePath();
222: String lTargetDirectoryName = lBaseDirectoryName
223: + "\\classes";
224: // Make sure we have a new clean base directory
225: DirectoryUtils
226: .ensureNewCleanDirectory(lTargetDirectoryName);
227: try {
228: // Check that source directory exists and it is a directory
229: File lSourceDir = new File(pSourceDirAbsolutePath);
230: if (!lSourceDir.exists())
231: throw new BSIllegalArgumentException(
232: "Specified source directory does not exist: "
233: + pSourceDirAbsolutePath);
234: if (!lSourceDir.isDirectory())
235: throw new BSIllegalArgumentException(
236: "Specified source directory is not a directory: "
237: + pSourceDirAbsolutePath);
238: // Collect names of all java files in the source directory
239: String[] lFilesToCompile = DirectoryUtils
240: .listAllFilesInDirectory(
241: pSourceDirAbsolutePath,
242: new FileFilter() {
243: public boolean accept(File pPathname) {
244: return pPathname.isDirectory()
245: || pPathname
246: .getName()
247: .toLowerCase()
248: .endsWith(
249: ".java");
250: }
251: });
252: if (lFilesToCompile.length > 0) {
253: String lCompilerOutput = compile(
254: lTargetDirectoryName, lFilesToCompile,
255: pSourceType);
256: if (lCompilerOutput != null)
257: return CompilationResult
258: .createCompilerFailure(lCompilerOutput);
259: // Now prepare jar file
260: return CompilationResult
261: .createCompilerSuccess(jarItUp(lTargetDirectoryName));
262: }
263: // Just prepare the jar file without compilation
264: return CompilationResult
265: .createCompilerSuccess(jarItUp(lTargetDirectoryName));
266: } catch (FileNotFoundException e) {
267: // Unexpected because we have specifically checked that directory exists
268: throw new BSUnexpectedProgramConditionException(e);
269: } finally {
270: // Clean up the directory after ourselves
271: DirectoryUtils.deleteDirectory(new File(
272: lBaseDirectoryName));
273: }
274: } catch (IOException e) {
275: throw new BSException(
276: "Error while compiling the local source file", e);
277: }
278: }
279:
280: // Helper. Compiles give source files and leaves output at the specified target
281: // returns non-empty string with compiler output in case of error
282: private static String compile(String pTargetDirectoryName,
283: String[] pSourceFileList, SourceType pSourceType)
284: throws BSException {
285: // Build compiler arguments
286: ArrayList lArgs = new ArrayList();
287: lArgs.add("-d");
288: lArgs.add(pTargetDirectoryName);
289: String lAdditionalClasspath = getAdditionalClasspathForSourceType(pSourceType);
290: if (lAdditionalClasspath != null) {
291: lArgs.add("-classpath");
292: lArgs.add(lAdditionalClasspath);
293: }
294: for (int i = 0; i < pSourceFileList.length; i++)
295: lArgs.add(pSourceFileList[i]);
296:
297: // Compile
298: java.io.PrintStream lOriginalOutputStream = System.out;
299: java.io.PrintStream lOriginalErrorStream = System.err;
300: try {
301: java.io.ByteArrayOutputStream lOutputStream = new java.io.ByteArrayOutputStream();
302: java.io.PrintStream lOutputStreamWrapper = new java.io.PrintStream(
303: lOutputStream);
304: System.setOut(lOutputStreamWrapper);
305: System.setErr(lOutputStreamWrapper);
306: com.sun.tools.javac.Main.compile((String[]) lArgs
307: .toArray(new String[lArgs.size()]));
308: lOutputStreamWrapper.flush();
309: String lReturn = lOutputStream.toString();
310: if (lReturn == null || lReturn.trim().length() == 0)
311: return null;
312: return lReturn.trim();
313: } finally {
314: System.setOut(lOriginalOutputStream);
315: System.setErr(lOriginalErrorStream);
316: }
317:
318: //System.setOut(printStream); // saving old out stream
319: //System.setErr(printStream); // saving old err stream
320: //outStream.println("out1"); // writes successfullyerr
321: //Stream.println("err1"); // writes successfully
322: // set params for javac:String[] argsCompile = {"-classpath", // ... further settings
323: //com.sun.tools.javac.Main.main(argsCompile); // compilesout
324: //Stream.println("out2"); // does NOT write !!!err
325: //Stream.println("err2"); // does NOT write !!!
326:
327: }
328:
329: // Helper. Creates the specified jar file and jars up everything from the specified directory downward
330: private static byte[] jarItUp(String pJarBaseDirectoryName)
331: throws BSException {
332: ByteArrayOutputStream lOutputStream = new ByteArrayOutputStream();
333: JarOutputStream lJarStream = null;
334: try {
335: lJarStream = new JarOutputStream(lOutputStream);
336: String[] lFilesToJar = DirectoryUtils
337: .listAllFilesInDirectory(pJarBaseDirectoryName);
338: for (int i = 0; i < lFilesToJar.length; i++) {
339: String lAbsoluteFileName = lFilesToJar[i];
340: String lRelativeFileName = lAbsoluteFileName
341: .substring(pJarBaseDirectoryName.length());
342: if (lRelativeFileName.startsWith("\\"))
343: lRelativeFileName = lRelativeFileName.substring(1);
344: JarEntry lJarEntry = new JarEntry(lRelativeFileName);
345: lJarStream.putNextEntry(lJarEntry);
346:
347: FileInputStream lFileInputStream = new FileInputStream(
348: lAbsoluteFileName);
349: try {
350: byte buffer[] = new byte[1024];
351: int bytesRead;
352: while ((bytesRead = lFileInputStream.read(buffer)) != -1)
353: lJarStream.write(buffer, 0, bytesRead);
354: } finally {
355: lFileInputStream.close();
356: }
357: }
358: lJarStream.flush();
359: lJarStream.close();
360: lJarStream = null;
361: lOutputStream.flush();
362: return lOutputStream.toByteArray();
363: } catch (FileNotFoundException e) {
364: throw new BSException(
365: "Error while creating an output jar file", e);
366: } catch (IOException e) {
367: throw new BSException(
368: "Error while creating an output jar file", e);
369: } finally {
370: if (lJarStream != null) {
371: try {
372: lJarStream.close();
373: } catch (IOException e) {
374: // Ignore
375: }
376: }
377: }
378: }
379:
380: // Helper. Saves given contents at the given location
381: private static void saveFile(String pDirectoryName,
382: String pFileName, String pFileContents) throws BSException {
383: // Save the java source where it belongs
384: FileWriter lWriter = null;
385: try {
386: DirectoryUtils.ensureNewCleanDirectory(pDirectoryName);
387: lWriter = new FileWriter(pDirectoryName + "\\" + pFileName,
388: false);
389: lWriter.write(pFileContents);
390: } catch (IOException e) {
391: throw new BSException("Error while saving file", e);
392: } finally {
393: if (lWriter != null) {
394: try {
395: lWriter.flush();
396: } catch (IOException e) {
397: // Ignore
398: }
399: try {
400: lWriter.close();
401: } catch (IOException e) {
402: // Ignore
403: }
404: }
405: }
406: }
407:
408: // Helper. Returns classpath for the source type or null if basic one will do
409: private static final String cMetaBossHome = System
410: .getProperty("MetaBoss.Home");
411: private static String cAdditionalClasspathForMETABOSS_RUNTIME = null;
412: private static String cAdditionalClasspathForMETABOSS_DEVTIME = null;
413:
414: private static String getAdditionalClasspathForSourceType(
415: SourceType pSourceType) throws BSException {
416: if (pSourceType.equals(SourceType.METABOSS_RUNTIME)) {
417: if (cAdditionalClasspathForMETABOSS_RUNTIME == null) {
418: if (cMetaBossHome == null
419: || cMetaBossHome.length() == 0)
420: throw new BSUndefinedSystemPropertyException(
421: "MetaBoss.Home");
422: StringBuffer lTempBuffer = new StringBuffer();
423: lTempBuffer.append(cMetaBossHome + File.separator
424: + "lib" + File.separator + "MetaBossCore.jar;");
425: lTempBuffer.append(cMetaBossHome + File.separator
426: + "lib" + File.separator
427: + "MetaBossEnterprise.jar;");
428: lTempBuffer.append(cMetaBossHome + File.separator
429: + "thirdpartylib" + File.separator
430: + "commons-logging-1.0.3.jar;");
431: lTempBuffer.append(cMetaBossHome + File.separator
432: + "thirdpartylib" + File.separator
433: + "log4j-1.2.8.jar;");
434: cAdditionalClasspathForMETABOSS_RUNTIME = lTempBuffer
435: .toString();
436: }
437: return cAdditionalClasspathForMETABOSS_RUNTIME;
438: } else if (pSourceType.equals(SourceType.METABOSS_DEVTIME)) {
439: if (cAdditionalClasspathForMETABOSS_DEVTIME == null) {
440: if (cMetaBossHome == null
441: || cMetaBossHome.length() == 0)
442: throw new BSUndefinedSystemPropertyException(
443: "MetaBoss.Home");
444: StringBuffer lTempBuffer = new StringBuffer();
445: lTempBuffer.append(cMetaBossHome + File.separator
446: + "lib" + File.separator + "MetaBossCore.jar;");
447: lTempBuffer.append(cMetaBossHome + File.separator
448: + "lib" + File.separator
449: + "MetaBossEnterprise.jar;");
450: lTempBuffer.append(cMetaBossHome + File.separator
451: + "lib" + File.separator
452: + "MetaBossDresdenOclIntegration.jar;");
453: lTempBuffer
454: .append(cMetaBossHome + File.separator + "lib"
455: + File.separator + "MetaBossModel.jar;");
456: lTempBuffer.append(cMetaBossHome + File.separator
457: + "lib" + File.separator
458: + "MetaBossGenerators.jar;");
459: lTempBuffer.append(cMetaBossHome + File.separator
460: + "lib" + File.separator
461: + "MetaBossGenerationFramework.jar;");
462: lTempBuffer.append(cMetaBossHome + File.separator
463: + "thirdpartylib" + File.separator
464: + "jamon-1.3.jar;");
465: lTempBuffer.append(cMetaBossHome + File.separator
466: + "thirdpartylib" + File.separator
467: + "commons-logging-1.0.3.jar;");
468: lTempBuffer.append(cMetaBossHome + File.separator
469: + "thirdpartylib" + File.separator
470: + "log4j-1.2.8.jar;");
471: lTempBuffer.append(cMetaBossHome + File.separator
472: + "thirdpartylib" + File.separator
473: + "dresden-ocl-injector-1.1.jar;");
474: lTempBuffer.append(cMetaBossHome + File.separator
475: + "thirdpartylib" + File.separator
476: + "netbeansmdr-20040323" + File.separator
477: + "jmi.jar;");
478: lTempBuffer.append(cMetaBossHome + File.separator
479: + "thirdpartylib" + File.separator
480: + "netbeansmdr-20040323" + File.separator
481: + "mof.jar;");
482: cAdditionalClasspathForMETABOSS_DEVTIME = lTempBuffer
483: .toString();
484: }
485: return cAdditionalClasspathForMETABOSS_DEVTIME;
486: }
487: return null;
488: }
489: }
|