x10dt.search.core.pdb.X10FactGenerator.java Source code

Java tutorial

Introduction

Here is the source code for x10dt.search.core.pdb.X10FactGenerator.java

Source

/*******************************************************************************
 * Copyright (c) 2010 IBM Corporation.                                         *
 * 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                                   *
 *******************************************************************************/
package x10dt.search.core.pdb;

import static x10dt.search.core.pdb.X10FactTypeNames.APPLICATION;
import static x10dt.search.core.pdb.X10FactTypeNames.RUNTIME;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.imp.pdb.analysis.AnalysisException;
import org.eclipse.imp.pdb.analysis.IFactGenerator;
import org.eclipse.imp.pdb.analysis.IFactUpdater;
import org.eclipse.imp.pdb.facts.ISet;
import org.eclipse.imp.pdb.facts.IValue;
import org.eclipse.imp.pdb.facts.db.FactBase;
import org.eclipse.imp.pdb.facts.db.FactKey;
import org.eclipse.imp.pdb.facts.db.IFactContext;
import org.eclipse.imp.pdb.facts.db.context.WorkspaceContext;
import org.eclipse.imp.pdb.facts.type.Type;
import org.eclipse.imp.pdb.indexing.IndexedDocumentDescriptor;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.osgi.util.NLS;

import polyglot.ast.Node;
import polyglot.frontend.FileResource;
import polyglot.frontend.FileSource;
import polyglot.frontend.Job;
import polyglot.frontend.Source;
import polyglot.frontend.ZipResource;
import polyglot.visit.NodeVisitor;
import x10dt.search.core.Messages;
import x10dt.search.core.SearchCoreActivator;

final class X10FactGenerator implements IFactGenerator, IFactUpdater {

    X10FactGenerator(final SearchDBTypes searchDBTypes) {
        this.fIndexingCompiler = new IndexingCompiler();
        this.fSearchDBTypes = searchDBTypes;
    }

    // --- IFactGenerator's interface methods implementation

    public IValue generate(final Type type, final IFactContext context,
            final Map<IResource, IndexedDocumentDescriptor> workingCopies) {
        return null;
    }

    // --- IFactUpdater's interface methods implementation

    public void update(final FactBase factBase, final Type type, final IFactContext context,
            final IResource resource, final int changeKind,
            final Map<IResource, IndexedDocumentDescriptor> workingCopies) throws AnalysisException {
        if ((resource.getType() == IResource.FILE) && !X10_EXT.equals(((IFile) resource).getFileExtension())) {
            return;
        }
        if (changeKind == IResourceDelta.REMOVED) {
            final ITypeManager typeManager = this.fSearchDBTypes.getTypeManager(type.getName(), APPLICATION);
            try {
                typeManager.initWriter(factBase, context, resource);
                typeManager.writeDataInFactBase(factBase, context);
            } finally {
                typeManager.clearWriter();
            }
        } else {
            IndexedDocumentDescriptor value = null;
            for (final Map.Entry<IResource, IndexedDocumentDescriptor> e : workingCopies.entrySet()) {
                if (e.getKey().equals(resource)) {
                    value = e.getValue();
                }
            }
            if (value == null) {
                final CompilerOptionsBuilder cmpOptBuilder = processResource(resource);
                if (cmpOptBuilder != null) {
                    update(factBase, type, context, resource, cmpOptBuilder, cmpOptBuilder.getSourceEntrySet());
                }
            } else {
                update(factBase, type, context, resource, value);
            }

            //        
            //      final Map<IResource, IndexedDocumentDescriptor> map;
            //      if (workingCopies.isEmpty()) { //MV
            //        map = new HashMap<IResource, IndexedDocumentDescriptor>(1);
            //        map.put(resource, null);
            //      } else {
            //        map = workingCopies;
            //      }
            //      for (final Map.Entry<IResource, IndexedDocumentDescriptor> entry : map.entrySet()) {
            //        if (entry.getValue() == null) {
            //          final CompilerOptionsBuilder cmpOptBuilder = processResource(entry.getKey());
            //          if (cmpOptBuilder != null) {
            //            update(factBase, type, context, entry.getKey(), cmpOptBuilder, cmpOptBuilder.getSourceEntrySet());
            //          }
            //        } else {
            //          update(factBase, type, context, entry.getKey(), entry.getValue());
            //        }
            //      }
        }
    }

    public void update(final FactBase factBase, final Type type, final IFactContext context,
            final IResource resource, final Map<IResource, IndexedDocumentDescriptor> workingCopies)
            throws AnalysisException {
        if ((resource.getType() == IResource.FILE) && !X10_EXT.equals(((IFile) resource).getFileExtension())) {
            return;
        }

        IndexedDocumentDescriptor value = null;

        for (final Map.Entry<IResource, IndexedDocumentDescriptor> e : workingCopies.entrySet()) {
            if (e.getKey().equals(resource)) {
                value = e.getValue();
            }
        }

        if (value == null) {
            final CompilerOptionsBuilder cmpOptBuilder = processResource(resource);
            if (cmpOptBuilder != null) {
                final Set<Map.Entry<String, Collection<Source>>> entries = cmpOptBuilder.getSourceEntrySet();
                if (entries.isEmpty()) {
                    final ITypeManager typeManager = this.fSearchDBTypes.getTypeManager(type.getName(),
                            APPLICATION);
                    try {
                        typeManager.initWriter(factBase, context, resource);
                        typeManager.writeDataInFactBase(factBase, context);
                    } finally {
                        typeManager.clearWriter();
                    }
                } else {
                    update(factBase, type, context, resource, cmpOptBuilder, entries);
                }
            }
        } else {
            update(factBase, type, context, resource, value);
        }

        //final Map<IResource, IndexedDocumentDescriptor> map;
        //if (workingCopies.isEmpty()) { // MV
        //  map = new HashMap<IResource, IndexedDocumentDescriptor>(1);
        //  map.put(resource, null);
        //} else {
        //  map = workingCopies;
        //}

        //    for (final Map.Entry<IResource, IndexedDocumentDescriptor> entry : map.entrySet()) {
        //      if (entry.getValue() == null) {
        //        final CompilerOptionsBuilder cmpOptBuilder = processResource(entry.getKey());
        //        if (cmpOptBuilder != null) {
        //          final Set<Map.Entry<String, Collection<Source>>> entries = cmpOptBuilder.getSourceEntrySet();
        //          if (entries.isEmpty()) {
        //            final ITypeManager typeManager = this.fSearchDBTypes.getTypeManager(type.getName(), APPLICATION);
        //            try {
        //              typeManager.initWriter(factBase, context, entry.getKey());
        //              typeManager.writeDataInFactBase(factBase, context);
        //            } finally {
        //              typeManager.clearWriter();
        //            }
        //          } else {
        //            update(factBase, type, context, entry.getKey(), cmpOptBuilder, entries);
        //          }
        //        }
        //      } else {
        //        update(factBase, type, context, entry.getKey(), entry.getValue());
        //      }
        //    }
    }

    // --- Private code

    private boolean hasIndexingFile(final String indexingFileName) {
        final File pluginStateLocation = Platform.getStateLocation(SearchCoreActivator.getInstance().getBundle())
                .toFile();
        final File indexingFile = new File(pluginStateLocation, indexingFileName);
        return indexingFile.exists();
    }

    private void processEntries(final CompilerOptionsBuilder cmpOptBuilder, final IWorkspaceRoot wsRoot,
            final IClasspathEntry[] entries, final IJavaProject javaProject, final IResource contextResource,
            final boolean isInRuntime) throws JavaModelException, AnalysisException {
        for (final IClasspathEntry pathEntry : entries) {
            switch (pathEntry.getEntryKind()) {
            case IClasspathEntry.CPE_SOURCE:
                if (pathEntry.getPath().isRoot()) {
                    cmpOptBuilder.addToSourcePath(pathEntry.getPath().toFile());
                } else {
                    cmpOptBuilder.addToSourcePath(wsRoot.getLocation().append(pathEntry.getPath()).toFile());
                }
                if (pathEntry.getPath().segmentCount() > 1) {
                    processSourceFolder(cmpOptBuilder, wsRoot.getFolder(pathEntry.getPath()), contextResource);
                }
                break;

            case IClasspathEntry.CPE_LIBRARY:
                try {
                    final IPackageFragmentRoot pkgRoot = javaProject.findPackageFragmentRoot(pathEntry.getPath());
                    if ((pkgRoot != null) && pkgRoot.exists()) {
                        final File localFile;
                        if (pkgRoot.isExternal()) {
                            localFile = pathEntry.getPath().toFile();
                        } else {
                            localFile = pkgRoot.getResource().getLocation().toFile();
                        }
                        cmpOptBuilder.addToClassPath(localFile.getAbsolutePath());
                        if (isInRuntime) {
                            cmpOptBuilder.addToSourcePath(localFile);
                        }
                        final ZipFile zipFile;
                        if (JAR_EXT.equals(pathEntry.getPath().getFileExtension())) {
                            zipFile = new JarFile(localFile);
                        } else {
                            zipFile = new ZipFile(localFile);
                        }
                        processLibrary(cmpOptBuilder, zipFile, localFile, contextResource, isInRuntime);
                    }
                } catch (IOException except) {
                    throw new AnalysisException(NLS.bind(Messages.XFG_JarReadingError, pathEntry.getPath()),
                            except);
                }
                break;

            case IClasspathEntry.CPE_CONTAINER:
                final IClasspathContainer cpContainer = JavaCore.getClasspathContainer(pathEntry.getPath(),
                        javaProject);
                processEntries(cmpOptBuilder, wsRoot, cpContainer.getClasspathEntries(), javaProject,
                        contextResource, true);
                break;

            case IClasspathEntry.CPE_PROJECT:
                final IResource projectResource = ResourcesPlugin.getWorkspace().getRoot()
                        .findMember(pathEntry.getPath());
                if ((projectResource != null) && projectResource.isAccessible()) {
                    final IJavaProject newJavaProject = JavaCore.create((IProject) projectResource);
                    processEntries(cmpOptBuilder, wsRoot, newJavaProject.getRawClasspath(), newJavaProject,
                            contextResource, false);
                }
                break;

            case IClasspathEntry.CPE_VARIABLE:
                processEntries(cmpOptBuilder, wsRoot,
                        new IClasspathEntry[] { JavaCore.getResolvedClasspathEntry(pathEntry) }, javaProject,
                        contextResource, false);
                break;
            }
        }
    }

    private CompilerOptionsBuilder processResource(final IResource resource) throws AnalysisException {
        final IJavaProject javaProject = JavaCore.create(resource.getProject());
        if (javaProject.exists()) {
            final CompilerOptionsBuilder cmpOptBuilder = new CompilerOptionsBuilder();
            final IWorkspaceRoot wsRoot = javaProject.getProject().getWorkspace().getRoot();
            try {
                processEntries(cmpOptBuilder, wsRoot, javaProject.getRawClasspath(), javaProject, resource, false);
            } catch (CoreException except) {
                throw new AnalysisException(NLS.bind(Messages.XFG_ResourceAccessError, resource.getFullPath()),
                        except);
            }
            return cmpOptBuilder;
        } else {
            return null;
        }
    }

    private void processSourceFolder(final CompilerOptionsBuilder cmpOptBuilder, final IFolder srcFolder,
            final IResource contextResource) throws AnalysisException {
        final IResource curResource;
        if (contextResource.getType() == IResource.PROJECT) {
            curResource = srcFolder;
        } else {
            curResource = contextResource;
        }
        if ((curResource != null) && curResource.exists()) {
            try {
                curResource.accept(new IResourceVisitor() {

                    public boolean visit(final IResource resource) throws CoreException {
                        if (resource.getType() == IResource.FILE) {
                            final IFile file = (IFile) resource;
                            final IPath location = file.getLocation();
                            if (location != null) {
                                final File localFile = location.toFile();
                                if (localFile.exists() && X10_EXT.equals(file.getFileExtension())) {
                                    try {
                                        cmpOptBuilder.addSource(X10FactTypeNames.APPLICATION,
                                                new FileSource(new FileResource(localFile)));
                                    } catch (IOException except) {
                                        // It can't occur since we already have tested for existence.
                                        SearchCoreActivator.log(IStatus.ERROR, null, except);
                                    }
                                }
                            }
                            return false;
                        }
                        return true;
                    }

                });
            } catch (CoreException except) {
                throw new AnalysisException(NLS.bind(Messages.XFG_ResourceAccessError, curResource.getFullPath()),
                        except);
            }
        }
    }

    private void processLibrary(final CompilerOptionsBuilder cmpOptBuilder, final ZipFile zipFile, final File file,
            final IResource contextResource, final boolean isInRuntime) throws IOException {
        if (contextResource.getType() == IResource.PROJECT) {
            final Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
            while (zipEntries.hasMoreElements()) {
                final ZipEntry entry = zipEntries.nextElement();
                if (entry.getName().endsWith(".x10")) { //$NON-NLS-1$
                    cmpOptBuilder.addSource(isInRuntime ? X10FactTypeNames.RUNTIME : X10FactTypeNames.LIBRARY,
                            new FileSource(new ZipResource(file, zipFile, entry.getName())));
                }
            }
        }
    }

    private void update(final FactBase factBase, final Type type, final IFactContext context,
            final IResource resource, final CompilerOptionsBuilder cmpOptBuilder,
            final Set<Map.Entry<String, Collection<Source>>> entries) throws AnalysisException {
        for (final Map.Entry<String, Collection<Source>> entry : entries) {
            final IFactContext factContext = RUNTIME.equals(entry.getKey()) ? WorkspaceContext.getInstance()
                    : context;

            final ITypeManager typeManager = this.fSearchDBTypes.getTypeManager(type.getName(), entry.getKey());

            if (RUNTIME.equals(entry.getKey())) {
                typeManager.loadIndexingFile(factBase, factContext);

                final ISet value = (ISet) factBase.queryFact(new FactKey(typeManager.getType(), factContext));
                if ((value != null) && !value.isEmpty()) {
                    continue; // We build the type info for the runtime context only one time.
                }
            }
            typeManager.initWriter(factBase, factContext, resource);

            final NodeVisitor visitor = typeManager.createNodeVisitor(entry.getKey());
            try {
                for (final Job job : this.fIndexingCompiler.compile(cmpOptBuilder.getClassPath(),
                        cmpOptBuilder.getSourcePath(), entry.getValue())) {
                    if (job.ast() != null) {
                        job.ast().visit(visitor);
                    }
                }

                typeManager.writeDataInFactBase(factBase, factContext);

                if (RUNTIME.equals(entry.getKey()) && !hasIndexingFile(typeManager.getType().getName())) {
                    typeManager.createIndexingFile(factBase, factContext);
                }
            } catch (RuntimeException except) {
                SearchCoreActivator.log(IStatus.ERROR, Messages.XFG_IndexerCompilationLogError, except);
            } finally {
                typeManager.clearWriter();
            }
        }
    }

    private void update(final FactBase factBase, final Type type, final IFactContext factContext,
            final IResource resource, final IndexedDocumentDescriptor documentDescriptor) throws AnalysisException {
        final ITypeManager typeManager = this.fSearchDBTypes.getTypeManager(type.getName(), APPLICATION);

        typeManager.initWriter(factBase, factContext, resource);

        final NodeVisitor visitor = typeManager.createNodeVisitor(APPLICATION);
        try {
            ((Node) documentDescriptor.astRoot).visit(visitor);

            typeManager.writeDataInFactBase(factBase, factContext);
        } catch (RuntimeException except) {
            SearchCoreActivator.log(IStatus.ERROR, Messages.XFG_IndexerCompilationLogError, except);
        } finally {
            typeManager.clearWriter();
        }
    }

    // --- Private classes

    private static final class CompilerOptionsBuilder {

        // --- Internal services

        void addSource(final String scope, final Source source) {
            final Collection<Source> container = this.fSources.get(scope);
            if (container == null) {
                final Collection<Source> newContainer = new LinkedList<Source>();
                newContainer.add(source);
                this.fSources.put(scope, newContainer);
            } else {
                container.add(source);
            }
        }

        void addToClassPath(final String classPathEntry) {
            if (this.fClassPathBuilder.length() > 0) {
                this.fClassPathBuilder.append(File.pathSeparatorChar);
            }
            this.fClassPathBuilder.append(classPathEntry);
        }

        void addToSourcePath(final File srcEntry) {
            this.fSourcePath.add(srcEntry);
        }

        String getClassPath() {
            return this.fClassPathBuilder.toString();
        }

        Set<Map.Entry<String, Collection<Source>>> getSourceEntrySet() {
            return this.fSources.entrySet();
        }

        List<File> getSourcePath() {
            return this.fSourcePath;
        }

        // --- Overridden methods

        public String toString() {
            final StringBuilder sb = new StringBuilder();
            sb.append("Class path: ").append(this.fClassPathBuilder) //$NON-NLS-1$
                    .append("\nSource path: ").append(this.fSourcePath); //$NON-NLS-1$
            for (final Map.Entry<String, Collection<Source>> entry : this.fSources.entrySet()) {
                sb.append("\n-> ").append(entry.getKey()).append('\n').append(entry.getValue()); //$NON-NLS-1$
            }
            return sb.toString();
        }

        // --- Fields

        private final StringBuilder fClassPathBuilder = new StringBuilder();

        private final List<File> fSourcePath = new ArrayList<File>();

        private final Map<String, Collection<Source>> fSources = new HashMap<String, Collection<Source>>();

    }

    // --- Fields

    private final IndexingCompiler fIndexingCompiler;

    private final SearchDBTypes fSearchDBTypes;

    private static final String JAR_EXT = "jar"; //$NON-NLS-1$

    private static final String X10_EXT = "x10"; //$NON-NLS-1$

}