/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 *******************************************************************************/ package org.ebayopensource.turmeric.tools.codegen.util; import java.io.File; import java.io.OutputStream; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; import org.ebayopensource.turmeric.tools.codegen.exception.CodeGenFailedException; import com.ebay.kernel.util.StringUtils; import edu.emory.mathcs.backport.java.util.Arrays; /** * Helper class that provides convenient methods for invoking Java Compiler * programmatically. * * * @author rmandapati */ public class JavacHelper { private static final Logger LOG = Logger.getLogger(JavacHelper.class.getName()); static final String ERR_MSG = "Failed to compile java source files"; static final Class<?>[] java5CompileMethodSignature; static { java5CompileMethodSignature = new Class[2]; java5CompileMethodSignature[0] = (new String[0]).getClass(); java5CompileMethodSignature[1] = PrintWriter.class; } private OutputStream m_out = null; public JavacHelper(OutputStream out) { m_out = out; } public void oldCompileJavaSource(List<String> javaSrcFiles, String outputDir) throws Exception { if (javaSrcFiles == null || javaSrcFiles.isEmpty()) { return; } String classpathString = buildClasspath(outputDir); int baseIndex = 5; String[] javacArgs = new String[baseIndex + javaSrcFiles.size()]; javacArgs[0] = "-d"; javacArgs[1] = outputDir; javacArgs[2] = "-classpath"; javacArgs[3] = classpathString; javacArgs[4] = "-g"; for (int i = 0; i < javaSrcFiles.size(); ++i) { javacArgs[baseIndex + i] = javaSrcFiles.get(i); } internalCompile(javacArgs); } public void compileJavaSource(List<String> javaSrcFiles, String outputDir) throws Exception { if (javaSrcFiles == null || javaSrcFiles.isEmpty()) { return; } String cp = buildClasspath(outputDir); // @formatter:off String baseArgs[] = { "-d", outputDir, "-cp", cp, "-g" }; // @formatter:on int size = javaSrcFiles.size()+baseArgs.length; String args[] = new String[size]; int offset = baseArgs.length; for(String srcFile: javaSrcFiles) { args[offset++] = srcFile; } System.arraycopy(baseArgs, 0, args, 0, baseArgs.length); modernJavaCompile(args); } public void oldCompileJavaSource(String javaSources, String srcDir, String outputDir) throws Exception { if (CodeGenUtil.isEmptyString(srcDir)) { return; } String classpathPrefix = srcDir + File.pathSeparator + outputDir; String classpathString = buildClasspath(classpathPrefix); int baseIndex = 6; String[] javacArgs = new String[baseIndex]; javacArgs[0] = "-d"; javacArgs[1] = outputDir; javacArgs[2] = "-classpath"; javacArgs[3] = classpathString; javacArgs[4] = "-g"; javacArgs[5] = javaSources; internalCompile(javacArgs); } public void compileJavaSource(String javaSources, String srcDir, String outputDir) throws Exception { if (CodeGenUtil.isEmptyString(srcDir)) { return; } String cp = buildClasspath(outputDir); // @formatter:off String args[] = { "-d", outputDir, "-sourcepath", srcDir, "-cp", cp, "-g", javaSources }; // @formatter:on modernJavaCompile(args); } private void modernJavaCompile(String args[]) throws CodeGenFailedException { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); if(LOG.isLoggable(Level.FINE)) { @SuppressWarnings("unchecked") List<String> l = Arrays.asList(args); LOG.fine("Executing JAVAC: [" + StringUtils.join(l, " ") + "]"); } int result = compiler.run(null, m_out, m_out, args); if(result != 0) { throw new CodeGenFailedException("JAVAC Compile Failure (see output)"); } } protected void internalCompile(String[] args) throws Exception { Class<?> javacMainClass = null; try { javacMainClass = Class.forName("com.sun.tools.javac.Main", true, this.getClass().getClassLoader()); Method compileMethod = javacMainClass.getMethod("compile", java5CompileMethodSignature); if(LOG.isLoggable(Level.FINER)) { @SuppressWarnings("unchecked") List<String> l = Arrays.asList(args); LOG.finer("Executing Javac: " + StringUtils.join(l, " ")); } Object result = compileMethod.invoke(null, new Object[] { args, new PrintWriter(m_out) }); if ((!(result instanceof Integer)) || ((Integer) result).intValue() == 0) { } } catch (IllegalAccessException illegalAccessEx) { throw new Exception(ERR_MSG, illegalAccessEx); } catch (IllegalArgumentException illegalArgEx) { throw new Exception(ERR_MSG, illegalArgEx); } catch (InvocationTargetException invTargetEx) { throw new Exception(ERR_MSG, invTargetEx); } catch (NoSuchMethodException noSuchmethodEx) { throw new Exception(ERR_MSG, noSuchmethodEx); } catch (ClassNotFoundException clsNotFoundEx) { throw clsNotFoundEx; } catch (SecurityException securityEx) { throw new Exception(ERR_MSG, securityEx); } } public static String buildClasspath(String classpathPrefix) { LinkedList<File> classpath = ClassPathUtil.getClassPath(); StringBuilder cp = new StringBuilder(); if (!CodeGenUtil.isEmptyString(classpathPrefix)) { cp.append(classpathPrefix); cp.append(File.pathSeparator); } if(classpath.isEmpty()) { cp.append(System.getProperty("java.class.path")); return cp.toString(); } ClassPathUtil.appendClasspath(cp, classpath); if(LOG.isLoggable(Level.FINER)) { StringBuilder b = new StringBuilder(); b.append("Classpath:"); String ln = System.getProperty("line.separator"); for(File path: classpath) { b.append(ln).append(path.getAbsolutePath()); } LOG.finer(b.toString()); } return cp.toString(); } /** * Adds given classpath entry to URL class loader if the entry does not * exist already. * * @param String * @return boolean, true if entry added to classloader otherwise false */ public static boolean addToClasspath(String classpathEntry) { if (CodeGenUtil.isEmptyString(classpathEntry)) { return false; } URL classpathURL = null; try { File classpathEntryFile = new File(classpathEntry); classpathURL = classpathEntryFile.toURI().toURL(); } catch (Exception ex) { } if (classpathURL == null) { return false; } boolean entryFound = false; ClassLoader classLoader = JavacHelper.class.getClassLoader(); if (classLoader instanceof CodeGenClassLoader) { CodeGenClassLoader codeGenClassLoader = (CodeGenClassLoader) classLoader; URL[] classpathURLs = codeGenClassLoader.getURLs(); URI classpathURI = null; try { classpathURI = classpathURL.toURI(); } catch (URISyntaxException uriSyntaxEx) { // NOPMD } if (classpathURI != null) { // Check whether classpath entry already exists? for (int i = 0; i < classpathURLs.length; i++) { try { if (classpathURI.equals(classpathURLs[i].toURI())) { entryFound = true; break; } } catch (URISyntaxException uriSyntaxEx) { // NOPMD } } } // given classpath entry not found in the classloader space.... // adding it... if (entryFound == false) { codeGenClassLoader.addURL(classpathURL); entryFound=true; } } // if entry not found means that entry has been // added to url classloader return entryFound; } public static String normalizeURLPath(URI uri) { File file = new File(uri); return file.getPath(); } }