Coverage Report - org.codehaus.plexus.compiler.j2objc.J2ObjCCompiler
 
Classes in this File Line Coverage Branch Coverage Complexity
J2ObjCCompiler
0%
0/96
0%
0/44
4,75
 
 1  
 package org.codehaus.plexus.compiler.j2objc;
 2  
 
 3  
 /*
 4  
  * Copyright 2005 The Apache Software Foundation.
 5  
  *
 6  
  * Licensed under the Apache License, Version 2.0 (the "License");
 7  
  * you may not use this file except in compliance with the License.
 8  
  * You may obtain a copy of the License at
 9  
  *
 10  
  *      http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  
  * See the License for the specific language governing permissions and
 16  
  * limitations under the License.
 17  
  */
 18  
 
 19  
 import java.io.BufferedReader;
 20  
 import java.io.File;
 21  
 import java.io.IOException;
 22  
 import java.io.StringReader;
 23  
 import java.io.StringWriter;
 24  
 import java.io.Writer;
 25  
 import java.util.ArrayList;
 26  
 import java.util.Arrays;
 27  
 import java.util.List;
 28  
 import java.util.Map;
 29  
 
 30  
 import org.codehaus.plexus.compiler.AbstractCompiler;
 31  
 import org.codehaus.plexus.compiler.CompilerConfiguration;
 32  
 import org.codehaus.plexus.compiler.CompilerException;
 33  
 import org.codehaus.plexus.compiler.CompilerMessage;
 34  
 import org.codehaus.plexus.compiler.CompilerMessage.Kind;
 35  
 import org.codehaus.plexus.compiler.CompilerOutputStyle;
 36  
 import org.codehaus.plexus.compiler.CompilerResult;
 37  
 import org.codehaus.plexus.util.StringUtils;
 38  
 import org.codehaus.plexus.util.cli.CommandLineException;
 39  
 import org.codehaus.plexus.util.cli.CommandLineUtils;
 40  
 import org.codehaus.plexus.util.cli.Commandline;
 41  
 import org.codehaus.plexus.util.cli.StreamConsumer;
 42  
 import org.codehaus.plexus.util.cli.WriterStreamConsumer;
 43  
 
 44  
 /**
 45  
  * A plexus compiler which use J2ObjC . It is derived from the CSharpCompiler to
 46  
  * compile with J2ObjC.
 47  
  * 
 48  
  * @author <a href="mailto:ludovic.maitre@effervens.com">Ludovic
 49  
  *         Ma&icirc;tre</a>
 50  
  * @see CSharpCompiler
 51  
  * @plexus.component role="org.codehaus.plexus.compiler.Compiler"
 52  
  *                   role-hint="j2objc"
 53  
  */
 54  
 public class J2ObjCCompiler extends AbstractCompiler {
 55  
 
 56  
         private static final String X_BOOTCLASSPATH = "Xbootclasspath";
 57  
 
 58  
         /**
 59  
          * -J<flag> Pass Java <flag>, such as -Xmx1G, to the system runtime.
 60  
          */
 61  
         private static final String J_FLAG = "J";
 62  
 
 63  
         /**
 64  
          * --batch-translate-max=<n> The maximum number of source files that are
 65  
          * translated. together. Batching speeds up translation, but requires more
 66  
          * memory.
 67  
          */
 68  
         private static final String BATCH_SIZE = "batch-translate-max";
 69  
 
 70  
         /**
 71  
          * Put the arguments of j2objc who takes one dash inside an array, in order
 72  
          * the check the command line.
 73  
          */
 74  0
         private static final List<String> ONE_DASH_ARGS = Arrays
 75  0
                         .asList(new String[] { "-pluginpath", "-pluginoptions", "-t",
 76  
                                         "-Xno-jsni-warnings", "-sourcepath", "-classpath", "-d",
 77  
                                         "-encoding", "-g", "-q", "-v", "-Werror", "-h", "-use-arc",
 78  
                                         "-use-reference-counting", "-x" });
 79  
 
 80  
         /**
 81  
          * Put the command line arguments with 2 dashes inside an array, in order
 82  
          * the check the command line and build it.
 83  
          */
 84  0
         private static final List<String> TWO_DASH_ARGS = Arrays
 85  0
                         .asList(new String[] { "--build-closure", "--dead-code-report",
 86  
                                         "--doc-comments", "--no-extract-unsequenced",
 87  
                                         "--generate-deprecated", "--mapping", "--no-class-methods",
 88  
                                         "--no-final-methods-functions",
 89  
                                         "--no-hide-private-members", "--no-package-directories",
 90  
                                         "--prefix", "--prefixes", "--preserve-full-paths",
 91  
                                         "--strip-gwt-incompatible", "--strip-reflection",
 92  
                                         "--segmented-headers", "--timing-info", "--quiet",
 93  
                                         "--verbose", "--help" });
 94  
 
 95  
         public J2ObjCCompiler() {
 96  0
                 super(CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE, ".java",
 97  
                                 null, null);
 98  0
         }
 99  
 
 100  
         // ----------------------------------------------------------------------
 101  
         // Compiler Implementation
 102  
         // ----------------------------------------------------------------------
 103  
 
 104  
         public boolean canUpdateTarget(CompilerConfiguration configuration)
 105  
                         throws CompilerException {
 106  0
                 return false;
 107  
         }
 108  
 
 109  
         public CompilerResult performCompile(CompilerConfiguration config)
 110  
                         throws CompilerException {
 111  0
                 File destinationDir = new File(config.getOutputLocation());
 112  0
                 if (!destinationDir.exists()) {
 113  0
                         destinationDir.mkdirs();
 114  
                 }
 115  
 
 116  0
                 config.setSourceFiles(null);
 117  
 
 118  0
                 String[] sourceFiles = J2ObjCCompiler.getSourceFiles(config);
 119  
 
 120  0
                 if (sourceFiles.length == 0) {
 121  0
                         return new CompilerResult().success(true);
 122  
                 }
 123  
 
 124  0
                 System.out.println("Compiling " + sourceFiles.length + " "
 125  
                                 + "source file" + (sourceFiles.length == 1 ? "" : "s") + " to "
 126  0
                                 + destinationDir.getAbsolutePath());
 127  
 
 128  0
                 String[] args = buildCompilerArguments(config, sourceFiles);
 129  
 
 130  
                 List<CompilerMessage> messages;
 131  
 
 132  0
                 if (config.isFork()) {
 133  0
                         messages = compileOutOfProcess(config.getWorkingDirectory(),
 134  0
                                         config.getBuildDirectory(), findExecutable(config), args);
 135  
                 } else {
 136  0
                         throw new CompilerException(
 137  
                                         "This compiler doesn't support in-process compilation.");
 138  
                 }
 139  
 
 140  0
                 return new CompilerResult().compilerMessages(messages);
 141  
         }
 142  
 
 143  
         public String[] createCommandLine(CompilerConfiguration config)
 144  
                         throws CompilerException {
 145  0
                 return buildCompilerArguments(config,
 146  0
                                 J2ObjCCompiler.getSourceFiles(config));
 147  
         }
 148  
 
 149  
         /**
 150  
          * Find the executable given in the configuration or use j2objc from the
 151  
          * PATH.
 152  
          * 
 153  
          * @param config
 154  
          * @return the List<String> of args
 155  
          */
 156  
         private String findExecutable(CompilerConfiguration config) {
 157  0
                 String executable = config.getExecutable();
 158  
 
 159  0
                 if (!StringUtils.isEmpty(executable)) {
 160  0
                         return executable;
 161  
                 }
 162  
 
 163  0
                 return "j2objc";
 164  
         }
 165  
 
 166  
         /**
 167  
          * Build the compiler arguments : 
 168  
          * <li>the output location is used for -d of j2objc) 
 169  
          * <li>the classpath entries are added to -classpath 
 170  
          * <li>the sourcefiles are listed at the end of the command line 
 171  
          * <li>the configuration can contain any of the arguments
 172  
          * 
 173  
          * @param config
 174  
          * @param sourceFiles
 175  
          * @return The List<String> to give to the command line tool
 176  
          * @throws CompilerException
 177  
          */
 178  
         private String[] buildCompilerArguments(CompilerConfiguration config,
 179  
                         String[] sourceFiles) throws CompilerException {
 180  
                 /*
 181  
                  * j2objc --help Usage: j2objc <options> <source files>
 182  
                  */
 183  0
                 List<String> args = new ArrayList<String>();
 184  0
                 Map<String, String> compilerArguments = config
 185  0
                                 .getCustomCompilerArgumentsAsMap();
 186  
 
 187  
                 // Verbose
 188  0
                 if (config.isVerbose()) {
 189  0
                         args.add("-v");
 190  
                 }
 191  
 
 192  
                 // Destination/output directory
 193  0
                 args.add("-d");
 194  0
                 args.add(config.getOutputLocation());
 195  
 
 196  0
                 if (!config.getClasspathEntries().isEmpty()) {
 197  0
                         List<String> classpath = new ArrayList<String>();
 198  0
                         for (String element : config.getClasspathEntries()) {
 199  0
                                 File f = new File(element);
 200  0
                                 classpath.add(f.getAbsolutePath());
 201  
 
 202  0
                                 classpath.add(element);
 203  0
                         }
 204  0
                         args.add("-classpath");
 205  0
                         args.add(StringUtils.join(classpath.toArray(), File.pathSeparator));
 206  
                 }
 207  
 
 208  0
                 if (config.isVerbose()) {
 209  0
                         System.out.println("Args: ");
 210  
                 }
 211  
 
 212  0
                 for (String k : compilerArguments.keySet()) {
 213  0
                         if (config.isVerbose()) {
 214  0
                                 System.out.println(k + "=" + compilerArguments.get(k));
 215  
                         }
 216  0
                         String v = compilerArguments.get(k);
 217  0
                         if (J_FLAG.equals(k)) {
 218  0
                                 args.add(J_FLAG + v);
 219  0
                         } else if (X_BOOTCLASSPATH.equals(k)) {
 220  0
                                 args.add(X_BOOTCLASSPATH + ":" + v);
 221  0
                         } else if (BATCH_SIZE.equals(k)) {
 222  0
                                 args.add("-" + BATCH_SIZE + "=" + v);
 223  
                         } else {
 224  0
                                 if (TWO_DASH_ARGS.contains(k)) {
 225  0
                                         args.add("-" + k);
 226  0
                                 } else if (ONE_DASH_ARGS.contains(k)) {
 227  0
                                         args.add(k);
 228  
                                 } else {
 229  0
                                         throw new IllegalArgumentException("The argument " + k
 230  
                                                         + " isnt't a flag recognized by J2ObjC.");
 231  
                                 }
 232  0
                                 if (v != null) {
 233  0
                                         args.add(v);
 234  
                                 }
 235  
                         }
 236  0
                 }
 237  
 
 238  0
                 for (String sourceFile : sourceFiles) {
 239  0
                         args.add(sourceFile);
 240  
                 }
 241  
 
 242  0
                 return args.toArray(new String[args.size()]);
 243  
         }
 244  
 
 245  
         private List<CompilerMessage> compileOutOfProcess(File workingDirectory,
 246  
                         File target, String executable, String[] args)
 247  
                         throws CompilerException {
 248  
 
 249  0
                 Commandline cli = new Commandline();
 250  
 
 251  0
                 cli.setWorkingDirectory(workingDirectory.getAbsolutePath());
 252  
 
 253  0
                 cli.setExecutable(executable);
 254  
 
 255  0
                 cli.addArguments(args);
 256  
 
 257  0
                 Writer stringWriter = new StringWriter();
 258  
 
 259  0
                 StreamConsumer out = new WriterStreamConsumer(stringWriter);
 260  
 
 261  0
                 StreamConsumer err = new WriterStreamConsumer(stringWriter);
 262  
 
 263  
                 int returnCode;
 264  
 
 265  
                 List<CompilerMessage> messages;
 266  
 
 267  
                 try {
 268  0
                         returnCode = CommandLineUtils.executeCommandLine(cli, out, err);
 269  
 
 270  0
                         messages = parseCompilerOutput(new BufferedReader(new StringReader(
 271  0
                                         stringWriter.toString())));
 272  0
                 } catch (CommandLineException e) {
 273  0
                         throw new CompilerException(
 274  
                                         "Error while executing the external compiler.", e);
 275  0
                 } catch (IOException e) {
 276  0
                         throw new CompilerException(
 277  
                                         "Error while executing the external compiler.", e);
 278  0
                 }
 279  
 
 280  0
                 if (returnCode != 0 && messages.isEmpty()) {
 281  
                         // TODO: exception?
 282  0
                         messages.add(new CompilerMessage(
 283  
                                         "Failure executing the compiler, but could not parse the error:"
 284  0
                                                         + EOL + stringWriter.toString(), Kind.ERROR));
 285  
                 }
 286  
 
 287  0
                 return messages;
 288  
         }
 289  
 
 290  
         public static List<CompilerMessage> parseCompilerOutput(
 291  
                         BufferedReader bufferedReader) throws IOException {
 292  0
                 List<CompilerMessage> messages = new ArrayList<CompilerMessage>();
 293  
 
 294  0
                 String line = bufferedReader.readLine();
 295  
 
 296  0
                 while (line != null) {
 297  0
                         CompilerMessage compilerError = DefaultJ2ObjCCompilerParser
 298  0
                                         .parseLine(line);
 299  
 
 300  0
                         if (compilerError != null) {
 301  0
                                 messages.add(compilerError);
 302  
                         }
 303  
 
 304  0
                         line = bufferedReader.readLine();
 305  0
                 }
 306  
 
 307  0
                 return messages;
 308  
         }
 309  
 
 310  
 }