edu.brown.cs.bubbles.bedrock.BedrockProject.java Source code

Java tutorial

Introduction

Here is the source code for edu.brown.cs.bubbles.bedrock.BedrockProject.java

Source

/********************************************************************************/
/*                              */
/*      BedrockProject.java                  */
/*                              */
/*   Project manager for Bubbles - Eclipse interface          */
/*                              */
/********************************************************************************/
/*   Copyright 2006 Brown University -- Steven P. Reiss            */
/*********************************************************************************
 *  Copyright 2011, Brown University, Providence, RI.             *
 *                               *
 *           All Rights Reserved                *
 *                               *
 * This program and the accompanying materials are made available under the    *
 * terms of the Eclipse Public License v1.0 which accompanies this distribution, *
 * and is available at                         *
 *   http://www.eclipse.org/legal/epl-v10.html             *
 *                               *
 ********************************************************************************/

/* RCS: $Header$ */

/*********************************************************************************
 *
 * $Log$
 *
 ********************************************************************************/

package edu.brown.cs.bubbles.bedrock;

import edu.brown.cs.ivy.xml.IvyXml;
import edu.brown.cs.ivy.xml.IvyXmlWriter;

import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.content.IContentDescription;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.preferences.IPreferencesService;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.jdt.core.*;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.*;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.*;
import org.eclipse.ui.actions.NewProjectAction;
import org.eclipse.ui.dialogs.PropertyDialogAction;
import org.osgi.framework.Bundle;
import org.osgi.service.prefs.Preferences;
import org.w3c.dom.Element;

import java.io.*;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;

class BedrockProject implements BedrockConstants, IResourceChangeListener {

    /********************************************************************************/
    /*                              */
    /*   Private Storage                      */
    /*                              */
    /********************************************************************************/

    private BedrockPlugin our_plugin;
    private boolean projects_inited;
    private boolean projects_registered;
    private Set<IProject> open_projects;
    private boolean projects_setup;
    private boolean use_android;

    private static boolean initial_build = false;
    private static boolean initial_refresh = false;

    private static Set<String> ignore_projects;

    private static boolean show_events = false;

    static {
        ignore_projects = new HashSet<String>();
        ignore_projects.add("RemoteSystemsTempFiles");
    }

    /********************************************************************************/
    /*                              */
    /*   Constructors                        */
    /*                              */
    /********************************************************************************/

    BedrockProject(BedrockPlugin bp) {
        our_plugin = bp;
        projects_inited = false;
        projects_registered = false;
        projects_setup = false;
        open_projects = new HashSet<IProject>();
    }

    /********************************************************************************/
    /*                              */
    /*   Starutp methods                      */
    /*                              */
    /********************************************************************************/

    void initialize() {
        if (projects_inited)
            return;

        IvyXmlWriter xw = new IvyXmlWriter(); // force loading
        xw.close();

        IWorkspace ws = ResourcesPlugin.getWorkspace();
        IWorkspaceRoot wr = ws.getRoot();

        BedrockPlugin.logI("WORKSPACE = " + wr.getName() + " " + wr.getFullPath());

        IProject[] projs = wr.getProjects();
        for (int i = 0; i < projs.length; ++i) {
            if (ignore_projects.contains(projs[i].getName()))
                continue;
            BedrockPlugin.logI("    PROJECT = " + projs[i].getName());
            String desc = "Project Setup for " + projs[i].getName();
            if (projs[i].isOpen()) {
                BedrockPlugin.logI("PROJECT OPEN");
                if (initial_build) {
                    try {
                        BedrockPlugin.logD("BUILD");
                        projs[i].build(IncrementalProjectBuilder.INCREMENTAL_BUILD,
                                new BedrockProgressMonitor(our_plugin, desc));
                    } catch (CoreException e) {
                        BedrockPlugin.logE("Problem doing initial build: " + e);
                    }
                }
                attachProject(projs[i], false);
            } else if (!PlatformUI.isWorkbenchRunning()) {
                try {
                    if (initial_refresh) {
                        BedrockPlugin.logI("REFRESH");
                        projs[i].refreshLocal(IResource.DEPTH_INFINITE, null);
                    }
                    if (initial_build) {
                        BedrockPlugin.logI("BUILD");
                        projs[i].build(IncrementalProjectBuilder.INCREMENTAL_BUILD,
                                new BedrockProgressMonitor(our_plugin, desc));
                    }
                } catch (CoreException e) {
                    BedrockPlugin.logE("Problem doing initial build: " + e);
                }
            }
        }

        projects_inited = true;
    }

    void register() {
        if (projects_registered)
            return;
        projects_registered = true;

        JavaCore.addPreProcessingResourceChangedListener(this,
                IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.POST_BUILD);
    }

    void terminate() {
        for (IProject p : new ArrayList<IProject>(open_projects)) {
            detachProject(p);
        }
    }

    /********************************************************************************/
    /*                              */
    /*   Command processing                     */
    /*                              */
    /********************************************************************************/

    void listProjects(IvyXmlWriter xw) {
        setupProjects();

        IWorkspace ws = ResourcesPlugin.getWorkspace();
        IWorkspaceRoot wr = ws.getRoot();
        IProject[] projs = wr.getProjects();

        for (int i = 0; i < projs.length; ++i) {
            if (ignore_projects.contains(projs[i].getName()))
                continue;
            if (projs[i].getLocation() == null)
                continue;
            xw.begin("PROJECT");
            xw.field("NAME", projs[i].getName());
            xw.field("OPEN", projs[i].isOpen());
            xw.field("WORKSPACE", wr.getLocation().toOSString());
            boolean isjava = false;
            boolean isandroid = false;
            try {
                isjava = projs[i].hasNature(JavaCore.NATURE_ID);
                isandroid = projs[i].hasNature("com.android.ide.eclipse.adt.AndroidNature");
            } catch (CoreException e) {
            }
            xw.field("ISJAVA", isjava);
            xw.field("ISANDROID", isandroid);
            try {
                xw.cdataElement("DESCRIPTION", projs[i].getDescription().getComment());
            } catch (CoreException e) {
            }
            xw.textElement("BASE", projs[i].getFullPath().toOSString());
            try {
                IProject[] rp = projs[i].getReferencedProjects();
                for (int j = 0; j < rp.length; ++j) {
                    xw.textElement("REFERENCES", rp[j].getName());
                }
            } catch (Exception e) {
            }
            IProject[] up = projs[i].getReferencingProjects();
            for (int j = 0; j < up.length; ++j) {
                xw.textElement("USEDBY", up[j].getName());
            }
            try {
                for (IBuildConfiguration ibcfg : projs[i].getBuildConfigs()) {
                    xw.begin("BUILDCONFIG");
                    xw.field("NAME", ibcfg.getName());
                    xw.field("CLASS", ibcfg.getClass().getName());
                    xw.end("BUILDCONFIG");
                }
            } catch (CoreException e) {
            }
            xw.end("PROJECT");
        }
    }

    void openProject(String name, boolean fil, boolean pat, boolean cls, boolean opt, boolean imps, String bkg,
            IvyXmlWriter xw) throws BedrockException {
        IProject p = findProject(name);

        attachProject(p, false);

        if (bkg != null) {
            ProjectThread pt = new ProjectThread(bkg, p, fil, pat, cls, opt);
            pt.start();
            if (xw != null)
                outputProject(p, false, false, false, false, false, xw);
        } else if (xw != null) {
            outputProject(p, fil, pat, cls, opt, imps, xw);
        }
    }

    void closeProject(String name, IvyXmlWriter _xw) throws BedrockException {
        detachProject(findProject(name));
    }

    void listSourceFiles(String name, IvyXmlWriter xw) throws BedrockException {
        IProject ip = findProject(name);

        addSourceFiles(ip, xw, new JavaSourceFilter());
    }

    void buildProject(String proj, boolean clean, boolean full, boolean refresh, IvyXmlWriter xw)
            throws BedrockException {
        IProject ip = findProject(proj);

        handleBuild(ip, clean, full, refresh);

        IMarker[] mrks;
        try {
            mrks = ip.findMarkers(null, true, IResource.DEPTH_INFINITE);
            BedrockUtil.outputMarkers(ip, mrks, xw);
        } catch (CoreException e) {
            throw new BedrockException("Problem finding errors", e);
        }
    }

    /********************************************************************************/
    /*                              */
    /*   Thread to compute and output project definitions         */
    /*                              */
    /********************************************************************************/

    private class ProjectThread extends Thread {

        private IProject for_project;
        private boolean do_files;
        private boolean do_patterns;
        private boolean do_classes;
        private boolean do_options;
        private String return_id;

        ProjectThread(String bkg, IProject p, boolean fil, boolean pat, boolean cls, boolean opt) {
            super("Bedrock_GetProjectInfo");
            return_id = bkg;
            for_project = p;
            do_files = fil;
            do_patterns = pat;
            do_classes = cls;
            do_options = opt;
        }

        @Override
        public void run() {
            IvyXmlWriter xw = our_plugin.beginMessage("PROJECTDATA");
            xw.field("BACKGROUND", return_id);
            outputProject(for_project, do_files, do_patterns, do_classes, do_options, false, xw);
            our_plugin.finishMessage(xw);
        }

    } // end of inner class ProjectThread

    /********************************************************************************/
    /*                              */
    /*   Project property editing                  */
    /*                              */
    /********************************************************************************/

    void editProject(String proj, boolean lcl, Element xml, IvyXmlWriter xw) throws BedrockException {
        if (lcl) {
            localEditProject(xml, xw);
            return;
        }

        IWorkspace ws = ResourcesPlugin.getWorkspace();
        IWorkspaceRoot wr = ws.getRoot();
        IProject ip = wr.getProject(proj);
        IWorkbenchWindow ww = null;

        try {
            IWorkbench wb = PlatformUI.getWorkbench();
            ww = wb.getActiveWorkbenchWindow();
            if (ww == null) {
                IWorkbenchWindow[] wins = wb.getWorkbenchWindows();
                if (wins != null && wins.length > 0)
                    ww = wins[0];
            }
            if (ww == null)
                ww = wb.openWorkbenchWindow(ip);
        } catch (Throwable t) {
            BedrockPlugin.logE("BEDROCK: problem finding window: " + t, t);
            return;
        }

        SelProvider sp = new SelProvider(ip, ww.getShell());

        Display.getDefault().asyncExec(new RunPropDialog(sp));
    }

    void localEditProject(Element pxml, IvyXmlWriter xw) throws BedrockException {
        String pnm = IvyXml.getAttrString(pxml, "NAME");
        IProject ip = findProject(pnm);
        IJavaProject ijp = JavaCore.create(ip);
        List<IClasspathEntry> ents = new ArrayList<IClasspathEntry>();
        try {
            for (Element oe : IvyXml.children(pxml, "OPTION")) {
                String k = IvyXml.getAttrString(oe, "NAME");
                String v = IvyXml.getAttrString(oe, "VALUE");
                if (k.startsWith("edu.brown.cs.bubbles.bedrock.")) {
                    String sfx = k.substring(29);
                    QualifiedName qn = new QualifiedName("edu.brown.cs.bubbles.bedrock", sfx);
                    try {
                        ip.setPersistentProperty(qn, v);
                    } catch (CoreException e) {
                        BedrockPlugin.logD("Problem setting property " + qn + ": " + e);
                    }
                } else
                    ijp.setOption(k, v);
            }

            for (Element xe : IvyXml.children(pxml, "XPREF")) {
                String q = IvyXml.getAttrString(xe, "NODE");
                String k = IvyXml.getAttrString(xe, "KEY");
                String v = IvyXml.getAttrString(xe, "VALUE");
                IPreferencesService ps = Platform.getPreferencesService();
                Preferences rn = ps.getRootNode();
                Preferences qn = rn.node(q);
                qn.put(k, v);
            }

            for (IClasspathEntry cpe : ijp.getRawClasspath())
                ents.add(cpe);
            for (Element pe : IvyXml.children(pxml, "PATH")) {
                updatePathElement(ents, pe);
            }
            IClasspathEntry[] enta = new IClasspathEntry[ents.size()];
            enta = ents.toArray(enta);
            ijp.setRawClasspath(enta, new BedrockProgressMonitor(our_plugin, "Update Paths"));
            ijp.save(null, false);
        } catch (CoreException e) {
            throw new BedrockException("Problem editing project", e);
        }
    }

    private void updatePathElement(List<IClasspathEntry> ents, Element xml) {
        IClasspathEntry oent = null;
        int id = IvyXml.getAttrInt(xml, "ID", 0);
        if (id != 0) {
            for (IClasspathEntry ent : ents) {
                if (ent.hashCode() == id) {
                    oent = ent;
                    break;
                }
            }
        }

        BedrockPlugin.logD("UPDATE PATH ELEMENT " + oent + " " + IvyXml.convertXmlToString(xml));

        if (IvyXml.getAttrString(xml, "TYPE").equals("LIBRARY")) {
            if (IvyXml.getAttrBool(xml, "DELETE")) {
                ents.remove(oent);
            } else if (IvyXml.getAttrBool(xml, "MODIFIED") || IvyXml.getAttrBool(xml, "NEW")) {
                String f = IvyXml.getTextElement(xml, "BINARY");
                IPath bin = (f == null ? null : Path.fromOSString(f));
                f = IvyXml.getTextElement(xml, "SOURCE");
                IPath src = (f == null ? null : Path.fromOSString(f));
                boolean optfg = IvyXml.getAttrBool(xml, "OPTIONAL");
                boolean export = IvyXml.getAttrBool(xml, "EXPORTED");
                IAccessRule[] rls = null;
                URL docu = null;
                String doc = IvyXml.getTextElement(xml, "JAVADOC");
                if (doc != null) {
                    try {
                        docu = new URL(doc);
                    } catch (MalformedURLException e) {
                    }
                    if (docu == null) {
                        try {
                            docu = new URL("file://" + doc);
                        } catch (MalformedURLException e) {
                        }
                    }
                }
                if (oent != null) {
                    rls = oent.getAccessRules();
                }

                IClasspathAttribute[] xatts = null;
                List<IClasspathAttribute> els = new ArrayList<IClasspathAttribute>();
                if (optfg)
                    els.add(JavaCore.newClasspathAttribute(IClasspathAttribute.OPTIONAL, "true"));
                if (docu != null) {
                    els.add(JavaCore.newClasspathAttribute(IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME,
                            docu.toString()));
                }
                if (!els.isEmpty()) {
                    xatts = new IClasspathAttribute[els.size()];
                    xatts = els.toArray(xatts);
                }

                IClasspathEntry nent = null;
                if (bin != null)
                    nent = JavaCore.newLibraryEntry(bin, src, null, rls, xatts, export);
                else
                    nent = JavaCore.newSourceEntry(src, null, null, null, xatts);

                if (IvyXml.getAttrBool(xml, "MODIFIED") && oent != null) {
                    int idx = ents.indexOf(oent);
                    ents.set(idx, nent);
                } else {
                    ents.add(nent);
                }
            }
        }
    }

    private static final class SelProvider implements ISelectionProvider, IShellProvider {

        private IStructuredSelection project_selection;
        private Shell use_shell;

        SelProvider(IProject ip, Shell sh) {
            project_selection = new StructuredSelection(ip);
            use_shell = sh;
        }

        public void addSelectionChangedListener(ISelectionChangedListener listener) {
        }

        public void removeSelectionChangedListener(ISelectionChangedListener listener) {
        }

        public void setSelection(ISelection selection) {
        }

        public ISelection getSelection() {
            return project_selection;
        }

        public Shell getShell() {
            return use_shell;
        }

    } // end of inner class SelProvider

    private static final class RunPropDialog implements Runnable {

        private SelProvider use_provider;

        RunPropDialog(SelProvider sp) {
            use_provider = sp;
        }

        @Override
        public void run() {
            PropertyDialogAction act = new PropertyDialogAction(use_provider, use_provider);
            try {
                act.run();
            } catch (Throwable t) {
                BedrockPlugin.logE("BEDROCK: Problem with project property: " + t, t);
            }
        }

    } // end of inner class RunPropDialog

    /********************************************************************************/
    /*                              */
    /*   New project setup                     */
    /*                              */
    /********************************************************************************/

    void createProject() {
        IWorkbenchWindow ww = null;

        try {
            IWorkbench wb = PlatformUI.getWorkbench();
            ww = wb.getActiveWorkbenchWindow();
            if (ww == null) {
                IWorkbenchWindow[] wins = wb.getWorkbenchWindows();
                if (wins != null && wins.length > 0)
                    ww = wins[0];
            }
            if (ww == null)
                ww = wb.openWorkbenchWindow(wb);
        } catch (Throwable t) {
            BedrockPlugin.logE("BEDROCK: problem finding window: " + t, t);
        }

        Display.getDefault().asyncExec(new RunNewDialog(ww));
    }

    /**
     * Adds a project that is already in the workspace folder but is not
     * a member of the workspace yet
     */
    void importExistingProject(String name) throws Exception {
        IProject p = ResourcesPlugin.getWorkspace().getRoot().getProject(name);

        //if it already exists in the workspace don't do anything
        if (p.exists())
            return;

        p.create(null);
        p.open(null);
        JavaCore.create(p);
        p.refreshLocal(IResource.DEPTH_INFINITE, null);
    }

    private static final class RunNewDialog implements Runnable {

        private IWorkbenchWindow work_window;

        RunNewDialog(IWorkbenchWindow ww) {
            work_window = ww;
        }

        @Override
        public void run() {
            NewProjectAction act = new NewProjectAction(work_window);
            try {
                act.run();
            } catch (Throwable t) {
                BedrockPlugin.logE("BEDROCK: Problem with new project: " + t, t);
            }
        }

    } // end of inner class RunNewDialog

    /********************************************************************************/
    /*                              */
    /*   Command utility routines                  */
    /*                              */
    /********************************************************************************/

    IProject findProject(String name) throws BedrockException {
        setupProjects();

        if (name == null)
            return null;
        if (ignore_projects.contains(name))
            return null;

        IWorkspace ws = ResourcesPlugin.getWorkspace();
        IWorkspaceRoot wr = ws.getRoot();
        IProject ip = wr.getProject(name);

        if (ip == null)
            throw new BedrockException("Project " + name + " not in workspace");

        return ip;
    }

    private static class JavaSourceFilter implements FileFilter {

        public boolean accept(File f) {
            return f.getPath().endsWith(".java");
        }

    } // end of subclass JavaSourceFilter

    static boolean useProject(String name) {
        if (ignore_projects.contains(name))
            return false;

        return true;
    }

    /********************************************************************************/
    /*                              */
    /*   Attach and detach methods                  */
    /*                              */
    /********************************************************************************/

    private void attachProject(IProject p, boolean setup) {
        if (!open_projects.contains(p)) {
            open_projects.add(p);
        }

        try {
            p.open(null);
            IJavaProject ijp = JavaCore.create(p);
            ijp.open(null);
            if (setup)
                setupDefaults(ijp);
            // ijp.setOption("org.eclipse.debug.ui.switch_perspective_on_suspend","never");
            // resolveAll(ijp);
        } catch (JavaModelException e) {
            BedrockPlugin.logE("Error resolving project: " + e);
            return;
        } catch (CoreException e) {
            BedrockPlugin.logE("Error opening project: " + e);
            return;
        } catch (Throwable e) {
            BedrockPlugin.logE("Error with project attach: " + e);
            return;
        }

    }

    private void detachProject(IProject p) {
        if (!open_projects.contains(p))
            return;

        open_projects.remove(p);
    }

    private void setupProjects() {
        // BedrockPlugin.logD("CHECK SETUP " + projects_setup + " " + PlatformUI.isWorkbenchRunning());

        if (!projects_setup && PlatformUI.isWorkbenchRunning()) {
            BedrockApplication.getDisplay(); // wait for setup
            IWorkspace ws = ResourcesPlugin.getWorkspace();
            IWorkspaceRoot wr = ws.getRoot();
            IProject[] projs = wr.getProjects();
            for (IProject ip : projs)
                attachProject(ip, true);
            projects_setup = true;
        }
    }

    private void setupDefaults(IJavaProject ijp) {
        try {
            IPreferenceStore ps = DebugUITools.getPreferenceStore();
            String s = ps.getString("org.eclipse.debug.ui.switch_perspective_on_suspend");
            if (s == null || s.equals("prompt")) {
                ps.setValue("org.eclipse.debug.ui.switch_perspective_on_suspend", "never");
                BedrockPlugin
                        .logD("DEBUG PREF " + ps.getString("org.eclipse.debug.ui.switch_perspective_on_suspend"));
            }
            s = ps.getString("org.eclipse.debug.ui.save_dirty_editors_before_launch");
            if (s == null || s.equals("prompt")) {
                ps.setValue("org.eclipse.debug.ui.save_dirty_editors_before_launch", "always");
                BedrockPlugin
                        .logD("DEBUG PREF " + ps.getString("org.eclipse.debug.ui.switch_perspective_on_suspend"));
            }
        } catch (Throwable t) {
            BedrockPlugin.logE("Problem seting defaults", t);
        }
    }

    /********************************************************************************/
    /*                              */
    /*   Project Access methods                     */
    /*                              */
    /********************************************************************************/

    Collection<IFile> getAllSourceFiles(String p) throws BedrockException {
        Collection<IFile> rslt = findSourceFiles(findProject(p), null);

        return rslt;
    }

    Collection<IProject> getOpenProjects() {
        Collection<IProject> rslt = new ArrayList<IProject>(open_projects);

        return rslt;
    }

    /********************************************************************************/
    /*                              */
    /*   Package management methods                  */
    /*                              */
    /********************************************************************************/

    void createPackage(String proj, String pkg, boolean force, IvyXmlWriter xw) throws BedrockException {
        IProject ip = findProject(proj);
        IJavaProject ijp = JavaCore.create(ip);

        IPackageFragmentRoot ipfr = null;
        try {
            for (IPackageFragmentRoot pfr : ijp.getAllPackageFragmentRoots()) {
                try {
                    if (!pfr.isExternal() && !pfr.isArchive() && pfr.getKind() == IPackageFragmentRoot.K_SOURCE) {
                        ipfr = pfr;
                        break;
                    }
                } catch (JavaModelException e) {
                }
            }
        } catch (JavaModelException e) {
            throw new BedrockException("Problem finding package roots: " + e, e);
        }

        if (ipfr == null)
            throw new BedrockException("Can't find source fragment root");

        IPackageFragment ifr = null;
        try {
            ifr = ipfr.createPackageFragment(pkg, force, null);
            ifr.save(null, force);
            ifr.open(null);
        } catch (JavaModelException e) {
            throw new BedrockException("Problem creating package: " + e, e);
        }

        xw.begin("PACKAGE");
        xw.field("NAME", ifr.getElementName());
        File f = BedrockUtil.getFileForPath(ifr.getPath(), ip);
        xw.field("PATH", f.getAbsolutePath());
        xw.end("PACKAGE");
    }

    void findPackage(String proj, String pkg, IvyXmlWriter xw) throws BedrockException {
        IProject ip = findProject(proj);
        IPackageFragment ipf = findPackageFragment(proj, pkg);

        if (ipf == null)
            return;

        File f = BedrockUtil.getFileForPath(ipf.getPath(), ip);

        xw.begin("PACKAGE");
        xw.field("NAME", ipf.getElementName());
        xw.field("PATH", f.getAbsolutePath());
        BedrockUtil.outputJavaElement(ipf, xw);
        xw.end("PACKAGE");
    }

    IPackageFragment findPackageFragment(String proj, String pkg) throws BedrockException {
        IProject ip = findProject(proj);
        IJavaProject ijp = JavaCore.create(ip);
        if (ijp == null)
            return null;

        try {
            for (IPackageFragmentRoot pfr : ijp.getAllPackageFragmentRoots()) {
                try {
                    if (!pfr.isExternal() && !pfr.isArchive() && pfr.getKind() == IPackageFragmentRoot.K_SOURCE) {
                        IPackageFragment ipf = pfr.getPackageFragment(pkg);
                        if (ipf != null && ipf.isOpen()) {
                            File f = BedrockUtil.getFileForPath(ipf.getPath(), ip);
                            if (f.exists())
                                return ipf;
                            BedrockPlugin.logE("Fragment path doesn't exist: " + f);
                        }
                    }
                } catch (JavaModelException e) {
                }
            }
        } catch (JavaModelException e) {
            e.printStackTrace();
            throw new BedrockException("Problem finding package roots: " + e, e);
        }

        return null;
    }

    /********************************************************************************/
    /*                              */
    /*   Preference methods                     */
    /*                              */
    /********************************************************************************/

    void handlePreferences(String proj, IvyXmlWriter xw) {
        xw.begin("PREFERENCES");

        Map<?, ?> opts;
        if (proj == null) {
            opts = JavaCore.getOptions();
        } else {
            try {
                IProject ip = findProject(proj);
                IJavaProject ijp = JavaCore.create(ip);
                opts = ijp.getOptions(true);
            } catch (BedrockException e) {
                opts = JavaCore.getOptions();
            }
        }

        for (Map.Entry<?, ?> ent : opts.entrySet()) {
            String key = (String) ent.getKey();
            String val = (String) ent.getValue();
            xw.begin("PREF");
            xw.field("NAME", key);
            xw.field("VALUE", val);
            xw.field("OPTS", true);
            xw.end("PREF");
        }

        // handle special preferences
        try {
            Bundle b = Platform.getBundle("com.android.ide.eclipse.adt");
            if (b != null) {
                xw.begin("PREF");
                xw.field("NAME", "bedrock.useAndroid");
                xw.field("VALUE", true);
                xw.field("OPTS", true);
                xw.end("PREF");
                use_android = true;
            }
        } catch (Throwable t) {
        }

        xw.end("PREFERENCES");
    }

    void handleSetPreferences(String proj, Element xml, IvyXmlWriter xw) {
        if (proj == null) {
            IWorkspace ws = ResourcesPlugin.getWorkspace();
            IWorkspaceRoot wr = ws.getRoot();
            IProject[] projs = wr.getProjects();
            for (int i = 0; i < projs.length; ++i) {
                setProjectPreferences(projs[i], xml);
            }
            setProjectPreferences(null, xml);
        } else {
            try {
                IProject ip = findProject(proj);
                setProjectPreferences(ip, xml);
            } catch (BedrockException e) {
            }
        }
    }

    @SuppressWarnings("unchecked")
    private boolean setProjectPreferences(IProject ip, Element xml) {
        Map<Object, Object> opts;
        IJavaProject ijp = null;

        if (ip != null) {
            ijp = JavaCore.create(ip);
            if (ijp == null)
                return false;
            opts = ijp.getOptions(false);
        } else
            opts = JavaCore.getOptions();

        for (Element opt : IvyXml.children(xml, "OPTION")) {
            String nm = IvyXml.getAttrString(opt, "NAME");
            String vl = IvyXml.getAttrString(opt, "VALUE");
            opts.put(nm, vl);
        }

        if (ijp != null) {
            ijp.setOptions(opts);
        } else {
            Hashtable<?, ?> nopts = new Hashtable<Object, Object>(opts);
            JavaCore.setOptions(nopts);
        }

        return true;
    }

    /********************************************************************************/
    /*                              */
    /*   Project search methods                     */
    /*                              */
    /********************************************************************************/

    Collection<IFile> findSourceFiles(IResource ir, Collection<IFile> rslt) {
        if (rslt == null)
            rslt = new HashSet<IFile>();

        try {
            if (ir instanceof IFile) {
                IFile ifl = (IFile) ir;
                rslt.add(ifl);
            } else if (ir instanceof IContainer) {
                IContainer ic = (IContainer) ir;
                IResource[] mems = ic.members();
                for (int i = 0; i < mems.length; ++i) {
                    findSourceFiles(mems[i], rslt);
                }
            }
        } catch (CoreException e) {
            BedrockPlugin.logE("Problem getting source files: " + e);
        }

        return rslt;
    }

    ICompilationUnit getCompilationUnit(String proj, String file) throws BedrockException {
        //TODO: This should find the current working copy, not the underlying unit

        IProject ip = findProjectForFile(proj, file);
        if (ip == null)
            return null;

        IJavaProject ijp = JavaCore.create(ip);
        ICompilationUnit icu = checkFilePrefix(ijp, null, file);
        if (icu != null)
            return icu;
        if (ijp == null)
            return null;

        try {
            IClasspathEntry[] ents = ijp.getResolvedClasspath(true);
            for (int i = 0; i < ents.length; ++i) {
                if (ents[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) {
                    IPath p = ents[i].getPath();
                    File f = BedrockUtil.getFileForPath(p, ip);
                    if (!f.exists())
                        continue;
                    icu = checkFilePrefix(ijp, f.getAbsolutePath(), file);
                    if (icu != null)
                        return icu;
                }
            }
        } catch (JavaModelException e) {
            BedrockPlugin.logE("Problem getting compilation unit: " + e);
        }

        return null;
    }

    private ICompilationUnit checkFilePrefix(IJavaProject ijp, String pfx, String file) {
        if (ijp == null)
            return null;

        if (pfx != null) {
            if (!file.startsWith(pfx))
                return null;
            int ln = pfx.length();
            if (file.charAt(ln) == File.separatorChar || file.charAt(ln) == '/')
                ++ln;
            file = file.substring(ln);
        }

        try {
            IPath fp = new Path(file);
            IJavaElement je = ijp.findElement(fp);
            if (je != null && je instanceof ICompilationUnit) {
                return (ICompilationUnit) je;
            }
        } catch (JavaModelException e) {
        }

        file = file.replace('\\', '/');

        try {
            IPath fp = new Path(file);
            IJavaElement je = ijp.findElement(fp);
            if (je != null && je instanceof ICompilationUnit) {
                return (ICompilationUnit) je;
            }
        } catch (JavaModelException e) {
        }

        return null;
    }

    IFile getProjectFile(String proj, String file) throws BedrockException {
        if (proj == null) {
            for (IProject ip : open_projects) {
                IFile ifl = findProjectFile(ip, file);
                if (ifl != null)
                    return ifl;
            }
            return null;
        }

        IProject ip = findProject(proj);

        return findProjectFile(ip, file);
    }

    IProject findProjectForFile(String proj, String file) throws BedrockException {
        if (proj == null && file != null) {
            for (IProject ip : open_projects) {
                IFile ifl = findProjectFile(ip, file);
                if (ifl != null)
                    return ip;
            }
            BedrockPlugin.logE("No project found for file " + file);
            return null;
        }

        return findProject(proj);
    }

    private IFile findProjectFile(IResource ir, String name) {
        try {
            if (ir instanceof IFile) {
                IFile ifl = (IFile) ir;
                File f = ifl.getLocation().toFile();
                if (f.getAbsolutePath().equals(name) || f.getPath().equals(name))
                    return ifl;
            } else if (ir instanceof IContainer) {
                IContainer ic = (IContainer) ir;
                IResource[] mems = ic.members();
                for (int i = 0; i < mems.length; ++i) {
                    IFile ifl = findProjectFile(mems[i], name);
                    if (ifl != null)
                        return ifl;
                }
            }
        } catch (CoreException e) {
            BedrockPlugin.logE("Problem getting source files: " + e);
        }

        return null;
    }

    /********************************************************************************/
    /*                              */
    /*   Project dumping methods                   */
    /*                              */
    /********************************************************************************/

    private void outputProject(IProject p, boolean fil, boolean pat, boolean cls, boolean opt, boolean imps,
            IvyXmlWriter xw) {
        if (p.getLocation() == null)
            return;

        xw.begin("PROJECT");
        xw.field("NAME", p.getName());
        xw.field("PATH", p.getLocation().toOSString());
        xw.field("WORKSPACE", p.getWorkspace().getRoot().getLocation().toOSString());
        xw.field("BEDROCKDIR", p.getWorkingLocation(BEDROCK_PLUGIN).toOSString());
        try {
            if (p.hasNature("org.eclipse.jdt.core.javanature"))
                xw.field("ISJAVA", true);
            if (p.hasNature("com.android.ide.eclipse.adt.AndroidNature"))
                xw.field("ISANDROID", true);
        } catch (CoreException e) {
        }

        IJavaProject jp = JavaCore.create(p);
        if (jp != null && pat) {
            xw.begin("CLASSPATH");
            addClassPaths(jp, xw, null, false);
            xw.end("CLASSPATH");
            xw.begin("RAWPATH");
            try {
                IClasspathEntry[] ents = jp.getRawClasspath();
                for (IClasspathEntry ent : ents) {
                    addPath(xw, jp, ent, false);
                }
            } catch (JavaModelException e) {
            }
            xw.end("RAWPATH");
        }

        if (fil) {
            xw.begin("FILES");
            addSourceFiles(p, xw, null);
            xw.end("FILES");
        }

        if (jp != null && cls) {
            xw.begin("CLASSES");
            addClasses(jp, xw);
            xw.end("CLASSES");
        }

        try {
            IProject[] rp = p.getReferencedProjects();
            IProject[] up = p.getReferencingProjects();
            for (int j = 0; j < rp.length; ++j) {
                xw.textElement("REFERENCES", rp[j].getName());
            }
            for (int j = 0; j < up.length; ++j) {
                xw.textElement("USEDBY", up[j].getName());
            }
        } catch (Exception e) {
        }

        if (opt && jp != null) {
            Map<?, ?> opts = jp.getOptions(false);
            for (Map.Entry<?, ?> ent : opts.entrySet()) {
                xw.begin("OPTION");
                xw.field("NAME", ent.getKey().toString());
                xw.field("VALUE", ent.getValue().toString());
                xw.end("OPTION");
            }
            Map<?, ?> allopts = jp.getOptions(true);
            for (Map.Entry<?, ?> ent : allopts.entrySet()) {
                String knm = (String) ent.getKey();
                if (opts.containsKey(knm))
                    continue;
                if (knm.startsWith("org.eclipse.jdt.core.formatter"))
                    continue;
                xw.begin("OPTION");
                xw.field("DEFAULT", true);
                xw.field("NAME", ent.getKey().toString());
                xw.field("VALUE", ent.getValue().toString());
                xw.end("OPTION");
            }
            try {
                Map<?, ?> pm = p.getPersistentProperties();
                for (Map.Entry<?, ?> ent : pm.entrySet()) {
                    QualifiedName qn = (QualifiedName) ent.getKey();
                    xw.begin("PROPERTY");
                    xw.field("QUAL", qn.getQualifier());
                    xw.field("NAME", qn.getLocalName());
                    xw.field("VALUE", ent.getValue().toString());
                    xw.end("PROPERTY");
                }
            } catch (CoreException e) {
            }
        }

        if (imps && jp != null) {
            try {
                for (IPackageFragment ipf : jp.getPackageFragments()) {
                    outputImports(xw, ipf);
                }
            } catch (JavaModelException e) {
            }
        }

        xw.end("PROJECT");
    }

    private void addClassPaths(IJavaProject jp, IvyXmlWriter xw, Set<IProject> done, boolean nest) {
        if (done == null)
            done = new HashSet<IProject>();
        done.add(jp.getProject());
        BedrockPlugin.logD("Getting class path for " + jp.getProject().getName());

        try {
            IClasspathEntry[] ents = jp.getResolvedClasspath(true);
            for (IClasspathEntry ent : ents) {
                addPath(xw, jp, ent, nest);
            }
            IPath op = jp.getOutputLocation();
            if (op != null) {
                xw.begin("PATH");
                xw.field("TYPE", "BINARY");
                File f = BedrockUtil.getFileForPath(op, jp.getProject());
                if (f.exists())
                    xw.textElement("BINARY", f.getAbsolutePath());
                xw.end("PATH");
            }
            for (IProject rp : jp.getProject().getReferencedProjects()) {
                if (done.contains(rp))
                    continue;
                IJavaProject jrp = JavaCore.create(rp);
                addClassPaths(jrp, xw, done, true);
            }
        } catch (CoreException e) {
            BedrockPlugin.logE("Problem resolving classpath: " + e);
        }
    }

    private void addPath(IvyXmlWriter xw, IJavaProject jp, IClasspathEntry ent, boolean nest) {
        IPath p = ent.getPath();
        IPath op = ent.getOutputLocation();
        IPath sp = ent.getSourceAttachmentPath();
        IProject ip = jp.getProject();

        String jdp = null;
        boolean opt = false;
        IClasspathAttribute[] atts = ent.getExtraAttributes();
        for (IClasspathAttribute att : atts) {
            if (att.getName().equals(IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME))
                jdp = att.getValue();
            else if (att.getName().equals(IClasspathAttribute.OPTIONAL)) {
                String v = att.getValue();
                if (v.equals("true"))
                    opt = true;
            }
        }

        if (p == null && op == null)
            return;
        File f1 = null;
        if (p != null) {
            f1 = BedrockUtil.getFileForPath(p, ip);
            if (!f1.exists()) {
                BedrockPlugin.logD("Path file " + p + " not found as " + f1);
                // f1 = null;
            }
        }
        File f2 = null;
        if (op != null) {
            f2 = BedrockUtil.getFileForPath(op, ip);
            if (!f2.exists()) {
                BedrockPlugin.logD("Path file " + op + " not found");
                f2 = null;
            }
        }
        File f3 = null;
        if (sp != null) {
            f3 = BedrockUtil.getFileForPath(sp, ip);
            if (!f3.exists()) {
                BedrockPlugin.logD("Path file " + sp + " not found");
                f3 = null;
            }
        }
        if (f1 == null && f2 == null)
            return;

        // references to nested projects are handled in addClassPaths
        if (ent.getEntryKind() == IClasspathEntry.CPE_PROJECT)
            return;

        xw.begin("PATH");
        xw.field("ID", ent.hashCode());
        if (nest)
            xw.field("NESTED", "TRUE");

        switch (ent.getEntryKind()) {
        case IClasspathEntry.CPE_SOURCE:
            xw.field("TYPE", "SOURCE");
            f3 = f1;
            f1 = null;
            break;
        case IClasspathEntry.CPE_PROJECT:
            xw.field("TYPE", "BINARY");
            break;
        case IClasspathEntry.CPE_LIBRARY:
            xw.field("TYPE", "LIBRARY");
            break;
        }
        if (ent.isExported())
            xw.field("EXPORTED", true);
        if (opt)
            xw.field("OPTIONAL", true);

        if (f1 != null)
            xw.textElement("BINARY", f1.getAbsolutePath());
        if (f2 != null)
            xw.textElement("OUTPUT", f2.getAbsolutePath());
        if (f3 != null)
            xw.textElement("SOURCE", f3.getAbsolutePath());
        if (jdp != null)
            xw.textElement("JAVADOC", jdp);

        IAccessRule[] rls = ent.getAccessRules();
        for (IAccessRule ar : rls) {
            xw.begin("ACCESS");
            xw.field("KIND", ar.getKind());
            xw.field("PATTERN", ar.getPattern().toString());
            xw.field("IGNOREIFBETTER", ar.ignoreIfBetter());
            xw.end("ACCESS");
        }

        xw.end("PATH");
    }

    private void addSourceFiles(IResource ir, IvyXmlWriter xw, FileFilter ff) {
        Collection<IFile> fls = findSourceFiles(ir, null);

        for (IFile ifl : fls) {
            IContentDescription cd = null;
            try {
                cd = ifl.getContentDescription();
            } catch (CoreException e) {
            }
            if (cd == null)
                continue;

            IContentType ct = cd.getContentType();
            IPath ip = ifl.getLocation();
            IPath ipr = ifl.getProjectRelativePath();
            File f = ip.toFile();
            if (ff != null && !ff.accept(f))
                continue;
            if (f.exists()) {
                try {
                    f = f.getCanonicalFile();
                } catch (IOException _e) {
                }
                xw.begin("FILE");
                if (ct.getId().endsWith("javaSource"))
                    xw.field("SOURCE", true);
                else if (ct.getId().endsWith("javaClass"))
                    xw.field("BINARY", true);
                else
                    xw.field("TYPENAME", ct.getId());
                xw.field("NAME", ifl.getName());
                if (ifl.isReadOnly())
                    xw.field("READONLY", true);
                if (ifl.isLinked())
                    xw.field("LINKED", true);
                if (!ifl.isSynchronized(IResource.DEPTH_ONE))
                    xw.field("SYNC", false);
                xw.field("PROJPATH", ipr.toOSString());
                xw.field("PATH", ip.toOSString());
                xw.text(f.getPath());
                xw.end("FILE");
            }
        }
    }

    private void addClasses(IJavaProject jp, IvyXmlWriter xw) {
        try {
            IClasspathEntry[] ents = jp.getResolvedClasspath(true);
            for (int k = 0; k < ents.length; ++k) {
                if (ents[k].getEntryKind() == IClasspathEntry.CPE_SOURCE) {
                    IPackageFragmentRoot[] rts = jp.findPackageFragmentRoots(ents[k]);
                    for (int l = 0; l < rts.length; ++l) {
                        IJavaElement[] elts = rts[l].getChildren();
                        for (int m = 0; m < elts.length; ++m) {
                            if (elts[m] instanceof IPackageFragment) {
                                IPackageFragment frag = (IPackageFragment) elts[m];
                                xw.textElement("PACKAGE", frag.getElementName());
                                for (ICompilationUnit icu : frag.getCompilationUnits()) {
                                    for (IType typ : icu.getTypes()) {
                                        outputType(typ, jp, xw);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch (JavaModelException e) {
            BedrockPlugin.logE("Problem getting class list: " + e);
        }
    }

    private void outputType(IType typ, IJavaProject jp, IvyXmlWriter xw) throws JavaModelException {
        xw.begin("TYPE");
        xw.field("NAME", typ.getFullyQualifiedName());
        IPath ip = typ.getPath();
        File f = BedrockUtil.getFileForPath(ip, jp.getProject());
        if (f.exists())
            xw.field("SOURCE", f.getAbsolutePath());
        File bf = findBinaryFor(jp, typ);
        if (bf != null)
            xw.field("BINARY", bf.getAbsolutePath());
        xw.end("TYPE");

        for (IType ntyp : typ.getTypes()) {
            outputType(ntyp, jp, xw);
        }
    }

    private void outputImports(IvyXmlWriter xw, IPackageFragment ipf) {
        try {
            for (ICompilationUnit icu : ipf.getCompilationUnits()) {
                for (IImportDeclaration imp : icu.getImports()) {
                    xw.begin("IMPORT");
                    if (imp.isOnDemand())
                        xw.field("DEMAND", true);
                    if (Modifier.isStatic(imp.getFlags()))
                        xw.field("STATIC", true);
                    xw.text(imp.getElementName());
                    xw.end("IMPORT");
                }
            }
        } catch (JavaModelException e) {
        }
    }

    private File findBinaryFor(IJavaProject jp, IType typ) {
        IPath op = jp.readOutputLocation();
        // op might not be correct if there is an output directory associated with
        // the source directory

        String tnm = typ.getFullyQualifiedName();
        tnm = tnm.replace('.', File.separatorChar);
        IPath cp = op.append(tnm + ".class");
        File f = BedrockUtil.getFileForPath(cp, jp.getProject());
        return f;
    }

    /********************************************************************************/
    /*                              */
    /*   Build methods                        */
    /*                              */
    /********************************************************************************/

    private void handleBuild(IProject p, boolean clean, boolean full, boolean refresh) throws BedrockException {
        if (use_android)
            BedrockApplication.getDisplay();

        try {
            if (refresh) {
                String desc = "Refreshing project " + p.getName();
                BedrockProgressMonitor wait = new BedrockProgressMonitor(our_plugin, desc);
                p.refreshLocal(IResource.DEPTH_INFINITE, wait);
                wait.waitFor();
            }
            int kind = IncrementalProjectBuilder.INCREMENTAL_BUILD;
            String knm = "";
            if (clean) {
                kind = IncrementalProjectBuilder.CLEAN_BUILD;
                knm = " (clean)";
            } else if (full) {
                kind = IncrementalProjectBuilder.FULL_BUILD;
                knm = " (full)";
            }
            String desc = "Building " + knm + " project " + p.getName();
            p.build(kind, new BedrockProgressMonitor(our_plugin, desc));
        } catch (Throwable t) {
            throw new BedrockException("Build error: " + t, t);
        }
    }

    /********************************************************************************/
    /*                              */
    /*   Event handler for workspace resources               */
    /*                              */
    /********************************************************************************/

    @Override
    public void resourceChanged(IResourceChangeEvent evt) {
        if (show_events) {
            BedrockPlugin.logD("Resource Change: " + evt.getBuildKind() + " " + evt.getType() + " "
                    + evt.getSource() + " " + evt.getResource());
            IvyXmlWriter dxw = new IvyXmlWriter();
            dxw.begin("RESOURCECHANGE");
            IResourceDelta drd = evt.getDelta();
            dumpDelta(0, drd);
            BedrockUtil.outputResource(drd, dxw);
            dxw.end();
            BedrockPlugin.logD("Resource: " + dxw.toString());
        } else {
            BedrockPlugin.logD("Resource Change: " + evt.getBuildKind() + " " + evt.getType() + " "
                    + evt.getSource() + " " + evt.getResource());
        }

        if (evt.getType() == IResourceChangeEvent.POST_CHANGE) {
            try {
                IvyXmlWriter xw = our_plugin.beginMessage("RESOURCE");
                IResourceDelta rd = evt.getDelta();
                int ctr = BedrockUtil.outputResource(rd, xw);
                if (ctr == 0)
                    return; // nothing output
                our_plugin.finishMessage(xw);
            } catch (Throwable t) {
                BedrockPlugin.logE("Problem with resource: " + t);
                t.printStackTrace();
            }
        } else if (evt.getType() == IResourceChangeEvent.POST_BUILD) {
            try {
                IvyXmlWriter xw = our_plugin.beginMessage("BUILDDONE");
                IResourceDelta rd = evt.getDelta();
                int ctr = BedrockUtil.outputResource(rd, xw);
                if (ctr != 0)
                    our_plugin.finishMessage(xw);
                else {
                    checkForProjectOpen(rd);
                }
            } catch (Throwable t) {
                BedrockPlugin.logE("Problem with resource: " + t);
                t.printStackTrace();
            }
        }
    }

    private void dumpDelta(int lvl, IResourceDelta drd) {
        if (drd == null)
            return;
        BedrockPlugin.logD("Resource " + lvl + " Delta: " + drd + " " + drd.getFullPath() + " " + drd.getFlags()
                + " " + drd.getKind() + " " + drd.getResource());
        for (IResourceDelta xrd : drd.getAffectedChildren()) {
            dumpDelta(lvl + 1, xrd);
        }
    }

    private void checkForProjectOpen(IResourceDelta rd) {
        IResource ir = rd.getResource();
        if (rd.getFlags() == IResourceDelta.OPEN) {
            if (ir != null && ir.getProject() != null && ir.getType() == IResource.PROJECT) {
                IvyXmlWriter xw = our_plugin.beginMessage("PROJECTOPEN");
                xw.field("PROJECT", ir.getProject().getName());
                our_plugin.finishMessage(xw);
            }
        } else if (ir.getType() == IResource.ROOT) {
            for (IResourceDelta crd : rd.getAffectedChildren()) {
                checkForProjectOpen(crd);
            }
        }
    }

    /********************************************************************************/
    /*                              */
    /*   Project editing methods                   */
    /*                              */
    /********************************************************************************/

    void setProjectClassPath(String proj, Element desc) {
        // List<IClasspathEntry> class_paths = new ArrayList<IClasspathEntry>();
    }

    void setProjectOutputPath(String proj, String path) {
    }

    void setProjectOption(String proj, String name, String value) {
    }

    void setProjectDescription(String proj, Element desc) {
    }

    void createProject(String proj, Element desc) {
    }

} // end of class BedrockProject

/* end of BedrockProject.java */