org.jboss.tools.seam.ui.search.SeamSearchEngine.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.tools.seam.ui.search.SeamSearchEngine.java

Source

/*******************************************************************************
 * Copyright (c) 2007 Red Hat, Inc.
 * Distributed under license by Red Hat, Inc. All rights reserved.
 * This program is 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
 *
 * Contributors:
 *     Red Hat, Inc. - initial API and implementation
 ******************************************************************************/

package org.jboss.tools.seam.ui.search;

import java.io.File;
import java.util.List;
import java.util.Set;
import java.util.zip.CRC32;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.search.core.text.TextSearchEngine;
import org.jboss.tools.common.el.core.model.ELInvocationExpression;
import org.jboss.tools.common.el.core.resolver.ElVarSearcher;
import org.jboss.tools.common.el.core.resolver.Var;
import org.jboss.tools.seam.core.ISeamContextVariable;
import org.jboss.tools.seam.core.ISeamProject;
import org.jboss.tools.seam.core.SeamCoreMessages;
import org.jboss.tools.seam.core.SeamCorePlugin;
import org.jboss.tools.seam.internal.core.el.SeamELCompletionEngine;
import org.jboss.tools.seam.ui.SeamGuiPlugin;

/**
 * A helper class used for search operations
 * 
 * @author Jeremy
 */
public abstract class SeamSearchEngine {
    private static SeamSearchEngine fInstance = null;
    private final IProgressMonitor fMonitor = new NullProgressMonitor();
    private SearchParticipant fParticipant = null;
    private IPath fSeamUIPluginLocation = null;
    private final CRC32 fChecksumCalculator = new CRC32();

    /**
     * Returns an instance. If the instance isn't initialized creates an instance 
     * of the search engine. 
     * @return the created {@link SeamSearchEngine}.
     */
    public static SeamSearchEngine getInstance() {
        if (fInstance == null) {
            fInstance = createDefault();
        }
        return fInstance;
    }

    /**
     * Creates the default, built-in, text search engine that implements a brute-force search, not using
     * any search index.
     * Note that clients should always use the search engine provided by {@link #create()}.
     * @return an instance of the default text search engine {@link TextSearchEngine}.
     */
    private static SeamSearchEngine createDefault() {
        return new SeamSearchEngine() {

            @Override
            public IStatus search(SeamSearchScope javaScope, SeamSearchRequestor requestor, IFile sourceFile,
                    ELInvocationExpression tokens, IProgressMonitor monitor) {

                if (tokens == null /*|| tokens.size() == 0*/) {
                    return Status.OK_STATUS;
                }

                IProject project = (sourceFile == null ? null : sourceFile.getProject());

                ISeamProject seamProject = SeamCorePlugin.getSeamProject(project, true);
                if (seamProject == null)
                    return Status.OK_STATUS;

                SeamELCompletionEngine engine = new SeamELCompletionEngine();

                //Find Seam variable names
                // - if the tokens are the variable name only - search for variable declaration in Seam project
                String variableName = tokens.getText(); //SeamSearchVisitor.tokensToString(tokens);

                Set<ISeamContextVariable> variables = seamProject.getVariablesByName(variableName);
                if (variables != null && !variables.isEmpty()) {
                    return search(javaScope, requestor, sourceFile, variables.toArray(new ISeamContextVariable[0]),
                            monitor);
                }

                // - else try to find Java Elements and declarations/references for them
                List<IJavaElement> elements = null;
                try {
                    elements = engine.getJavaElementsForELOperandTokens(seamProject, sourceFile, tokens);
                } catch (StringIndexOutOfBoundsException e) {
                    SeamGuiPlugin.getPluginLog().logError(e);
                    return Status.OK_STATUS;
                } catch (BadLocationException e) {
                    SeamGuiPlugin.getPluginLog().logError(e);
                    return Status.OK_STATUS;
                }

                if (elements != null && !elements.isEmpty()) {
                    return search(javaScope, requestor, sourceFile, elements.toArray(new IJavaElement[0]), monitor);
                }

                // Try to find a local Var (a pair of variable-value attributes)
                ElVarSearcher varSearcher = new ElVarSearcher(sourceFile, engine);
                // Find a Var in the EL 
                int start = tokens.getStartPosition();
                int end = tokens.getEndPosition();

                StringBuffer elText = new StringBuffer();
                elText.append(tokens.toString());

                if (elText == null || elText.length() == 0)
                    return Status.OK_STATUS;

                List<Var> allVars = varSearcher.findAllVars(sourceFile, tokens.getStartPosition());
                Var var = varSearcher.findVarForEl(elText.toString(), null, allVars, true);
                if (var == null) {
                    // Find a Var in the current offset assuming that it's a node with var/value attribute pair
                    var = varSearcher.findVar(sourceFile, tokens.getStartPosition());
                }
                if (var == null)
                    return Status.OK_STATUS;

                if (tokens.getLeft() == null) {
                    // The only Var is selected to search for
                    if (isSearchForDeclarations(javaScope.getLimitTo())) {

                        boolean res = SeamSearchVisitor.acceptPaternMatch(requestor, sourceFile,
                                var.getDeclarationOffset(), var.getDeclarationLength());
                        if (!res) {
                            return Status.OK_STATUS; // no further reporting requested
                        }
                    } else {
                        return search(javaScope, requestor, sourceFile, new Var[] { var }, monitor);
                    }

                    return Status.OK_STATUS;
                }

                // Need to extract the var value and search for the real elements

                return Status.OK_STATUS;
            }

            @Override
            public IStatus search(SeamSearchScope scope, SeamSearchRequestor requestor, IFile sourceFile,
                    IJavaElement[] elements, IProgressMonitor monitor) {
                IProject project = (sourceFile == null ? null : sourceFile.getProject());
                return new SeamSearchVisitor(requestor, elements, project).search(scope, monitor);
            }

            @Override
            public IStatus search(SeamSearchScope scope, SeamSearchRequestor requestor, IFile sourceFile,
                    Var[] vars, IProgressMonitor monitor) {
                IProject project = (sourceFile == null ? null : sourceFile.getProject());
                return new SeamSearchVisitor(requestor, vars, sourceFile).search(scope, monitor);
            }

            @Override
            public IStatus search(String searchText, SeamSearchScope scope, int searchFor, int limitTo,
                    int matchMode, boolean isCaseSensitive, SearchRequestor requestor) {

                SeamJavaSearchJob job = new SeamJavaSearchJob(searchText, scope, searchFor, limitTo, matchMode,
                        isCaseSensitive, requestor);
                setCanceled(false);
                job.setUser(true);
                job.schedule();
                return Status.OK_STATUS;
            }

            @Override
            public IStatus search(SeamSearchScope scope, SeamSearchRequestor requestor, IFile sourceFile,
                    ISeamContextVariable[] variables, IProgressMonitor monitor) {
                IProject project = (sourceFile == null ? null : sourceFile.getProject());
                return new SeamSearchVisitor(requestor, variables, project).search(scope, monitor);
            }
        };
    }

    /**
     * Uses a given tokens to find matches in the content of 
     * workspace file resources. If a file is open in an editor, the
     * editor buffer is searched.
     * 
     * @param scope
     * @param requestor
     * @param sourceFile
     * @param tokens
     * @param monitor
     * @return the status containing information about problems in resources searched.
     */
    public abstract IStatus search(SeamSearchScope scope, SeamSearchRequestor requestor, IFile sourceFile,
            ELInvocationExpression tokens, IProgressMonitor monitor);

    /**
     * Uses a given IJavaElement-s to find matches in the content of 
     * workspace file resources. If a file is open in an editor, the
     * editor buffer is searched.
      * 
     * @param scope
     * @param requestor
     * @param sourceFile
     * @param elements
     * @param monitor
     * @return
     */
    public abstract IStatus search(SeamSearchScope scope, SeamSearchRequestor requestor, IFile sourceFile,
            IJavaElement[] elements, IProgressMonitor monitor);

    /**
     * Uses a given {@link ISeamContextVariable} objects to find matches in the content of 
     * workspace file resources. If a file is open in an editor, the
     * editor buffer is searched.
     * 
     * @param scope
     * @param requestor
     * @param sourceFile
     * @param variables
     * @param monitor
     * @return
     */
    public abstract IStatus search(SeamSearchScope scope, SeamSearchRequestor requestor, IFile sourceFile,
            ISeamContextVariable[] variables, IProgressMonitor monitor);

    /**
     * Uses a given {@link Var} objects to find matches in the content of 
     * workspace file resources. If a file is open in an editor, the
     * editor buffer is searched.
     * 
     * @param scope
     * @param requestor
     * @param sourceFile
     * @param vars
     * @param monitor
     * @return
     */
    public abstract IStatus search(SeamSearchScope scope, SeamSearchRequestor requestor, IFile sourceFile,
            Var[] vars, IProgressMonitor monitor);

    /**
     * Perform a java search w/ the given parameters. Runs in a background Job
     * (results may still come in after this method call)
     * 
     * @param searchText
     *            the string of text to search on
     * @param searchFor
     *            IJavaSearchConstants.TYPE, METHOD, FIELD, PACKAGE, etc...
     * @param limitTo
     *            IJavaSearchConstants.DECLARATIONS,
     *            IJavaSearchConstants.REFERENCES,
     *            IJavaSearchConstants.IMPLEMENTORS, or
     *            IJavaSearchConstants.ALL_OCCURRENCES
     * @param matchMode
     *            allow * wildcards or not
     * @param isCaseSensitive
     * @param requestor
     *            passed in to accept search matches (and do "something" with
     *            them)
     */
    public abstract IStatus search(String searchText, SeamSearchScope scope, int searchFor, int limitTo,
            int matchMode, boolean isCaseSensitive, SearchRequestor requestor);

    /**
     * Seam Indexing and Search jobs check this
     * 
     * @return
     */
    public synchronized final void setCanceled(boolean cancel) {
        fMonitor.setCanceled(cancel);
    }

    /**
     * Seam Indexing and Search jobs check this
     * 
     * @return
     */
    public synchronized final boolean isCanceled() {
        return fMonitor.isCanceled();
    }

    // This is called from SeamPathIndexer
    public final IPath computeIndexLocation(IPath containerPath) {

        IPath indexLocation = null;
        String pathString = containerPath.toOSString();
        this.fChecksumCalculator.reset();
        this.fChecksumCalculator.update(pathString.getBytes());
        String fileName = Long.toString(this.fChecksumCalculator.getValue()) + ".index"; //$NON-NLS-1$
        indexLocation = getSeamUIPluginWorkingLocation().append(fileName);
        JavaModelManager.getJavaModelManager().getIndexManager().indexLocations.put(containerPath, indexLocation);
        return indexLocation;
    }

    // copied from JDT IndexManager
    public IPath getSeamUIPluginWorkingLocation() {

        if (this.fSeamUIPluginLocation != null)
            return this.fSeamUIPluginLocation;

        // Append the folder name "seamsearch" to keep the state location area cleaner
        IPath stateLocation = SeamGuiPlugin.getDefault().getStateLocation().append("seamsearch");

        String device = stateLocation.getDevice();
        if (device != null && device.charAt(0) == '/')
            stateLocation = stateLocation.setDevice(device.substring(1));

        // ensure that it exists on disk
        File folder = new File(stateLocation.toOSString());
        if (!folder.isDirectory()) {
            try {
                folder.mkdir();
            } catch (SecurityException e) {
            }
        }

        return this.fSeamUIPluginLocation = stateLocation;
    }

    /**
     * This operation ensures that the live resource's search markers show up in
     * the open editor. It also allows the ability to pass in a ProgressMonitor
     */
    private class SeamJavaSearchJob extends Job implements IJavaSearchConstants {

        String fSearchText = ""; //$NON-NLS-1$

        IJavaSearchScope fScope = null;

        int fSearchFor = FIELD;

        int fLimitTo = ALL_OCCURRENCES;

        int fMatchMode = SearchPattern.R_PATTERN_MATCH;

        boolean fIsCaseSensitive = false;

        SearchRequestor fRequestor = null;

        IJavaElement fElement = null;

        // constructor w/ java element
        public SeamJavaSearchJob(IJavaElement element, IJavaSearchScope scope, SearchRequestor requestor) {
            super(SeamCoreMessages.SeamSearch + element.getElementName());
            this.fElement = element;
            this.fScope = scope;
            this.fRequestor = requestor;
        }

        // constructor w/ search text
        public SeamJavaSearchJob(String searchText, IJavaSearchScope scope, int searchFor, int limitTo,
                int matchMode, boolean isCaseSensitive, SearchRequestor requestor) {
            super(SeamCoreMessages.SeamSearch + searchText);
            this.fSearchText = searchText;
            this.fScope = scope;
            this.fSearchFor = searchFor;
            this.fLimitTo = limitTo;
            this.fMatchMode = matchMode;
            this.fIsCaseSensitive = isCaseSensitive;
            this.fRequestor = requestor;
        }

        public IStatus run(IProgressMonitor jobMonitor) {

            if (jobMonitor != null && jobMonitor.isCanceled())
                return Status.CANCEL_STATUS;
            if (SeamSearchEngine.getInstance().isCanceled())
                return Status.CANCEL_STATUS;

            SearchPattern javaSearchPattern = null;
            // if an element is available, use that to create search pattern
            // (eg. LocalVariable)
            // otherwise use the text and other paramters
            boolean searchForDeclarations = isSearchForDeclarations(this.fLimitTo);
            boolean searchForReferences = isSearchForDeclarations(this.fLimitTo);

            if (this.fElement != null) {
                javaSearchPattern = SearchPattern.createPattern(this.fElement, this.fLimitTo);
            } else {
                javaSearchPattern = SearchPattern.createPattern(this.fSearchText, this.fSearchFor, this.fLimitTo,
                        this.fMatchMode);
            }

            // if is searching for the declarations:
            // if (fElement != null): 
            // - No components can be found for the element (the declaration for the element itself will be found by java search)
            // - No properties/methods can be found for the Variable/Method (the declaration for the element itself will be found by java search)
            // if (fSearchText != null):
            // try to find the Seam Variable or the Seam variable's Method/Property and search for its declaration.

            if (isSearchForDeclarations(this.fLimitTo)) {
                if (this.fElement != null) {
                    javaSearchPattern = SearchPattern.createPattern(this.fElement, this.fLimitTo);
                } else {
                    javaSearchPattern = SearchPattern.createPattern(this.fSearchText, this.fSearchFor,
                            this.fLimitTo, this.fMatchMode);
                }
            }
            // if is searching for the references:
            // if (fElement != null): 
            // ? Search for references to the components which are declared by this element's class
            // - Search for properties/methods can be found for the Variable/Method
            // if (fSearchText != null):
            // try to find the Seam Variable or the Seam variable's Method/Property and search for its declaration.
            if (isSearchForReferences(this.fLimitTo)) {
                if (this.fElement != null) {
                    javaSearchPattern = SearchPattern.createPattern(this.fElement, this.fLimitTo);

                } else {
                    javaSearchPattern = SearchPattern.createPattern(this.fSearchText, this.fSearchFor,
                            this.fLimitTo, this.fMatchMode);
                }
            }

            if (javaSearchPattern != null) {

            }
            return Status.OK_STATUS;
        }

    }

    /**
     * Checks if the given limitTo flag is limited to declarations
     * 
     * @param limitTo
     * @return
     */
    public static boolean isSearchForDeclarations(int limitTo) {
        int maskedLimitTo = limitTo
                & ~(IJavaSearchConstants.IGNORE_DECLARING_TYPE + IJavaSearchConstants.IGNORE_RETURN_TYPE);
        if (maskedLimitTo == IJavaSearchConstants.DECLARATIONS
                || maskedLimitTo == IJavaSearchConstants.ALL_OCCURRENCES) {
            return true;
        }

        return false;
    }

    /**
     * Checks if the given limitTo flag is limited to references
     * 
     * @param limitTo
     * @return
     */
    public static boolean isSearchForReferences(int limitTo) {
        int maskedLimitTo = limitTo
                & ~(IJavaSearchConstants.IGNORE_DECLARING_TYPE + IJavaSearchConstants.IGNORE_RETURN_TYPE);
        if (maskedLimitTo == IJavaSearchConstants.REFERENCES
                || maskedLimitTo == IJavaSearchConstants.ALL_OCCURRENCES) {
            return true;
        }

        return false;
    }

    /**
     * Checks if the given element is IField
     * 
     * @param element
     * @return
     */
    public static boolean isField(IJavaElement element) {
        if (element == null)
            return false;

        return (element.getElementType() == IJavaElement.FIELD);
    }

    /**
     * Checks if the given element is IMethod
     * 
     * @param element
     * @return
     */
    public static boolean isMethod(IJavaElement element) {
        if (element == null)
            return false;

        return (element.getElementType() == IJavaElement.METHOD);
    }

    /**
     * Checks if the given element is IType
     * 
     * @param element
     * @return
     */
    public static boolean isType(IJavaElement element) {
        if (element == null)
            return false;

        return (element.getElementType() == IJavaElement.TYPE);
    }
}