Package org.apache.cocoon.components.language.programming.java

Source Code of org.apache.cocoon.components.language.programming.java.Jikes$StreamPumper

/*
* Copyright 1999-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.cocoon.components.language.programming.java;

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;

import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.cocoon.components.language.programming.CompilerError;
import org.apache.cocoon.components.thread.RunnableManager;
import EDU.oswego.cs.dl.util.concurrent.CountDown;

/**
* This class wraps IBM's <i>Jikes</i> Java compiler
* NOTE: inspired by the Apache Jasper implementation.
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
* @version CVS $Id: Jikes.java 124680 2005-01-08 20:23:32Z antonio $
* @since 2.0
*/

public class Jikes extends AbstractJavaCompiler implements Serviceable {

    static final int OUTPUT_BUFFER_SIZE = 1024;
    static final int BUFFER_SIZE = 512;

    private ServiceManager m_serviceManager;
   
    private static class StreamPumper implements Runnable {

        private BufferedInputStream stream;
        private boolean endOfStream = false;
        private int SLEEP_TIME = 5;
        private OutputStream out;
        private CountDown m_done;

        public StreamPumper(BufferedInputStream is, OutputStream out, CountDown done) {
            this.stream = is;
            this.out = out;
            m_done = done;
        }

        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();
                    Thread.sleep(SLEEP_TIME);
                }
            } catch (Exception e) {
               // getLogger().warn("Jikes.run()", e);
            }
            m_done.release(); // signal 'we are finished'
        }
        }

    /**
     * Set the {@link ServiceManager}
     */
    public void service( ServiceManager serviceManager )
    throws ServiceException
    {
        m_serviceManager = serviceManager;
    }

    /**
     * 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() + 1];
      for (i = 0; i < arguments.size(); i++) {
        args[i] = (String) arguments.get(i);
      }

      args[i] = file;

      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());

            RunnableManager runnableManager = null;
            try
            {
                runnableManager = (RunnableManager)m_serviceManager.lookup( RunnableManager.ROLE );
            }
            catch( final ServiceException se )
            {
                getLogger().error( "Cannot get RunnableManager", se );
                throw new IOException( "Cannot get RunnableManager" );
            }

            final CountDown done = new CountDown( 1 );
            StreamPumper errPumper = new StreamPumper(compilerErr, tmpErr, done);
            runnableManager.execute( errPumper );
            m_serviceManager.release( runnableManager );

            p.waitFor();
            exitValue = p.exitValue();

            done.acquire(); // Wait for StreadmPumper to finish
            compilerErr.close();

            p.destroy();

            tmpErr.close();
            this.errors = new ByteArrayInputStream(tmpErr.toByteArray());

        } catch (InterruptedException somethingHappened) {
            getLogger().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;
            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;
                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("Please ensure that you have your JDK's rt.jar listed in your classpath. Jikes needs it to operate.");
            type="error";
            getLogger().error(message.toString(), e);
        }

        if ("".equals(message.toString())) {
            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 "IBM Jikes Compiler";
    }
}
TOP

Related Classes of org.apache.cocoon.components.language.programming.java.Jikes$StreamPumper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.