alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.openide.compiler;

import java.util.*;
import java.io.File;
import java.io.IOException;

import org.openide.cookies.CompilerCookie;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileSystemCapability;
import org.openide.filesystems.FileStateInvalidException;
import org.openide.filesystems.FileSystem;
import org.openide.filesystems.FileUtil;
import org.openide.execution.NbProcessDescriptor;
import org.openide.util.NbBundle;
import org.openide.ErrorManager;

/** Compiles (probably Java) sources via an external compiler process.
* The path to the executable, classpath, error-matching expressions, etc.
* are configurable.
*
* @author Ales Novak
*/
public class ExternalCompiler extends Compiler {

    /** locales */
    private static ResourceBundle bundle;

    /** regular expression descripting Sun's compiler error format */
    static final String SUN_ERROR_EXPR = "^([^ ][^\n]+):([0-9]+): (.*)"; // NOI18N
    /** regular expression descripting MS compiler error format */
    static final String MICROSOFT_ERROR_EXPR = "^([^\\(]+)\\(([0-9]+),([0-9]+)\\) : (.*)"; // NOI18N
    /** regexp of JIKES */
    static final String JIKES_ERROR_EXPR = "^([^ ]+):([0-9]+):([0-9]+):[0-9]+:[0-9]+:( |.*\n^)(.*)"; // NOI18N

    /** Error parsing for Sun's Javac. */
    public static final ErrorExpression JAVAC = new ErrorExpression("CTL_Sun", SUN_ERROR_EXPR, 1, 2, -1, 3, false); // NOI18N
    /** Error parsing for Microsoft's JVC. */
    public static final ErrorExpression JVC = new ErrorExpression("CTL_Microsoft", MICROSOFT_ERROR_EXPR, 1, 2, 3, 4, false); // NOI18N
    /** Error parsing for IBM's Jikes (with the +E switch). */
    public static final ErrorExpression JIKES = new ErrorExpression("CTL_Jikes", JIKES_ERROR_EXPR, 1, 2, 3, 5, false); // NOI18N

    /** Constant for compilation. */
    public static final Object COMPILE = CompilerCookie.Compile.class;
    /** Constant for building. */
    public static final Object BUILD = CompilerCookie.Build.class;
    /** Constant for cleaning. Not supported by this class however. */
    public static final Object CLEAN = CompilerCookie.Clean.class;


    /** File extension for class files. */
    protected static final String CLASS_EXTENSION = "class"; // NOI18N

    /** can create the name of the file to compile */
    private FNP fileNameProducer;
    /** external compiler description - which file to exec, its args... */
    private NbProcessDescriptor nbDescriptor;
    /** ErrorExpression valid for this instance of external compiler */
    private ErrorExpression errorExpression;
    /** Type of the compilation. */
    private Object type;

    /** Create an external compiler.
    * @param fo a file to compile
    * @param type the type of compilation ({@link #COMPILE} or {@link #BUILD})
    * @param nbDescriptor a description of an external compiler executable
    * @param err a regular expression to scan for compiler errors
    * @exception IllegalArgumentException if the file object is invalid
    */
    public ExternalCompiler(
        FileObject fo,
        Object type,
        NbProcessDescriptor nbDescriptor,
        ErrorExpression err
    ) {
        init (fo, type, nbDescriptor, err);
    }

    /** Create an external compiler.
    * @param job the compiler job to add to
    * @param fo a file to compile
    * @param type the type of compilation ({@link #COMPILE} or {@link #BUILD})
    * @param nbDescriptor a description of an external compiler executable
    * @param err a regular expression to scan for compiler errors
    * @exception IllegalArgumentException if the file object is invalid
    */
    public ExternalCompiler(CompilerJob job, FileObject fo, Object type, NbProcessDescriptor nbDescriptor, ErrorExpression err) {
        init (fo, type, nbDescriptor, err);

        job.add (this);
        registerInJob (job);
    }

    /** Create an external compiler with dependencies.
    * @param dependencies an array of compilers that are to be invoked before this one.
    * @param fo a file to compile
    * @param type the type of compilation ({@link #COMPILE} or {@link #BUILD})
    * @param nbDescriptor a description of an external compiler executable
    * @param err a regular expression to scan for compiler errors
    * @exception IllegalArgumentException if the file object is invalid
    */
    public ExternalCompiler(Compiler[] dependencies, FileObject fo, Object type, NbProcessDescriptor nbDescriptor, ErrorExpression err) {
        init (fo, type, nbDescriptor, err);

        dependsOn (Arrays.asList (dependencies));
        registerInJob (dependencies[0]);
    }

    /** Create an external compiler for a given java.io.File.
    * @param file the file to compile
    * @param type the type of compilation ({@link #COMPILE} or {@link #BUILD})
    * @param nbDescriptor a description of an external compiler executable
    * @param err a regular expression to scan for compiler errors
    */
    public ExternalCompiler(
        final java.io.File file,
        Object type,
        NbProcessDescriptor nbDescriptor,
        ErrorExpression err
    ) {
        if (
            file == null ||
            (type != COMPILE && type != BUILD) ||
            nbDescriptor == null ||
            err == null
        ) {
            throw new IllegalArgumentException();
        }

        this.fileNameProducer = new FNP () {
                                    public String getFileName () {
                                        return file.toString ();
                                    }
                                    public FileObject getFileObject () {
                                        return null;
                                    }
                                    public boolean equalTo (FNP fnp) {
                                        return fnp.equalToFile (file);
                                    }
                                    public boolean equalToFile (java.io.File f) {
                                        return file.equals (f);
                                    }
                                    public boolean equalToResource (String res) {
                                        return false;
                                    }
                                    public boolean equalToResourceAndFS (String res, FileSystem fs) {
                                        return false;
                                    }
                                    public boolean equalToFileObject (FileObject obj) {
                                        return false;
                                    }
                                };
        this.nbDescriptor = nbDescriptor;
        this.errorExpression = err;
        this.type = type;
    }

    /** Create an external compiler for an object in repository
    * that still does not exists.
    *
    * @param fs file system to look on for resource
    * @param resourceName the name of resource to look for
    *
    * @param type the type of compilation ({@link #COMPILE} or {@link #BUILD})
    * @param nbDescriptor a description of an external compiler executable
    * @param err a regular expression to scan for compiler errors
    */
    public ExternalCompiler(
        final FileSystem fs,
        final String resourceName,
        Object type,
        NbProcessDescriptor nbDescriptor,
        ErrorExpression err
    ) {
        if (
            fs == null ||
            resourceName == null ||
            (type != COMPILE && type != BUILD) ||
            nbDescriptor == null ||
            err == null
        ) {
            throw new IllegalArgumentException();
        }

        this.fileNameProducer = new FNP () {
                                    public String getFileName () {
                                        FileObject fo = fs.findResource (resourceName);
                                        if (fo == null) {
                                            return ""; // NOI18N
                                        }
                                        File f = FileUtil.toFile (fo);
                                        if (f == null) {
                                            return ""; // NOI18N
                                        }
                                        return f.toString ();
                                    }
                                    public FileObject getFileObject () {
                                        return fs.findResource (resourceName);
                                    }

                                    public boolean equalTo (FNP fnp) {
                                        return fnp.equalToResourceAndFS (resourceName, fs);
                                    }
                                    public boolean equalToFile (java.io.File f) {
                                        return false;
                                    }
                                    public boolean equalToResource (String res) {
                                        return false;
                                    }
                                    public boolean equalToResourceAndFS (String res, FileSystem fileSystem) {
                                        return fs.equals (fileSystem) && res.equals (resourceName);
                                    }
                                    public boolean equalToFileObject (FileObject obj) {
                                        return false;
                                    }

                                };
        this.nbDescriptor = nbDescriptor;
        this.errorExpression = err;
        this.type = type;
    }

    /** Create an external compiler for an object in repository
    * need not exist in present. Looks on all filesystems.
    *
    * @param resourceName the name of resource to look for
    *
    * @param type the type of compilation ({@link #COMPILE} or {@link #BUILD})
    * @param nbDescriptor a description of an external compiler executable
    * @param err a regular expression to scan for compiler errors
    */
    public ExternalCompiler(
        final String resourceName,
        Object type,
        NbProcessDescriptor nbDescriptor,
        ErrorExpression err
    ) {
        if (
            resourceName == null ||
            (type != COMPILE && type != BUILD) ||
            nbDescriptor == null ||
            err == null
        ) {
            throw new IllegalArgumentException();
        }

        this.fileNameProducer = new FNP () {
                                    public String getFileName () {
                                        FileObject fo = FileSystemCapability.ALL.findResource (resourceName);
                                        if (fo == null) {
                                            return ""; // NOI18N
                                        }
                                        File f = FileUtil.toFile (fo);
                                        if (f == null) {
                                            return ""; // NOI18N
                                        }
                                        return f.toString ();
                                    }
                                    public FileObject getFileObject () {
                                        return FileSystemCapability.ALL.findResource (resourceName);
                                    }

                                    public boolean equalTo (FNP fnp) {
                                        return fnp.equalToResource (resourceName);
                                    }
                                    public boolean equalToFile (java.io.File f) {
                                        return false;
                                    }
                                    public boolean equalToResource (String res) {
                                        return res.equals (resourceName);
                                    }
                                    public boolean equalToResourceAndFS (String res, FileSystem fs) {
                                        return false;
                                    }
                                    public boolean equalToFileObject (FileObject obj) {
                                        return false;
                                    }

                                };
        this.nbDescriptor = nbDescriptor;
        this.errorExpression = err;
        this.type = type;
    }

    /** Initialization of basic parameters.
    */
    private void init (
        final FileObject fo,
        Object type,
        NbProcessDescriptor nbDescriptor,
        ErrorExpression err
    ) {
        if (
            fo == null ||
            (type != COMPILE && type != BUILD) ||
            nbDescriptor == null ||
            err == null) {
            throw new IllegalArgumentException();
        }
        final File myFile = FileUtil.toFile(fo);
        if (myFile == null) { // #11367
            IllegalArgumentException iae = new IllegalArgumentException ("no such java.io.File: " + fo); // NOI18N
            ErrorManager em = ErrorManager.getDefault ();
	    try {
                em.annotate(iae, NbBundle.getMessage (ExternalCompiler.class,
                            "EXC_no_such_java_io_File", // NOI18N
                            fo.getPath(),
                            fo.getFileSystem ().getDisplayName ()));
                // Also get any message from the VCS, which may be apropos.
                try {
                    fo.getInputStream ().close ();
                    // If it worked (e.g. from SystemFileSystem), then nothing special.
                    // But if getInputStream is called e.g. on an un-checked-out CVS file,
                    // the annotation on the IOException should tell the user what to do.
                } catch (IOException ioe) {
                    em.annotate (iae, ioe);
                }
            } catch (FileStateInvalidException fsie) {
                em.annotate (iae, fsie);
            }
            throw iae;
        }

        this.fileNameProducer = new FNP () {
                                    public String getFileName () {
                                        return myFile.toString ();
                                    }
                                    public FileObject getFileObject () {
                                        return fo;
                                    }

                                    public boolean equalTo (FNP fnp) {
                                        return fnp.equalToFileObject (fo);
                                    }
                                    public boolean equalToFile (java.io.File f) {
                                        return false;
                                    }
                                    public boolean equalToResource (String res) {
                                        return false;
                                    }
                                    public boolean equalToResourceAndFS (String res, FileSystem fs) {
                                        return false;
                                    }
                                    public boolean equalToFileObject (FileObject obj) {
                                        return obj.equals (fo);
                                    }
                                };
        this.nbDescriptor = nbDescriptor;
        this.errorExpression = err;
        this.type = type;
    }

    /** Get the description of the compiler executable.
     * @return the descriptor */
    public final NbProcessDescriptor getCompilerDescriptor() {
        return nbDescriptor;
    }

    /** Get the error expression used to parse error output from this compiler.
     * @return the error expression
     */
    public final ErrorExpression getErrorExpression() {
        return errorExpression;
    }

    /** Get the file object to be compiled
    * @return the file object (can be null if constructor without 
    *   file object argument has been used and the file object does not exists)
    */
    protected final FileObject getFileObject() {
        return fileNameProducer.getFileObject ();
    }

    /** Get the name of the file to be compiled.
    * @return the file name
    */
    public String getFileName() {
        return fileNameProducer.getFileName ();
    }

    /** @retrun true iff the fo is up to date */
    private static boolean isUpToDate(FileObject fo, Date dates[]) {
        FileObject clsfo;

        // find all entries if the fo belongs to a MultiDataObject
        try {
            org.openide.loaders.DataObject dataobj = org.openide.loaders.DataObject.find(fo);
            java.util.Set files = dataobj.files();
            java.util.Iterator iter = files.iterator();
            int classfilescount = 0;

            while (iter.hasNext()) {
                clsfo = (FileObject) iter.next();
                if (clsfo.getExt().equals(CLASS_EXTENSION)) {
                    classfilescount++;
                    
                    // return the timestamp of the class file
                    if (dates != null)
                        dates[0] = clsfo.lastModified();
                    
                    if (clsfo.lastModified().compareTo(fo.lastModified ()) < 0) {
                        // class fo does not exists or is older then the java source
                        // => compile the file
                        return false;
                    }
                }
            }
            if (classfilescount == 0) {
                return false;
            } else {
                return true;
            }
        } catch (org.openide.loaders.DataObjectNotFoundException e) {
            return false;
        }
    }

    protected boolean isUpToDate() {
        if (type == BUILD) {
            return false;
        } else {
            FileObject fo = getFileObject ();
            return fo == null || isUpToDate(fo, null);
        }
    }

    protected Date getTimeStamp () {
        if (type == BUILD) {
            return null;
        } else {
            FileObject fo = getFileObject ();
            if (fo == null)
                return null;
            Date dates[] = new Date[1];
            isUpToDate(fo, dates);
            return dates[0];
        }
    }
    
    public String toString() {
        StringBuffer sb = new StringBuffer(getClass().getName());
        sb.append(" for "); // NOI18N
        sb.append(getFileName());
        sb.append(" "); // NOI18N
        if (type == COMPILE)
            sb.append("COMPILE");  // NOI18N
        else
            sb.append("BUILD");  // NOI18N
        return sb.toString();
    }

    /** @return ExternalCompilerGroup
    */
    public Class compilerGroupClass() {
        return ExternalCompilerGroup.class;
    }

    /** Identifier for type of compiler. This method allows subclasses to specify
    * the type this compiler belongs to. Compilers that belong to the same class
    * will be compiled together by one external process.
    * 

* It is necessary for all compilers of the same type to have same process * descriptor and error expression. *

* This implementation returns the process descriptor, so all compilers * with the same descriptor will be compiled at once. *

Note that this method has no relation to {@link CompilerType}s; the name is incidental. * @return key to define type of the compiler * @see ExternalCompilerGroup#createProcess * @deprecated While subclassing this method and specifying a type will still work, * it is no longer recommended. Instead, please use {@link Compiler#compilerGroupKey} * and make all compiler-specific state available to the compiler group via other means * (such as getter methods). */ protected Object compilerType () { return nbDescriptor; } /** Produce a refined key for external compilers. * Groups not only by the compiler group class, but by the result of {@link #compilerType} as well, * and also by the error description. * Specialized external compilers are encouraged to override this method directly according to the * contract specified in {@link Compiler#compilerGroupKey}. * @return a composite key */ public Object compilerGroupKey () { List l = new ArrayList (3); l.add (super.compilerGroupKey ()); l.add (compilerType ()); l.add (errorExpression); return l; } /** Two external compilers are the same if they have been constructed with * the same arguments. If one has been constructed with the * java.io.File argument and second with resource name then they are different. * */ public boolean equals (Object o) { if (o instanceof ExternalCompiler) { ExternalCompiler c = (ExternalCompiler)o; return fileNameProducer.equalTo (c.fileNameProducer) && compilerGroupKey ().equals (c.compilerGroupKey ()); // [PENDING] should this also check type (BUILD vs. COMPILE)? } return false; } public int hashCode() { String fn = getFileName(); return (fn == null) ? 0 : fn.hashCode(); } /** @return localized String */ static String getLocalizedString(String s) { if (bundle == null) { bundle = NbBundle.getBundle(ExternalCompiler.class); } return bundle.getString(s); } /** Encapsulates several properties needed for processing * the error output of an external compiler. */ public static class ErrorExpression implements java.io.Serializable, Cloneable { /** name of the compiler */ private String name; /** a regular expression */ private String errordesc; /** position of the file with error inside the expression */ private int filepos; /** position of the line */ private int linepos; /** positiom of the column */ private int columnpos; /** position of the description */ private int descpos; /** the name was resolved against bundle */ private boolean resolved; static final long serialVersionUID =-2647801563993403964L; /** Create an error expression. * @param name display name * @param errordesc Perl5-style regular expression which should match lines containing error output * @param filepos index of backreference containing the filename of the error, or -1 if none * @param linepos index of backreference containing the line number of the error, or -1 if none * @param columnpos index of backreference containing the column number of the error, or -1 if none * @param descpos index of backreference containing the description of the error, or -1 if none */ public ErrorExpression (String name, String errordesc, int filepos, int linepos, int columnpos, int descpos) { this(name, errordesc, filepos, linepos, columnpos, descpos, true); } ErrorExpression (String name, String errordesc, int filepos, int linepos, int columnpos, int descpos, boolean resolved) { this.name = name; this.errordesc = errordesc; this.filepos = filepos; this.linepos = linepos; this.columnpos = columnpos; this.descpos = descpos; this.resolved = resolved; } public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { // cannot happen throw new InternalError (); } } /** Get the display name. * @return the display name */ public String getName () { if (!resolved) { name = getLocalizedString(name); resolved = true; } return name; } /** Set the display name. * @param d the new name */ public void setName(String d) { name = d; } /** Get the error regexp. * @return the error regexp */ public String getErrorExpression () { return errordesc; } /** Set the error regexp. * @param s the new regexp */ public void setErrorExpression(String s) { errordesc = s; } /** Get the filename backreference. * @return the index, or -1 for none */ public int getFilePos () { return filepos; } /** Set the filename backreference. * @param i the new index (-1 to disable) */ public void setFilePos(int i) { filepos = i; } /** Get the line-number backreference. * @return the index, or -1 for none */ public int getLinePos () { return linepos; } /** Set the line-number backreference. * @param i the new index (-1 to disable) */ public void setLinePos(int i) { linepos = i; } /** Get the column-number backreference. * @return the index, or -1 for none */ public int getColumnPos () { return columnpos; } /** Set the column-number backreference. * @param i the new index (-1 to disable) */ public void setColumnPos(int i) { columnpos = i; } /** Get the description backreference. * @return the index, or -1 for none */ public int getDescriptionPos () { return descpos; } /** Set the description backreference. * @param i the new index (-1 to disable) */ public void setDescriptionPos(int i) { descpos = i; } public boolean equals (Object o) { if ((o == null) || (!(o instanceof ErrorExpression))) return false; ErrorExpression him = (ErrorExpression) o; return getName().equals(him.getName()) && errordesc.equals(him.errordesc) && filepos == him.filepos && linepos == him.linepos && columnpos == him.columnpos && descpos == him.descpos; } public int hashCode () { return getName().hashCode(); } } /** Internal interface to provide different methods for locating of * file object and file name. */ interface FNP { public String getFileName (); public FileObject getFileObject (); /** JST: Do you know how SmallTalk compares numbers? Let's try * the same comparing here.... * * So three different subclasses => four comparing methods * * But as usual there is a room for improvement. */ public boolean equalTo (FNP fnp); public boolean equalToFile (java.io.File f); public boolean equalToResource (String res); public boolean equalToResourceAndFS (String res, FileSystem fs); public boolean equalToFileObject (FileObject obj); } }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.