FileDocCategorySizeDatePackage
BaseBuilder.javaAPI DocAndroid 1.5 API35073Wed May 06 22:41:10 BST 2009com.android.ide.eclipse.adt.build

BaseBuilder

public abstract class BaseBuilder extends org.eclipse.core.resources.IncrementalProjectBuilder
Base builder for XML files. This class allows for basic XML parsing with error checking and marking the files for errors/warnings.

Fields Summary
private static final Pattern
sPattern0Line1
Single line aapt warning for skipping files.
" (skipping hidden file '<file path>'"
private static final Pattern
sPattern1Line1
First line of dual line aapt error.
"ERROR at line <line>: <error>"
" (Occurred while parsing <path>)"
private static final Pattern
sPattern1Line2
Second line of dual line aapt error.
"ERROR at line <line>: <error>"
" (Occurred while parsing <path>)"
private static final Pattern
sPattern2Line1
First line of dual line aapt error.
"ERROR: <error>"
"Defined at file <path> line <line>"
private static final Pattern
sPattern2Line2
Second line of dual line aapt error.
"ERROR: <error>"
"Defined at file <path> line <line>"
private static final Pattern
sPattern3Line1
Single line aapt error
"<path> line <line>: <error>"
private static final Pattern
sPattern4Line1
First line of dual line aapt error.
"ERROR parsing XML file <path>"
"<error> at line <line>"
private static final Pattern
sPattern4Line2
Second line of dual line aapt error.
"ERROR parsing XML file <path>"
"<error> at line <line>"
private static final Pattern
sPattern5Line1
Single line aapt warning
"<path>:<line>: <error>"
private static final Pattern
sPattern6Line1
Single line aapt error
"<path>:<line>: <error>"
private static final Pattern
sPattern7Line1
4 line aapt error
"ERROR: 9-path image <path> malformed"
Line 2 and 3 are taken as-is while line 4 is ignored (it repeats with
'ERROR: failure processing <path>)
private static final Pattern
sPattern8Line1
private static final Pattern
sPattern9Line1
2 line aapt error
"ERROR: Invalid configuration: foo"
" ^^^"
There's no need to parse the 2nd line.
private SAXParserFactory
mParserFactory
SAX Parser factory.
Constructors Summary
public BaseBuilder()

        super();
        mParserFactory = SAXParserFactory.newInstance();

        // FIXME when the compiled XML support for namespace is in, set this to true.
        mParserFactory.setNamespaceAware(false);
    
Methods Summary
protected final voidabortOnBadSetup(org.eclipse.core.resources.IProject project)
Aborts the build if the SDK/project setups are broken. This does not display any errors.

param
project The {@link IJavaProject} being compiled.
throws
CoreException

        // check if we have finished loading the SDK.
        if (AdtPlugin.getDefault().getSdkLoadStatus() != LoadStatus.LOADED) {
            // we exit silently
            stopBuild("SDK is not loaded yet");
        }

        // abort if there are TARGET or ADT type markers
        IMarker[] markers = project.findMarkers(AdtConstants.MARKER_TARGET,
                false /*includeSubtypes*/, IResource.DEPTH_ZERO);
        
        if (markers.length > 0) {
            stopBuild("");
        }
        
        markers = project.findMarkers(AdtConstants.MARKER_ADT, false /*includeSubtypes*/,
                IResource.DEPTH_ZERO);
        
        if (markers.length > 0) {
            stopBuild("");
        }
    
private final booleancheckAndMark(java.lang.String location, java.lang.String lineStr, java.lang.String message, java.lang.String root, org.eclipse.core.resources.IProject project, java.lang.String markerId, int severity)
Check if the parameters gotten from the error output are valid, and mark the file with an AAPT marker.

param
location the full OS path of the error file. If null, the project is marked
param
lineStr
param
message
param
root The root directory of the project, in OS specific format.
param
project
param
markerId The marker id to put.
param
severity The severity of the marker to put (IMarker.SEVERITY_*)
return
true if the parameters were valid and the file was marked successfully.
see
IMarker

        // check this is in fact a file
        if (location != null) {
            File f = new File(location);
            if (f.exists() == false) {
                return false;
            }
        }

        // get the line number
        int line = -1; // default value for error with no line.

        if (lineStr != null) {
            try {
                line = Integer.parseInt(lineStr);
            } catch (NumberFormatException e) {
                // looks like the string we extracted wasn't a valid
                // file number. Parsing failed and we return true
                return false;
            }
        }

        // add the marker
        IResource f2 = project;
        if (location != null) {
            f2 = getResourceFromFullPath(location, root, project);
            if (f2 == null) {
                return false;
            }
        }

        // check if there's a similar marker already, since aapt is launched twice
        boolean markerAlreadyExists = false;
        try {
            IMarker[] markers = f2.findMarkers(markerId, true, IResource.DEPTH_ZERO);

            for (IMarker marker : markers) {
                int tmpLine = marker.getAttribute(IMarker.LINE_NUMBER, -1);
                if (tmpLine != line) {
                    break;
                }

                int tmpSeverity = marker.getAttribute(IMarker.SEVERITY, -1);
                if (tmpSeverity != severity) {
                    break;
                }

                String tmpMsg = marker.getAttribute(IMarker.MESSAGE, null);
                if (tmpMsg == null || tmpMsg.equals(message) == false) {
                    break;
                }

                // if we're here, all the marker attributes are equals, we found it
                // and exit
                markerAlreadyExists = true;
                break;
            }

        } catch (CoreException e) {
            // if we couldn't get the markers, then we just mark the file again
            // (since markerAlreadyExists is initialized to false, we do nothing)
        }

        if (markerAlreadyExists == false) {
            if (line != -1) {
                BaseProjectHelper.addMarker(f2, markerId, message, line,
                        severity);
            } else {
                BaseProjectHelper.addMarker(f2, markerId, message, severity);
            }
        }

        return true;
    
protected final voidcheckXML(org.eclipse.core.resources.IResource resource, com.android.ide.eclipse.adt.build.BaseBuilder$BaseDeltaVisitor visitor)
Checks an Xml file for validity. Errors/warnings will be marked on the file

param
resource the resource to check
param
visitor a valid resource delta visitor


        // first make sure this is an xml file
        if (resource instanceof IFile) {
            IFile file = (IFile)resource;

            // remove previous markers
            removeMarkersFromFile(file, AndroidConstants.MARKER_XML);

            // create  the error handler
            XmlErrorHandler reporter = new XmlErrorHandler(file, visitor);
            try {
                // parse
                getParser().parse(file.getContents(), reporter);
            } catch (Exception e1) {
            }
        }
    
protected final java.lang.String[]getExternalJars()
Returns an array of external jar files used by the project.

return
an array of OS-specific absolute file paths

        // get the current project
        IProject project = getProject();

        // get a java project from it
        IJavaProject javaProject = JavaCore.create(project);
        
        IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();

        ArrayList<String> oslibraryList = new ArrayList<String>();
        IClasspathEntry[] classpaths = javaProject.readRawClasspath();
        if (classpaths != null) {
            for (IClasspathEntry e : classpaths) {
                if (e.getEntryKind() == IClasspathEntry.CPE_LIBRARY ||
                        e.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
                    // if this is a classpath variable reference, we resolve it.
                    if (e.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
                        e = JavaCore.getResolvedClasspathEntry(e); 
                    }

                    // get the IPath
                    IPath path = e.getPath();

                    // check the name ends with .jar
                    if (AndroidConstants.EXT_JAR.equalsIgnoreCase(path.getFileExtension())) {
                        boolean local = false;
                        IResource resource = wsRoot.findMember(path);
                        if (resource != null && resource.exists() &&
                                resource.getType() == IResource.FILE) {
                            local = true;
                            oslibraryList.add(resource.getLocation().toOSString());
                        }

                        if (local == false) {
                            // if the jar path doesn't match a workspace resource,
                            // then we get an OSString and check if this links to a valid file.
                            String osFullPath = path.toOSString();

                            File f = new File(osFullPath);
                            if (f.exists()) {
                                oslibraryList.add(osFullPath);
                            } else {
                                String message = String.format( Messages.Couldnt_Locate_s_Error,
                                        path);
                                AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE,
                                        project, message);

                                // Also put a warning marker on the project
                                markProject(AdtConstants.MARKER_ADT, message,
                                        IMarker.SEVERITY_WARNING);
                            }
                        }
                    }
                }
            }
        }

        return oslibraryList.toArray(new String[oslibraryList.size()]);
    
private final java.util.regex.MatchergetNextLineMatcher(java.util.ArrayList lines, int nextIndex, java.util.regex.Pattern pattern)
Returns a matching matcher for the next line

param
lines The array of lines
param
nextIndex The index of the next line
param
pattern The pattern to match
return
null if error or no match, the matcher otherwise.

        // unless we can't, because we reached the last line
        if (nextIndex == lines.size()) {
            // we expected a 2nd line, so we flag as error
            // and we bail
            return null;
        }

        Matcher m = pattern.matcher(lines.get(nextIndex));
        if (m.matches()) {
           return m;
        }

        return null;
    
protected final javax.xml.parsers.SAXParsergetParser()
Returns the SAXParserFactory, instantiating it first if it's not already created.

return
the SAXParserFactory object
throws
ParserConfigurationException
throws
SAXException

        return mParserFactory.newSAXParser();
    
private org.eclipse.core.resources.IResourcegetResourceFromFullPath(java.lang.String filename, java.lang.String root, org.eclipse.core.resources.IProject project)

        if (filename.startsWith(root)) {
            String file = filename.substring(root.length());

            // get the resource
            IResource r = project.findMember(file);

            // if the resource is valid, we add the marker
            if (r.exists()) {
                return r;
            }
        }

        return null;
    
protected final intgrabProcessOutput(java.lang.Process process, java.util.ArrayList results)
Get the stderr output of a process and return when the process is done.

param
process The process to get the ouput from
param
results The array to store the stderr output
return
the process return code.
throws
InterruptedException

    	// Due to the limited buffer size on windows for the standard io (stderr, stdout), we
    	// *need* to read both stdout and stderr all the time. If we don't and a process output
    	// a large amount, this could deadlock the process.

        // read the lines as they come. if null is returned, it's
        // because the process finished
        new Thread("") { //$NON-NLS-1$
            @Override
            public void run() {
                // create a buffer to read the stderr output
                InputStreamReader is = new InputStreamReader(process.getErrorStream());
                BufferedReader errReader = new BufferedReader(is);

                try {
                    while (true) {
                        String line = errReader.readLine();
                        if (line != null) {
                            results.add(line);
                        } else {
                            break;
                        }
                    }
                } catch (IOException e) {
                    // do nothing.
                }
            }
        }.start();

        new Thread("") { //$NON-NLS-1$
            @Override
            public void run() {
                InputStreamReader is = new InputStreamReader(process.getInputStream());
                BufferedReader outReader = new BufferedReader(is);

                IProject project = getProject();

                try {
                    while (true) {
                        String line = outReader.readLine();
                        if (line != null) {
                            AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE,
                                    project, line);
                        } else {
                            break;
                        }
                    }
                } catch (IOException e) {
                    // do nothing.
                }
            }

        }.start();

        // get the return code from the process
        return process.waitFor();
    
protected booleanloadProjectBooleanProperty(java.lang.String propertyName, boolean defaultValue)
Loads a boolean property from the persistent storage of the project.

param
propertyName the name of the property. The id of the plugin is added to this string.
param
defaultValue The default value to return if the property was not found.
return
the property value or the default value if the property was not found.

        IProject project = getProject();
        return ProjectHelper.loadBooleanProperty(project, propertyName, defaultValue);
    
protected org.eclipse.core.resources.IResourceloadProjectResourceProperty(java.lang.String propertyName)
Loads the path of a resource from the persistent storage of the project, and returns the corresponding IResource object.

param
propertyName the name of the property. The id of the plugin is added to this string.
return
The corresponding IResource object (or children interface) or null

        IProject project = getProject();
        return ProjectHelper.loadResourceProperty(project, propertyName);
    
protected java.lang.StringloadProjectStringProperty(java.lang.String propertyName)
Loads a String property from the persistent storage of the project.

param
propertyName the name of the property. The id of the plugin is added to this string.
return
the property value or null if it was not found.

        IProject project = getProject();
        return ProjectHelper.loadStringProperty(project, propertyName);
    
protected final voidmarkProject(java.lang.String markerId, java.lang.String message, int severity)
Adds a marker to the current project.

param
markerId The id of the marker to add.
param
message the message associated with the mark
param
severity the severity of the marker.

        BaseProjectHelper.addMarker(getProject(), markerId, message, severity);
    
protected final booleanparseAaptOutput(java.util.ArrayList results, org.eclipse.core.resources.IProject project)
Parse the output of aapt and mark the incorrect file with error markers

param
results the output of aapt
param
project the project containing the file to mark
return
true if the parsing failed, false if success.

        // nothing to parse? just return false;
        if (results.size() == 0) {
            return false;
        }

        // get the root of the project so that we can make IFile from full
        // file path
        String osRoot = project.getLocation().toOSString();

        Matcher m;

        for (int i = 0; i < results.size(); i++) {
            String p = results.get(i);

            m = sPattern0Line1.matcher(p);
            if (m.matches()) {
                // we ignore those (as this is an ignore message from aapt)
                continue;
            }

            m = sPattern1Line1.matcher(p);
            if (m.matches()) {
                String lineStr = m.group(1);
                String msg = m.group(2);

                // get the matcher for the next line.
                m = getNextLineMatcher(results, ++i, sPattern1Line2);
                if (m == null) {
                    return true;
                }

                String location = m.group(1);

                // check the values and attempt to mark the file.
                if (checkAndMark(location, lineStr, msg, osRoot, project,
                        AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
                    return true;
                }
                continue;
            }

            // this needs to be tested before Pattern2 since they both start with 'ERROR:'
            m = sPattern7Line1.matcher(p);
            if (m.matches()) {
                String location = m.group(1);
                String msg = p; // default msg is the line in case we don't find anything else

                if (++i < results.size()) {
                    msg = results.get(i).trim();
                    if (++i < results.size()) {
                        msg = msg + " - " + results.get(i).trim(); //$NON-NLS-1$

                        // skip the next line
                        i++;
                    }
                }

                // display the error
                if (checkAndMark(location, null, msg, osRoot, project,
                        AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
                    return true;
                }

                // success, go to the next line
                continue;
            }

            m =  sPattern2Line1.matcher(p);
            if (m.matches()) {
                // get the msg
                String msg = m.group(1);

                // get the matcher for the next line.
                m = getNextLineMatcher(results, ++i, sPattern2Line2);
                if (m == null) {
                    return true;
                }

                String location = m.group(1);
                String lineStr = m.group(2);

                // check the values and attempt to mark the file.
                if (checkAndMark(location, lineStr, msg, osRoot, project,
                        AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
                    return true;
                }
                continue;
            }

            m = sPattern3Line1.matcher(p);
            if (m.matches()) {
                String location = m.group(1);
                String lineStr = m.group(2);
                String msg = m.group(3);

                // check the values and attempt to mark the file.
                if (checkAndMark(location, lineStr, msg, osRoot, project,
                        AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
                    return true;
                }

                // success, go to the next line
                continue;
            }

            m = sPattern4Line1.matcher(p);
            if (m.matches()) {
                // get the filename.
                String location = m.group(1);

                // get the matcher for the next line.
                m = getNextLineMatcher(results, ++i, sPattern4Line2);
                if (m == null) {
                    return true;
                }

                String msg = m.group(1);
                String lineStr = m.group(2);

                // check the values and attempt to mark the file.
                if (checkAndMark(location, lineStr, msg, osRoot, project,
                        AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
                    return true;
                }

                // success, go to the next line
                continue;
            }

            m = sPattern5Line1.matcher(p);
            if (m.matches()) {
                String location = m.group(1);
                String lineStr = m.group(2);
                String msg = m.group(3);

                // check the values and attempt to mark the file.
                if (checkAndMark(location, lineStr, msg, osRoot, project,
                        AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_WARNING) == false) {
                    return true;
                }

                // success, go to the next line
                continue;
            }

            m = sPattern6Line1.matcher(p);
            if (m.matches()) {
                String location = m.group(1);
                String lineStr = m.group(2);
                String msg = m.group(3);

                // check the values and attempt to mark the file.
                if (checkAndMark(location, lineStr, msg, osRoot, project,
                        AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
                    return true;
                }

                // success, go to the next line
                continue;
            }
            
            m = sPattern8Line1.matcher(p);
            if (m.matches()) {
                String location = m.group(2);
                String msg = m.group(1);

                // check the values and attempt to mark the file.
                if (checkAndMark(location, null, msg, osRoot, project,
                        AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
                    return true;
                }

                // success, go to the next line
                continue;
            }

            m = sPattern9Line1.matcher(p);
            if (m.matches()) {
                String badConfig = m.group(1);
                String msg = String.format("APK Configuration filter '%1$s' is invalid", badConfig);
                
                // skip the next line
                i++;

                // check the values and attempt to mark the file.
                if (checkAndMark(null /*location*/, null, msg, osRoot, project,
                        AndroidConstants.MARKER_AAPT_PACKAGE, IMarker.SEVERITY_ERROR) == false) {
                    return true;
                }

                // success, go to the next line
                continue;
            }

            // invalid line format, flag as error, and bail
            return true;
        }

        return false;
    
protected voidremoveDerivedResources(org.eclipse.core.resources.IResource resource, org.eclipse.core.runtime.IProgressMonitor monitor)
Recursively delete all the derived resources.

        if (resource.exists()) {
            if (resource.isDerived()) {
                resource.delete(true, new SubProgressMonitor(monitor, 10));
            } else if (resource.getType() == IResource.FOLDER) {
                IFolder folder = (IFolder)resource;
                IResource[] members = folder.members();
                for (IResource member : members) {
                    removeDerivedResources(member, monitor);
                }
            }
        }
    
protected final voidremoveMarkersFromContainer(org.eclipse.core.resources.IContainer folder, java.lang.String markerId)
Removes markers from a container and its children.

param
folder The container from which to delete the markers.
param
markerId The id of the markers to remove. If null, all marker of type IMarker.PROBLEM will be removed.

        try {
            if (folder.exists()) {
                folder.deleteMarkers(markerId, true, IResource.DEPTH_INFINITE);
            }
        } catch (CoreException ce) {
            String msg = String.format(Messages.Marker_Delete_Error, markerId, folder.toString());
            AdtPlugin.printErrorToConsole(getProject(), msg);
        }
    
protected final voidremoveMarkersFromFile(org.eclipse.core.resources.IFile file, java.lang.String markerId)
Removes markers from a file.

param
file The file from which to delete the markers.
param
markerId The id of the markers to remove. If null, all marker of type IMarker.PROBLEM will be removed.

        try {
            if (file.exists()) {
                file.deleteMarkers(markerId, true, IResource.DEPTH_ZERO);
            }
        } catch (CoreException ce) {
            String msg = String.format(Messages.Marker_Delete_Error, markerId, file.toString());
            AdtPlugin.printErrorToConsole(getProject(), msg);
        }
    
protected static final voidremoveMarkersFromProject(org.eclipse.core.resources.IProject project, java.lang.String markerId)
Removes markers from a project and its children.

param
project The project from which to delete the markers
param
markerId The id of the markers to remove. If null, all marker of type IMarker.PROBLEM will be removed.

        try {
            if (project.exists()) {
                project.deleteMarkers(markerId, true, IResource.DEPTH_INFINITE);
            }
        } catch (CoreException ce) {
            String msg = String.format(Messages.Marker_Delete_Error, markerId, project.getName());
            AdtPlugin.printErrorToConsole(project, msg);
        }
    
protected booleansaveProjectBooleanProperty(java.lang.String propertyName, boolean value)
Saves a property into the persistent storage of the project.

param
propertyName the name of the property. The id of the plugin is added to this string.
param
value the value to save
return
true if the save succeeded.

        IProject project = getProject();
        return ProjectHelper.saveStringProperty(project, propertyName, Boolean.toString(value));
    
protected booleansaveProjectResourceProperty(java.lang.String propertyName, org.eclipse.core.resources.IResource resource)
Saves the path of a resource into the persistent storate of the project.

param
propertyName the name of the property. The id of the plugin is added to this string.
param
resource the resource which path is saved.
return
true if the save succeeded

        return ProjectHelper.saveResourceProperty(getProject(), propertyName, resource);
    
protected booleansaveProjectStringProperty(java.lang.String propertyName, java.lang.String value)
Saves a String property into the persistent storage of the project.

param
propertyName the name of the property. The id of the plugin is added to this string.
param
value the value to save
return
true if the save succeeded.

        IProject project = getProject();
        return ProjectHelper.saveStringProperty(project, propertyName, value);
    
protected final voidstopBuild(java.lang.String error, java.lang.Object args)
Throws an exception to cancel the build.

param
error the error message
param
args the printf-style arguments to the error message.
throws
CoreException

        throw new CoreException(new Status(IStatus.CANCEL, AdtPlugin.PLUGIN_ID,
                String.format(error, args)));