/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* 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
*
* 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.
*/
package org.apache.axis.components.compiler;
import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.utils.Messages;
import org.apache.commons.logging.Log;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/**
* This class wraps IBM's <i>Jikes</i> Java compiler
* NOTE: inspired by the Apache Jasper implementation.
* @author <a href="mailto:dims@yahoo.com">Davanum Srinivas</a>
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
* @since 2.0
*/
public class Jikes extends AbstractCompiler
{
protected static Log log =
LogFactory.getLog(Jikes.class.getName());
static final int OUTPUT_BUFFER_SIZE = 1024;
static final int BUFFER_SIZE = 512;
private class StreamPumper extends Thread {
private BufferedInputStream stream;
private boolean endOfStream = false;
private boolean stopSignal = false;
private int SLEEP_TIME = 5;
private OutputStream out;
public StreamPumper(BufferedInputStream is, OutputStream out) {
this.stream = is;
this.out = out;
}
public void pumpStream() throws IOException {
byte[] buf = new byte[BUFFER_SIZE];
if (!endOfStream) {
int bytesRead = stream.read(buf, 0, BUFFER_SIZE);
if (bytesRead > 0) {
out.write(buf, 0, bytesRead);
} else if (bytesRead == -1) {
endOfStream = true;
}
}
}
public void run() {
try {
while (!endOfStream) {
pumpStream();
sleep(SLEEP_TIME);
}
} catch (Exception e) {
// getLogger().warn("Jikes.run()", e);
}
}
}
/**
* Copy arguments to a string array
*
* @param arguments The compiler arguments
* @return A string array containing compilation arguments
*/
protected String[] toStringArray(List arguments) {
int i;
for (i = 0; i < arguments.size(); i++) {
String arg = (String) arguments.get(i);
if (arg.equals("-sourcepath")) {
// Remove -sourcepath option. Jikes does not understand that.
arguments.remove(i);
arguments.remove(i);
break;
}
}
String[] args = new String[arguments.size() + fileList.size()];
for (i = 0; i < arguments.size(); i++) {
args[i] = (String) arguments.get(i);
}
for (int j=0; j < fileList.size(); i++,j++) {
args[i] = (String)fileList.get(j);
}
return args;
}
/**
* Execute the compiler
*/
public boolean compile() throws IOException {
List args = new ArrayList();
// command line name
args.add("jikes");
// indicate Emacs output mode must be used
args.add("+E");
// avoid warnings
// Option nowarn with one hyphen only
args.add("-nowarn");
int exitValue;
ByteArrayOutputStream tmpErr = new ByteArrayOutputStream(OUTPUT_BUFFER_SIZE);
try {
Process p = Runtime.getRuntime().exec(toStringArray(fillArguments(args)));
BufferedInputStream compilerErr = new BufferedInputStream(p.getErrorStream());
StreamPumper errPumper = new StreamPumper(compilerErr, tmpErr);
errPumper.start();
p.waitFor();
exitValue = p.exitValue();
// Wait until the complete error stream has been read
errPumper.join();
compilerErr.close();
p.destroy();
tmpErr.close();
this.errors = new ByteArrayInputStream(tmpErr.toByteArray());
} catch (InterruptedException somethingHappened) {
log.debug("Jikes.compile():SomethingHappened", somethingHappened);
return false;
}
// Jikes returns 0 even when there are some types of errors.
// Check if any error output as well
// Return should be OK when both exitValue and
// tmpErr.size() are 0 ?!
return ((exitValue == 0) && (tmpErr.size() == 0));
}
/**
* Parse the compiler error stream to produce a list of
* <code>CompilerError</code>s
*
* @param input The error stream
* @return The list of compiler error messages
* @exception IOException If an error occurs during message collection
*/
protected List parseStream(BufferedReader input) throws IOException {
List errors = null;
String line = null;
StringBuffer buffer = null;
while (true) {
// cleanup the buffer
buffer = new StringBuffer(); // this is faster than clearing it
// first line is not space-starting
if (line == null) line = input.readLine();
if (line == null) return errors;
log.debug(line);
buffer.append(line);
// all other space-starting lines are one error
while (true) {
line = input.readLine();
// EOF
if (line == null)
break;
// Continuation of previous error starts with ' '
if (line.length() > 0 && line.charAt(0) != ' ')
break;
log.debug(line);
buffer.append('\n');
buffer.append(line);
}
// if error is found create the vector
if (errors == null) errors = new ArrayList();
// add the error bean
errors.add(parseError(buffer.toString()));
}
}
/**
* Parse an individual compiler error message
*
* @param error The error text
* @return A mssaged <code>CompilerError</code>
*/
private CompilerError parseError(String error) {
StringTokenizer tokens = new StringTokenizer(error, ":");
String file = tokens.nextToken();
if (file.length() == 1) file = new StringBuffer(file).append(":").append(tokens.nextToken()).toString();
StringBuffer message = new StringBuffer();
String type = "";
int startline = 0;
int startcolumn = 0;
int endline = 0;
int endcolumn = 0;
try {
startline = Integer.parseInt(tokens.nextToken());
startcolumn = Integer.parseInt(tokens.nextToken());
endline = Integer.parseInt(tokens.nextToken());
endcolumn = Integer.parseInt(tokens.nextToken());
} catch (Exception e) {
// FIXME: VG: This is not needed anymore?
message.append(Messages.getMessage("compilerFail00"));
type="error";
log.error(Messages.getMessage("compilerFail00"), e);
}
if ("".equals(message)) {
type = tokens.nextToken().trim().toLowerCase();
message.append(tokens.nextToken("\n").substring(1).trim());
while (tokens.hasMoreTokens())
message.append("\n").append(tokens.nextToken());
}
return new CompilerError(file, type.equals("error"), startline, startcolumn, endline, endcolumn, message.toString());
}
public String toString() {
return Messages.getMessage("ibmJikes");
}
}
|