package org.codehaus.mojo.idlj; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.maven.plugin.MojoExecutionException; import org.codehaus.plexus.util.StringOutputStream; import org.codehaus.plexus.util.StringUtils; /** * This class implement the <code>CompilerTranslator</code> for the Sun idlj IDL compiler * * @author Anders Hessellund Jensen <ahj@trifork.com> * @version $Id$ */ public class IdljTranslator extends AbstractTranslator implements CompilerTranslator { /** * Default constructor */ public IdljTranslator() { super(); } /** * This method it's used to invoke the compiler * * @param sourceDirectory the path to the sources * @param includeDirs the <code>File[]</code> of directories where to find the includes * @param targetDirectory the path to the destination of the compilation * @param idlFile the path to the file to compile * @param source the source tag available in the configuration tree of the maven plugin * @throws MojoExecutionException the exception is thrown whenever the compilation fails or crashes * @see CompilerTranslator#invokeCompiler(String, List, String, String, Source) */ public void invokeCompiler( String sourceDirectory, File[] includeDirs, String targetDirectory, String idlFile, Source source ) throws MojoExecutionException { List args = new ArrayList(); args.add( "-i" ); args.add( sourceDirectory ); // add idl files from other directories as well if ( includeDirs != null && includeDirs.length > 0 ) { for ( int i = 0; i < includeDirs.length; i++ ) { args.add( "-i" ); args.add( includeDirs[i] ); } } args.add( "-td" ); args.add( toRelativeAndFixSeparator( new File( System.getProperty( "user.dir" ) ), new File( targetDirectory ), false ) ); if ( source.getPackagePrefix() != null ) { throw new MojoExecutionException( "idlj compiler does not support packagePrefix" ); } if ( source.getPackagePrefixes() != null ) { for ( Iterator prefixes = source.getPackagePrefixes().iterator(); prefixes.hasNext(); ) { PackagePrefix prefix = (PackagePrefix) prefixes.next(); args.add( "-pkgPrefix" ); args.add( prefix.getType() ); args.add( prefix.getPrefix() ); } } if ( source.getDefines() != null ) { for ( Iterator defs = source.getDefines().iterator(); defs.hasNext(); ) { Define define = (Define) defs.next(); if ( define.getValue() != null ) { throw new MojoExecutionException( "idlj compiler unable to define symbol values" ); } args.add( "-d" ); args.add( define.getSymbol() ); } } if ( source.emitStubs() != null && source.emitStubs().booleanValue() ) { if ( source.emitSkeletons().booleanValue() ) { args.add( "-fall" ); } else { args.add( "-fclient" ); } } else { if ( source.emitSkeletons() != null && source.emitSkeletons().booleanValue() ) { args.add( "-fserver" ); } else { args.add( "-fserverTIE" ); } } if ( source.compatible() != null && source.compatible().booleanValue() ) { String version = System.getProperty( "java.specification.version" ); getLog().debug( "JDK Version:" + version ); // TODO A compiled REGEX should be used instead of the matches() // method if ( version.matches( "^[0-1]\\.[0-3]" ) ) { getLog().debug( "OPTION IGNORED: compatible" ); } else { args.add( "-oldImplBase" ); } } if ( source.getAdditionalArguments() != null ) { for ( Iterator it = source.getAdditionalArguments().iterator(); it.hasNext(); ) { args.add( it.next() ); } } args.add( idlFile ); Class compilerClass = getCompilerClass(); invokeCompiler( compilerClass, args ); } /** * @return the <code>Class</code> that implements the idlj compiler * @throws MojoExecutionException if the search for the class fails */ private Class getCompilerClass() throws MojoExecutionException { ClassLoader cl = this.getClass().getClassLoader(); Class idljCompiler; try { idljCompiler = Class.forName( getIDLCompilerClass() ); } catch ( ClassNotFoundException e ) { try { File javaHome = new File( System.getProperty( "java.home" ) ); File toolsJar = new File( javaHome, "../lib/tools.jar" ); URL toolsJarUrl = toolsJar.toURL(); URLClassLoader urlLoader = new URLClassLoader( new URL[] { toolsJarUrl }, cl ); // Unfortunately the idlj compiler reads messages using the // system class path. // Therefore this really nasty hack is required. System.setProperty( "java.class.path", System.getProperty( "java.class.path" ) + System.getProperty( "path.separator" ) + toolsJar.getAbsolutePath() ); if ( System.getProperty( "java.vm.name" ).indexOf( "HotSpot" ) != -1 ) { urlLoader.loadClass( "com.sun.tools.corba.se.idl.som.cff.FileLocator" ); } idljCompiler = urlLoader.loadClass( getIDLCompilerClass() ); } catch ( Exception notUsed ) { throw new MojoExecutionException( " IDL compiler not available", e ); } } return idljCompiler; } /** * @return the class name of the clas that implements the compiler */ private String getIDLCompilerClass() { String vendor = System.getProperty( "java.vm.vendor" ); if ( vendor.indexOf( "IBM" ) != -1 ) { return "com.ibm.idl.toJavaPortable.Compile"; } return "com.sun.tools.corba.se.idl.toJavaPortable.Compile"; } /** * Invoke the specified compiler with a set of arguments * * @param compilerClass the <code>Class</code> that implements the compiler * @param args a <code>List</code> that contains the arguments to use for the compiler * @throws MojoExecutionException if the compilation fail or the compiler crashes */ private void invokeCompiler( Class compilerClass, List args ) throws MojoExecutionException { getLog().debug( "Current dir : " + System.getProperty( "user.dir" ) ); Method compilerMainMethod; String arguments[]; if ( isDebug() ) { args.add( 0, "-verbose" ); arguments = (String[]) args.toArray( new String[args.size()] ); String command = compilerClass.getName(); for ( int i = 0; i < arguments.length; i++ ) { command += " " + arguments[i]; } getLog().info( command ); } else { arguments = (String[]) args.toArray( new String[args.size()] ); } try { compilerMainMethod = compilerClass.getMethod( "main", new Class[] { String[].class } ); } catch ( NoSuchMethodException e1 ) { throw new MojoExecutionException( "Error: Compiler had no main method" ); } int exitCode = 0; // Backup std channels PrintStream stdErr = System.err; PrintStream stdOut = System.out; // Local channels StringOutputStream err = new StringOutputStream(); StringOutputStream out = new StringOutputStream(); System.setErr( new PrintStream( err ) ); System.setOut( new PrintStream( out ) ); try { Object retVal = (Object) compilerMainMethod.invoke( compilerClass, new Object[] { arguments } ); if ( retVal != null && retVal instanceof Integer ) exitCode = ( (Integer) retVal ).intValue(); } catch ( InvocationTargetException e ) { throw new MojoExecutionException( "IDL compilation failed", e.getTargetException() ); } catch ( Throwable e ) { throw new MojoExecutionException( "IDL compilation failed", e ); } finally { if ( !"".equals( out.toString() ) ) getLog().info( out.toString() ); if ( !"".equals( err.toString() ) ) getLog().error( err.toString() ); // Restore std channels System.setErr( stdErr ); System.setOut( stdOut ); } if ( !"".equals( out.toString() ) ) getLog().info( out.toString() ); if ( !"".equals( err.toString() ) ) getLog().error( err.toString() ); // Restore std channels System.setErr( stdErr ); System.setOut( stdOut ); if ( isFailOnError() && ( exitCode != 0 || err.toString().indexOf( "Invalid argument" ) != -1 ) ) { throw new MojoExecutionException( "IDL compilation failed" ); } } /** * Convert the provided filename from a Windows separator \\ to a unix/java separator / * * @param filename file name to fix separator * @return filename with all \\ replaced with / */ public static String fixSeparator( String filename ) { return StringUtils.replace( filename, '\\', '/' ); } public static String getCanonicalPath( File file ) throws MojoExecutionException { try { return file.getCanonicalPath(); } catch ( IOException e ) { throw new MojoExecutionException( "Can't canonicalize system path: " + file.getAbsolutePath(), e ); } } /** * Taken from maven-eclipse-plugin * * @param fromdir * @param todir * @param replaceSlashesWithDashes * @return the relative path between fromdir to todir * @throws MojoExecutionException */ public static String toRelativeAndFixSeparator( File fromdir, File todir, boolean replaceSlashesWithDashes ) throws MojoExecutionException { if ( !todir.isAbsolute() ) { todir = new File( fromdir, todir.getPath() ); } String basedirPath = getCanonicalPath( fromdir ); String absolutePath = getCanonicalPath( todir ); String relative = null; if ( absolutePath.equals( basedirPath ) ) { relative = "."; //$NON-NLS-1$ } else if ( absolutePath.startsWith( basedirPath ) ) { // MECLIPSE-261 // The canonical form of a windows root dir ends in a slash, whereas // the canonical form of any other file // does not. // The absolutePath is assumed to be: basedirPath + Separator + // fileToAdd // In the case of a windows root directory the Separator is missing // since it is contained within // basedirPath. int length = basedirPath.length() + 1; if ( basedirPath.endsWith( "\\" ) ) { length--; } relative = absolutePath.substring( length ); } else { relative = absolutePath; } relative = fixSeparator( relative ); if ( replaceSlashesWithDashes ) { relative = StringUtils.replace( relative, '/', '-' ); relative = StringUtils.replace( relative, ':', '-' ); // remove ":" // for absolute // paths in // windows } return relative; } }