/******************************************************************************* * 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.IOException; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.filebuffers.FileBuffers; import org.eclipse.core.filebuffers.ITextFileBuffer; import org.eclipse.core.filebuffers.ITextFileBufferManager; import org.eclipse.core.filebuffers.LocationKind; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceProxy; import org.eclipse.core.resources.IResourceProxyVisitor; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.content.IContentDescription; import org.eclipse.core.runtime.content.IContentType; import org.eclipse.core.runtime.content.IContentTypeManager; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.search.IJavaSearchConstants; import org.eclipse.jdt.core.search.IJavaSearchScope; import org.eclipse.jdt.internal.ui.search.JavaSearchQuery; import org.eclipse.jdt.internal.ui.search.JavaSearchResult; import org.eclipse.jdt.internal.ui.search.JavaSearchScopeFactory; import org.eclipse.jdt.internal.ui.text.FastJavaPartitionScanner; import org.eclipse.jdt.ui.search.ElementQuerySpecification; import org.eclipse.jdt.ui.text.IJavaPartitions; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.rules.IToken; import org.eclipse.jface.text.rules.Token; import org.eclipse.search.core.text.TextSearchScope; import org.eclipse.search.internal.core.text.DocumentCharSequence; import org.eclipse.search.internal.core.text.FileCharSequenceProvider; import org.eclipse.search.internal.core.text.TextSearchVisitor; import org.eclipse.search.internal.core.text.TextSearchVisitor.ReusableMatchAccess; import org.eclipse.search.internal.ui.Messages; import org.eclipse.search.internal.ui.SearchMessages; import org.eclipse.search.internal.ui.SearchPlugin; import org.eclipse.search.ui.NewSearchUI; import org.eclipse.search.ui.text.Match; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.wst.sse.core.StructuredModelManager; import org.eclipse.wst.sse.core.internal.provisional.IModelManager; import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion; import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion; import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode; import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext; import org.jboss.tools.common.el.core.model.ELExpression; import org.jboss.tools.common.el.core.model.ELInstance; import org.jboss.tools.common.el.core.model.ELInvocationExpression; import org.jboss.tools.common.el.core.model.ELModel; import org.jboss.tools.common.el.core.parser.ELParser; import org.jboss.tools.common.el.core.parser.ELParserUtil; import org.jboss.tools.common.el.core.resolver.ElVarSearcher; import org.jboss.tools.common.el.core.resolver.Var; import org.jboss.tools.common.java.IJavaSourceReference; import org.jboss.tools.common.model.util.EclipseJavaUtil; import org.jboss.tools.common.text.ITextSourceReference; import org.jboss.tools.seam.core.BijectedAttributeType; import org.jboss.tools.seam.core.IBijectedAttribute; import org.jboss.tools.seam.core.IOpenableElement; import org.jboss.tools.seam.core.IRole; import org.jboss.tools.seam.core.ISeamComponentDeclaration; import org.jboss.tools.seam.core.ISeamContextShortVariable; import org.jboss.tools.seam.core.ISeamContextVariable; import org.jboss.tools.seam.core.ISeamDeclaration; 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.core.SeamCoreMessages; import org.jboss.tools.seam.internal.core.AbstractSeamDeclaration; import org.jboss.tools.seam.internal.core.SeamComponent; import org.jboss.tools.seam.internal.core.el.SeamELCompletionEngine; import org.jboss.tools.seam.internal.core.scanner.ScannerException; import org.jboss.tools.seam.internal.core.scanner.java.AnnotatedASTNode; import org.jboss.tools.seam.internal.core.scanner.java.ResolvedAnnotation; import org.jboss.tools.seam.internal.core.scanner.java.SeamAnnotations; import org.jboss.tools.seam.ui.SeamGuiPlugin; import org.jboss.tools.seam.ui.text.java.scanner.JavaAnnotationScanner; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * Seam Search Visitor - performs searching on the Seam Projects and their files * * @author Jeremy * */ public class SeamSearchVisitor { private final SeamVariableMatcher[] fVariableMatchers; private final JavaElementMatcher[] fJavaMatchers; private final VarMatcher[] fVarMatchers; private final SeamSearchRequestor fCollector; private final MultiStatus fStatus; private IProgressMonitor fProgressMonitor; private int fNumberOfScannedFiles; private int fNumberOfFilesToScan; private IResource fSearchRoot; private ISeamProject fCurrentSeamProject; private Map fDocumentsInEditors; private final TextSearchVisitor.ReusableMatchAccess fMatchAccess; private IFile fCurrentFile; private final FileCharSequenceProvider fFileCharSequenceProvider; interface ISeamMatcher { String getName(); boolean match(Object obj); Object getElement(); } class VarMatcher implements ISeamMatcher { Var fVar; IFile fFile; VarMatcher(Var var, IFile file) { this.fVar = var; this.fFile = file; } public IFile getFile() { return fFile; } public String getName() { String name = fVar == null ? null : fVar.getName(); return name == null ? "<null>" : name; } public boolean match(Object compare) { if (fVar == null) return false; return fVar.equals(compare); } public Var getElement() { return fVar; } } class SeamVariableMatcher implements ISeamMatcher { ISeamContextVariable fVariable; IProject fProject; SeamVariableMatcher(ISeamContextVariable variable, IProject project) { this.fVariable = variable; this.fProject = project; } public String getName() { String name = fVariable == null ? null : fVariable.getName(); return name == null ? "<null>" : name; } public boolean match(Object compare) { if (fVariable == null) return false; if (fVariable.equals(compare)) return true; return fVariable.equals(compare); } public ISeamContextVariable getElement() { return fVariable; } } class JavaElementMatcher implements ISeamMatcher { IJavaElement fElement; IProject fProject; JavaElementMatcher(IJavaElement javaElement, IProject project) { this.fElement = javaElement; this.fProject = project; } public String getName () { return fElement.getElementName(); } public IJavaElement getElement() { return fElement; } public boolean match(Object object) { if (!(object instanceof IJavaElement)) return false; IJavaElement compare = (IJavaElement)object; if (fElement.equals(compare)) return true; if (fElement.getElementType() != compare.getElementType()) return false; switch(fElement.getElementType()) { case IJavaElement.FIELD: return matchField((IField)compare); case IJavaElement.METHOD: return matchMethod((IMethod)compare); case IJavaElement.TYPE: return matchType((IType)compare); default: System.out.println("match: UnsupportedType:\n" + fElement.getElementName() + " ==>> " + fElement.getElementType()); } return false; } boolean matchType (IType compare) { return internalMatchType((IType)fElement, compare); } private boolean internalMatchType (IType type, IType compare) { return EclipseJavaUtil.isDerivedClass( type.getFullyQualifiedName(), compare.getFullyQualifiedName(), fProject); } boolean matchField (IField compare) { IField field = (IField)fElement; if (!field.getElementName().equals(compare.getElementName())) return false; if (!internalMatchType(field.getDeclaringType(), compare.getDeclaringType())) return false; try { return field.getTypeSignature().equals(compare.getTypeSignature()); } catch (JavaModelException e) { // e.printStackTrace(); SeamGuiPlugin.getPluginLog().logError(e); return false; } } boolean matchMethod (IMethod compare) { IMethod method = (IMethod)fElement; if (!method.getElementName().equals(compare.getElementName())) return false; if (!internalMatchType(method.getDeclaringType(), compare.getDeclaringType())) return false; try { return method.getSignature().equals(compare.getSignature()); } catch (JavaModelException e) { // e.printStackTrace(); SeamGuiPlugin.getPluginLog().logError(e); return false; } } } /** * Constructs SeamSearchVisitor for a given {@link Var} set * using a given {@link SeamSearchRequestor} * * @param collector * @param vars * @param file */ public SeamSearchVisitor(SeamSearchRequestor collector, Var[] vars, IFile file) { fCollector= collector; fStatus= new MultiStatus(NewSearchUI.PLUGIN_ID, IStatus.OK, SearchMessages.TextSearchEngine_statusMessage, null); fSearchRoot = file; fJavaMatchers = null; fVariableMatchers = null; fVarMatchers = new VarMatcher[vars == null ? 0 : vars.length]; for (int i = 0; vars != null && i < vars.length; i++) { fVarMatchers[i]= vars[i] == null ? null : new VarMatcher(vars[i], file); } fFileCharSequenceProvider= new FileCharSequenceProvider(); fMatchAccess= new ReusableMatchAccess(); } /** * Constructs SeamSearchVisitor for a given {@link IJavaElement} set * using a given {@link SeamSearchRequestor} * * @param collector * @param elements * @param project */ public SeamSearchVisitor(SeamSearchRequestor collector, IJavaElement[] elements, IProject project) { fCollector= collector; fStatus= new MultiStatus(NewSearchUI.PLUGIN_ID, IStatus.OK, SearchMessages.TextSearchEngine_statusMessage, null); fSearchRoot = project; fVarMatchers = null; fVariableMatchers = null; fJavaMatchers = new JavaElementMatcher[elements == null ? 0 : elements.length]; for (int i = 0; elements != null && i < elements.length; i++) { fJavaMatchers[i]= elements[i] == null ? null : new JavaElementMatcher(elements[i], project); } fFileCharSequenceProvider= new FileCharSequenceProvider(); fMatchAccess= new ReusableMatchAccess(); } /** * Constructs SeamSearchVisitor for a given {@link ISeamContextVariable} set * using a given {@link SeamSearchRequestor} * @param collector * @param variables * @param project */ public SeamSearchVisitor(SeamSearchRequestor collector, ISeamContextVariable[] variables, IProject project) { fCollector= collector; fStatus= new MultiStatus(NewSearchUI.PLUGIN_ID, IStatus.OK, SearchMessages.TextSearchEngine_statusMessage, null); fSearchRoot = project; fVarMatchers = null; fJavaMatchers = null; fVariableMatchers = new SeamVariableMatcher[variables == null ? 0 : variables.length]; for (int i = 0; variables!= null && i < variables.length; i++) { fVariableMatchers[i]= variables[i] == null ? null : new SeamVariableMatcher(variables[i], project); } fFileCharSequenceProvider= new FileCharSequenceProvider(); fMatchAccess= new ReusableMatchAccess(); } private SeamSearchScope fCurrentScope = null; /** * Performs search operation using a given scope * * @param scope * @param monitor * @return */ public IStatus search(TextSearchScope scope, IProgressMonitor monitor) { try { if (scope instanceof SeamSearchScope) { fCurrentScope = (SeamSearchScope)scope; if (SeamSearchEngine.isSearchForDeclarations(((SeamSearchScope)scope).getLimitTo())) { return searchForDeclarations(((SeamSearchScope)scope).evaluateSeamProjectsInScope(fStatus), monitor); } else { return searchForReferences(((SeamSearchScope)scope).evaluateSeamProjectsInScope(fStatus), monitor); } } } finally { fCurrentScope = null; } return Status.OK_STATUS; } private int calculateFiles() { if ((fJavaMatchers != null && fJavaMatchers.length > 0) || (fVariableMatchers != null && fVariableMatchers.length > 0)) { IFile[] files = fCurrentScope.evaluateFilesInScope(fStatus); return (files == null ? 0 : files.length); } else if (fVarMatchers != null && fVarMatchers.length > 0) { List<IFile> fileList = new ArrayList<IFile>(fVarMatchers.length); for (int i = 0; i < fVarMatchers.length; i++) { if (fVarMatchers[i] != null && fVarMatchers[i].getFile() != null) fileList.add(fVarMatchers[i].getFile()); } return fileList.size(); } return 0; } public IStatus searchForDeclarations(ISeamProject[] projects, IProgressMonitor monitor) { fProgressMonitor= monitor == null ? new NullProgressMonitor() : monitor; fNumberOfScannedFiles= 0; fNumberOfFilesToScan= calculateFiles(); fCurrentSeamProject= null; Job monitorUpdateJob= new MonitorUpdateJob(); try { fProgressMonitor.beginTask(getTaskName(), fNumberOfFilesToScan); monitorUpdateJob.setSystem(true); monitorUpdateJob.schedule(); try { fCollector.beginReporting(); processSeamProjects(projects, true); return fStatus; } catch (Throwable x) { // x.printStackTrace(); SeamGuiPlugin.getPluginLog().logError(x); return fStatus; } finally { monitorUpdateJob.cancel(); } } finally { fProgressMonitor.done(); fCollector.endReporting(); } } private void processSeamProjects(ISeamProject[] projects, boolean searchDeclarations) { for (int i= 0; i < projects.length; i++) { fCurrentSeamProject= projects[i]; boolean res= searchDeclarations ? processSeamDeclarationsInProject(fCurrentSeamProject) : processSeamReferencesInProject(fCurrentSeamProject); if (!res) break; } } private ElVarSearcher fELVarSearcher; private boolean processSeamReferencesInProject(ISeamProject project) { IFile[] files = null; if (fCurrentScope != null) { if ((fJavaMatchers != null && fJavaMatchers.length > 0) || (fVariableMatchers != null && fVariableMatchers.length > 0)) { files = evaluateProjectFilesInScope(project.getProject(), fStatus); } else if (fVarMatchers != null && fVarMatchers.length > 0) { List<IFile> fileList = new ArrayList<IFile>(fVarMatchers.length); for (int i = 0; i < fVarMatchers.length; i++) { if (fVarMatchers[i] != null && fVarMatchers[i].getFile() != null) fileList.add(fVarMatchers[i].getFile()); } if (!fileList.isEmpty()) { files = fileList.toArray(new IFile[0]); } } } SeamELCompletionEngine fCompletionEngine = new SeamELCompletionEngine(); fELVarSearcher = new ElVarSearcher(fCompletionEngine); fDocumentsInEditors= evalNonFileBufferDocuments(); boolean res= true; for (int i = 0; files != null && i < files.length; i++) { res= processSeamReferencesInFile(files[i]); if (!res) break; } fDocumentsInEditors= null; fELVarSearcher = null; return res; } private boolean processSeamReferencesInFile(IFile file) { try { if (!fCollector.acceptFile(file) || // fMatchers == null || (fJavaMatchers == null && fVarMatchers == null && fVariableMatchers == null)) { return true; } IDocument document= getOpenDocument(file); if (document != null) { DocumentCharSequence documentCharSequence= new DocumentCharSequence(document); // assume all documents are non-binary locateMatches(file, documentCharSequence); } else { CharSequence seq= null; try { seq= fFileCharSequenceProvider.newCharSequence(file); if (hasBinaryContent(seq, file) && !fCollector.reportBinaryFile(file)) { return true; } locateMatches(file, seq); } catch (FileCharSequenceProvider.FileCharSequenceException e) { e.throwWrappedException(); } finally { if (seq != null) { try { fFileCharSequenceProvider.releaseCharSequence(seq); } catch (IOException e) { SearchPlugin.log(e); } } } } } catch (UnsupportedCharsetException e) { String[] args= { getCharSetName(file), file.getFullPath().makeRelative().toString()}; String message= Messages.format(SearchMessages.TextSearchVisitor_unsupportedcharset, args); fStatus.add(new Status(IStatus.WARNING, NewSearchUI.PLUGIN_ID, IStatus.WARNING, message, e)); } catch (IllegalCharsetNameException e) { String[] args= { getCharSetName(file), file.getFullPath().makeRelative().toString()}; String message= Messages.format(SearchMessages.TextSearchVisitor_illegalcharset, args); fStatus.add(new Status(IStatus.WARNING, NewSearchUI.PLUGIN_ID, IStatus.WARNING, message, e)); } catch (IOException e) { String[] args= { getExceptionMessage(e), file.getFullPath().makeRelative().toString()}; String message= Messages.format(SearchMessages.TextSearchVisitor_error, args); fStatus.add(new Status(IStatus.WARNING, NewSearchUI.PLUGIN_ID, IStatus.WARNING, message, e)); } catch (CoreException e) { String[] args= { getExceptionMessage(e), file.getFullPath().makeRelative().toString()}; String message= Messages.format(SearchMessages.TextSearchVisitor_error, args); fStatus.add(new Status(IStatus.WARNING, NewSearchUI.PLUGIN_ID, IStatus.WARNING, message, e)); } catch (StackOverflowError e) { String message= SearchMessages.TextSearchVisitor_patterntoocomplex0; fStatus.add(new Status(IStatus.ERROR, NewSearchUI.PLUGIN_ID, IStatus.ERROR, message, e)); return false; } finally { fNumberOfScannedFiles++; } if (fProgressMonitor.isCanceled()) throw new OperationCanceledException(SearchMessages.TextSearchVisitor_canceled); return true; } private void locateMatches(IFile file, CharSequence searchInput) throws CoreException { fELVarSearcher.setFile(file); if("java".equalsIgnoreCase(file.getFileExtension())) { //$NON-NLS-1$ locateMatchesInJava(file, searchInput); } else { locateMatchesInDom(file, searchInput); } } private List<Var> fVarListForCurentValidatedNode = new ArrayList<Var>(); private void locateMatchesInDom(IFile file, CharSequence content) { fVarListForCurentValidatedNode.clear(); IModelManager manager = StructuredModelManager.getModelManager(); if(manager == null) { // this can happen if plugin org.eclipse.wst.sse.core // is stopping or uninstalled, that is Eclipse is shutting down. // there is no need to report it, just stop validation. return; } IStructuredModel model = null; try { model = manager.getModelForRead(file); if (model instanceof IDOMModel) { IDOMModel domModel = (IDOMModel) model; IDOMDocument document = domModel.getDocument(); locateMatchesInChildNodes(file, document, content); } } catch (CoreException e) { SeamCorePlugin.getDefault().logError(SeamCoreMessages.SEAM_EL_VALIDATOR_ERROR_VALIDATING_SEAM_EL, e); } catch (IOException e) { SeamCorePlugin.getDefault().logError(SeamCoreMessages.SEAM_EL_VALIDATOR_ERROR_VALIDATING_SEAM_EL, e); } finally { if (model != null) { model.releaseFromRead(); } } return; } private void locateMatchesInChildNodes(IFile file, Node parent, CharSequence content) throws CoreException { Var var = fELVarSearcher.findVar(parent); if(var!=null) { fVarListForCurentValidatedNode.add(var); } NodeList children = parent.getChildNodes(); for(int i=0; i<children.getLength(); i++) { Node curentValidatedNode = children.item(i); if(Node.ELEMENT_NODE == curentValidatedNode.getNodeType()) { locateMatchesInNodeContent(file, ((IDOMNode)curentValidatedNode).getFirstStructuredDocumentRegion(), DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE, content); } else if(Node.TEXT_NODE == curentValidatedNode.getNodeType()) { locateMatchesInNodeContent(file, ((IDOMNode)curentValidatedNode).getFirstStructuredDocumentRegion(), DOMRegionContext.XML_CONTENT, content); } locateMatchesInChildNodes(file, curentValidatedNode, content); } if(var!=null) { fVarListForCurentValidatedNode.remove(var); } } private void locateMatchesInNodeContent(IFile file, IStructuredDocumentRegion node, String regionType, CharSequence content) throws CoreException { ITextRegionList regions = node.getRegions(); for(int i=0; i<regions.size(); i++) { ITextRegion region = regions.get(i); if(region.getType() == regionType) { String text = node.getFullText(region); if(text.indexOf("{")>-1) { //$NON-NLS-1$ int offset = node.getStartOffset() + region.getStart(); locateMatchesInString(file, text, offset, content); } } } } private void locateMatchesInJava(IFile file, CharSequence content) throws CoreException { try { FastJavaPartitionScanner scaner = new FastJavaPartitionScanner(); Document document = new Document(content.subSequence(0, content.length()).toString()); scaner.setRange(document, 0, document.getLength()); IToken token = scaner.nextToken(); while(token!=null && token!=Token.EOF) { if(IJavaPartitions.JAVA_STRING.equals(token.getData())) { int length = scaner.getTokenLength(); int offset = scaner.getTokenOffset(); String value = document.get(offset, length); if(value.indexOf('{')>-1) { locateMatchesInString(file, value, offset, content); } } token = scaner.nextToken(); } // Search in annotations ICompilationUnit compilationUnit = JavaCore.createCompilationUnitFrom(file); if (compilationUnit == null) return; JavaAnnotationScanner annotationScanner = new JavaAnnotationScanner(); Map<ResolvedAnnotation, AnnotatedASTNode<ASTNode>> loadedAnnotations = null; try { annotationScanner.parse((ICompilationUnit)compilationUnit); loadedAnnotations = annotationScanner.getResolvedAnnotations(); } catch (ScannerException e) { SeamGuiPlugin.getPluginLog().logError(e); return; } for (ResolvedAnnotation annotation : loadedAnnotations.keySet()) { if (annotationScanner.isAnnotationOfType(annotation, SeamAnnotations.IN_ANNOTATION_TYPE) || annotationScanner.isAnnotationOfType(annotation, SeamAnnotations.OUT_ANNOTATION_TYPE)) { String value = annotationScanner.getAnnotationValue(annotation); if (value == null || value.length() == 0) continue; IRegion valueRegion = annotationScanner.getAnnotationValueRegion(annotation); if (valueRegion == null) continue; int length = valueRegion.getLength(); int offset = valueRegion.getOffset(); if(value != null && value.indexOf("#{") >= 0) { locateMatchesInString(file, value, offset, content); } else { String string = "#{" + value + "}"; locateMatchesInString(file, string, offset - 2, content); } } } } catch (BadLocationException e) { SeamGuiPlugin.getDefault().logError(e); } } /** * @param offset - offset of string in file * @param length - length of string in file */ private void locateMatchesInString(IFile file, String string, int offset, CharSequence content) throws CoreException { int startEl = string.indexOf("#{"); //$NON-NLS-1$ if(startEl>-1) { ELParser parser = ELParserUtil.getJbossFactory().createParser(); ELModel model = parser.parse(string); List<ELInstance> is = model.getInstances(); for (ELInstance i: is) { if(i.getExpression() != null) { locateMatchesInEL(file, i.getExpression(), content, offset); } } } } private void locateMatchesInEL(IFile file, ELExpression el, CharSequence content, int offset) throws CoreException { List<ELInvocationExpression> invocations = el.getInvocations(); for (ELInvocationExpression token : invocations) { // validateElOperand(file, token, el.getStart()); String operand = token.getText(); String varName = operand; int offsetOfToken = offset + token.getFirstToken().getStart(); if (fJavaMatchers != null) { ELInvocationExpression expr = token; while(expr != null) { List<IJavaElement> elements = null; SeamELCompletionEngine fCompletionEngine = new SeamELCompletionEngine(); try { elements = fCompletionEngine.getJavaElementsForELOperandTokens(fCurrentSeamProject, file, expr); } catch (StringIndexOutOfBoundsException e) { SeamGuiPlugin.getPluginLog().logError(e); } catch (BadLocationException e) { SeamGuiPlugin.getPluginLog().logError(e); } if(elements != null) for (int i = 0; i < elements.size(); i++) { if (!matches(elements.get(i))) continue; int start = 0; int end = expr.getEndPosition() - expr.getStartPosition(); String variationText = operand.substring(start, end); int offsetOfOperandToken = offsetOfToken + start; int lengthOfOperandToken = end - start; fMatchAccess.initialize(file, offsetOfOperandToken, lengthOfOperandToken, content); boolean res= fCollector.acceptPatternMatch(fMatchAccess); if (!res) { return; // no further reporting requested } } expr = expr.getLeft(); } } else if (fVariableMatchers != null) { ELInvocationExpression expr = token; while(expr != null) { Set<ISeamContextVariable> variables = fCurrentSeamProject.getVariablesByName(expr.getText()); if(variables != null) for (ISeamContextVariable variable : variables) { if (!matches(variable)) continue; int start = 0; int end = expr.getEndPosition() - expr.getStartPosition(); String variationText = operand.substring(start, end); int offsetOfOperandToken = offsetOfToken + start; int lengthOfOperandToken = end - start; fMatchAccess.initialize(file, offsetOfOperandToken, lengthOfOperandToken, content); boolean res= fCollector.acceptPatternMatch(fMatchAccess); if (!res) { return; // no further reporting requested } } expr = expr.getLeft(); } } else if (fVarMatchers != null) { Var var = fELVarSearcher.findVarForEl(operand, null, fVarListForCurentValidatedNode, false); if (var != null){ if (matches(var)) { ELInvocationExpression expr = token; while(expr.getLeft() != null) expr = expr.getLeft(); String varRefText = expr.getText(); int start = expr.getStartPosition(); int end = expr.getEndPosition(); int offsetOfVarRefToken = offsetOfToken + start; int lengthOfVarRefToken = end - start; fMatchAccess.initialize(file, offsetOfVarRefToken, lengthOfVarRefToken, content); boolean res= fCollector.acceptPatternMatch(fMatchAccess); if (!res) { return; // no further reporting requested } } } } } } public boolean processSeamDeclarationsInProject(ISeamProject project) { if (fJavaMatchers != null && fJavaMatchers.length > 0) { JavaSearchScopeFactory factory= JavaSearchScopeFactory.getInstance(); IJavaSearchScope scope= factory.createWorkspaceScope(true); String description= factory.getWorkspaceScopeDescription(true); for (int i = 0; i < fJavaMatchers.length; i++) { ElementQuerySpecification elementQuerySpecification = new ElementQuerySpecification( fJavaMatchers[i].getElement(), IJavaSearchConstants.DECLARATIONS, scope, description); JavaSearchQuery query= new JavaSearchQuery(elementQuerySpecification); query.run(fProgressMonitor); JavaSearchResult result = (JavaSearchResult)query.getSearchResult(); Object[] elements = result.getElements(); for (int j = 0; elements != null && j < elements.length; j++) { Match[] matches = result.getMatches(elements[j]); for (int k = 0; matches != null && k < matches.length; k++) { fCollector.reportMatch(matches[k]); } } } } if (fVariableMatchers != null && fVariableMatchers.length > 0) { try { for (int i = 0; i < fVariableMatchers.length; i++) { if (fVariableMatchers[i] == null) continue; ISeamContextVariable variable = fVariableMatchers[i].getElement(); if (variable instanceof ISeamContextShortVariable) { variable = ((ISeamContextShortVariable)variable).getOriginal(); } boolean continueWithFactories = true; if (variable instanceof SeamComponent) { SeamComponent comp = (SeamComponent)variable; Set<ISeamComponentDeclaration> declarations = comp.getAllDeclarations(); for (ISeamComponentDeclaration decl : declarations) { if (decl instanceof IJavaSourceReference) { IJavaSourceReference sourceRef = (IJavaSourceReference)decl; IResource resource = sourceRef.getSourceMember().getResource(); IJavaElement sourceMember = sourceRef.getSourceMember(); String name = sourceRef.getSourceMember().getElementName(); int offset = sourceRef.getStartPosition(); int length = sourceRef.getLength(); //fMatchAccess.initialize((IFile)resource, offset, length, (CharSequence)name); boolean res= fCollector.acceptSeamDeclarationSourceReferenceMatch(sourceRef); if (!res) { return true; // no further reporting requested } continueWithFactories = false; } else if (decl instanceof IOpenableElement) { IResource resource = decl.getResource(); String name = decl.getName(); ITextSourceReference textSourceReference = decl.getLocationFor(AbstractSeamDeclaration.PATH_OF_NAME); if (textSourceReference != null) { int offset = textSourceReference.getStartPosition(); int length = textSourceReference.getLength(); boolean res= fCollector.acceptSeamDeclarationMatch(decl); if (!res) { return true; // no further reporting requested } continueWithFactories = false; } else { int offset = decl.getStartPosition(); int length = decl.getLength(); fMatchAccess.initialize((IFile)resource, offset, length, (CharSequence)name); boolean res= fCollector.acceptPatternMatch(fMatchAccess); if (!res) { return true; // no further reporting requested } continueWithFactories = false; } } } } else if (variable instanceof IRole) { // add the declaration ISeamDeclaration decl = (ISeamDeclaration)variable; IResource resource = decl.getResource(); String name = decl.getName(); ITextSourceReference textSourceReference = decl.getLocationFor(AbstractSeamDeclaration.PATH_OF_NAME); if (textSourceReference != null) { int offset = textSourceReference.getStartPosition(); int length = textSourceReference.getLength(); fMatchAccess.initialize((IFile)resource, offset, length, (CharSequence)name); boolean res= fCollector.acceptPatternMatch(fMatchAccess); if (!res) { return true; // no further reporting requested } continueWithFactories = false; } } else if (variable instanceof IBijectedAttribute) { IBijectedAttribute ba = (IBijectedAttribute)variable; BijectedAttributeType[] types = ba.getTypes(); boolean hasDeclarationType = false; for (int j = 0; !hasDeclarationType && types != null && j < types.length; j++) { if (types[j] == BijectedAttributeType.OUT || types[j] == BijectedAttributeType.DATA_BINDER || types[j] == BijectedAttributeType.DATA_MODEL_SELECTION) { hasDeclarationType = true; } } if (hasDeclarationType) { // add the declaration ISeamDeclaration decl = (ISeamDeclaration)variable; IResource resource = decl.getResource(); String name = decl.getName(); ITextSourceReference textSourceReference = decl.getLocationFor(AbstractSeamDeclaration.PATH_OF_NAME); if (textSourceReference != null) { int offset = textSourceReference.getStartPosition(); int length = textSourceReference.getLength(); fMatchAccess.initialize((IFile)resource, offset, length, (CharSequence)name); boolean res= fCollector.acceptPatternMatch(fMatchAccess); if (!res) { return true; // no further reporting requested } continueWithFactories = false; } } } // Search for Seam factories if (continueWithFactories && variable instanceof ISeamDeclaration) { ISeamDeclaration decl = (ISeamDeclaration)variable; IResource resource = decl.getResource(); String name = decl.getName(); ITextSourceReference textSourceReference = decl.getLocationFor(AbstractSeamDeclaration.PATH_OF_NAME); if (textSourceReference != null) { int offset = textSourceReference.getStartPosition(); int length = textSourceReference.getLength(); boolean res= fCollector.acceptSeamDeclarationMatch(decl); if (!res) { return true; // no further reporting requested } } } } } catch (CoreException ce) { String[] args= { getExceptionMessage(ce), project.getResource().getFullPath().makeRelative().toString()}; String message= Messages.format(SearchMessages.TextSearchVisitor_error, args); fStatus.add(new Status(IStatus.WARNING, NewSearchUI.PLUGIN_ID, IStatus.WARNING, message, ce)); } } if (fProgressMonitor.isCanceled()) throw new OperationCanceledException(SearchMessages.TextSearchVisitor_canceled); return true; } private class MonitorUpdateJob extends Job { private int fLastNumberOfScannedFiles= 0; MonitorUpdateJob() { super(SearchMessages.TextSearchVisitor_progress_updating_job); } public IStatus run(IProgressMonitor inner) { while (!inner.isCanceled()) { ISeamProject seamProject= fCurrentSeamProject; if (seamProject != null) { String seamProjectName= seamProject.getProject().getName(); Object[] args= { seamProjectName, new Integer(fNumberOfScannedFiles), new Integer(fNumberOfFilesToScan)}; fProgressMonitor.subTask(Messages.format(SeamCoreMessages.SeamSearchVisitor_scanning, args)); int steps= fNumberOfScannedFiles - fLastNumberOfScannedFiles; fProgressMonitor.worked(steps); fLastNumberOfScannedFiles += steps; } try { Thread.sleep(100); } catch (InterruptedException e) { return Status.OK_STATUS; } } return Status.OK_STATUS; } } private String getTaskName() { ISeamMatcher[] currentMatchers = (fJavaMatchers == null ? fVarMatchers : fJavaMatchers); StringBuffer elements = new StringBuffer(); for(int i = 0; currentMatchers != null && i < currentMatchers.length; i++) { if (currentMatchers[i] != null) { if (elements.length() > 0) { elements.append(", "); } elements.append(currentMatchers[i].getName()); } } String taskName= elements.length() == 0 ? SearchMessages.TextSearchVisitor_filesearch_task_label : Messages.format(SearchMessages.TextSearchVisitor_textsearch_task_label, elements.toString()); return taskName; } private IStatus searchForReferences(ISeamProject[] projects, IProgressMonitor monitor) { fProgressMonitor= monitor == null ? new NullProgressMonitor() : monitor; fNumberOfScannedFiles= 0; fNumberOfFilesToScan= calculateFiles(); fCurrentSeamProject= null; Job monitorUpdateJob= new MonitorUpdateJob(); try { fProgressMonitor.beginTask(getTaskName(), fNumberOfFilesToScan); monitorUpdateJob.setSystem(true); monitorUpdateJob.schedule(); try { fCollector.beginReporting(); processSeamProjects(projects, false); return fStatus; } finally { monitorUpdateJob.cancel(); } } finally { fProgressMonitor.done(); fCollector.endReporting(); } } ISeamMatcher fCurrentMatcher; private boolean matches (IJavaElement element) { fCurrentMatcher = null; for (int i = 0; fJavaMatchers != null && i < fJavaMatchers.length; i++) { if (fJavaMatchers[i] == null) continue; if (fJavaMatchers[i].match(element)) { fCurrentMatcher = fJavaMatchers[i]; return true; } } return false; } private boolean matches (ISeamContextVariable element) { fCurrentMatcher = null; for (int i = 0; fVariableMatchers != null && i < fVariableMatchers.length; i++) { if (fVariableMatchers[i] == null) continue; if (fVariableMatchers[i].match(element)) { fCurrentMatcher = fVariableMatchers[i]; return true; } } return false; } private boolean matches (Var var) { fCurrentMatcher = null; for (int i = 0; fVarMatchers != null && i < fVarMatchers.length; i++) { if (fVarMatchers[i] == null) continue; if (fVarMatchers[i].match(var)) { fCurrentMatcher = fVarMatchers[i]; return true; } } return false; } private static String getExceptionMessage(Exception e) { String message= e.getLocalizedMessage(); if (message == null) { return e.getClass().getName(); } return message; } private static boolean hasBinaryContent(CharSequence seq, IFile file) throws CoreException { IContentDescription desc= file.getContentDescription(); if (desc != null) { IContentType contentType= desc.getContentType(); if (contentType != null && contentType.isKindOf(Platform.getContentTypeManager().getContentType(IContentTypeManager.CT_TEXT))) { return false; } } // avoid calling seq.length() at it runs through the complete file, // thus it would do so for all binary files. try { int limit= FileCharSequenceProvider.BUFFER_SIZE; for (int i= 0; i < limit; i++) { if (seq.charAt(i) == '\0') { return true; } } } catch (IndexOutOfBoundsException e) { // The exception is to be ignored because we're not calling the seq.length() // due not to run through the complete file. // So, IndexOutOfBoundsException here indicates the end of file. } return false; } /** * @return returns a map from IFile to IDocument for all open, dirty editors */ private static Map evalNonFileBufferDocuments() { Map result= new HashMap(); IWorkbench workbench= SearchPlugin.getDefault().getWorkbench(); IWorkbenchWindow[] windows= workbench.getWorkbenchWindows(); for (int i= 0; i < windows.length; i++) { IWorkbenchPage[] pages= windows[i].getPages(); for (int x= 0; x < pages.length; x++) { IEditorReference[] editorRefs= pages[x].getEditorReferences(); for (int z= 0; z < editorRefs.length; z++) { IEditorPart ep= editorRefs[z].getEditor(false); if (ep instanceof ITextEditor && ep.isDirty()) { // only dirty editors evaluateTextEditor(result, ep); } } } } return result; } private static void evaluateTextEditor(Map result, IEditorPart ep) { IEditorInput input= ep.getEditorInput(); if (input instanceof IFileEditorInput) { IFile file= ((IFileEditorInput) input).getFile(); if (!result.containsKey(file)) { // take the first editor found ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager(); ITextFileBuffer textFileBuffer= bufferManager.getTextFileBuffer(file.getFullPath(), LocationKind.IFILE); if (textFileBuffer != null) { // file buffer has precedence result.put(file, textFileBuffer.getDocument()); } else { // use document provider IDocument document= ((ITextEditor) ep).getDocumentProvider().getDocument(input); if (document != null) { result.put(file, document); } } } } } private IDocument getOpenDocument(IFile file) { return getOpenDocument(file, fDocumentsInEditors); } /** * Returns the IDocument of file currently opened in an editor * @param file * @param documentsInEditors * @return */ public static IDocument getOpenDocument(IFile file, Map documentsInEditors) { IDocument document= (IDocument) documentsInEditors.get(file); if (document == null) { ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager(); ITextFileBuffer textFileBuffer= bufferManager.getTextFileBuffer(file.getFullPath(), LocationKind.IFILE); if (textFileBuffer != null) { document= textFileBuffer.getDocument(); } } return document; } private static String getCharSetName(IFile file) { try { return file.getCharset(); } catch (CoreException e) { return "unknown"; //$NON-NLS-1$ } } private static boolean acceptPaternMatch(SeamSearchRequestor collector, IFile file, int offset, int length, CharSequence content) throws CoreException { ReusableMatchAccess matchAccess = new ReusableMatchAccess(); matchAccess.initialize(file, offset, length, content); collector.beginReporting(); boolean result = collector.acceptPatternMatch(matchAccess); collector.endReporting(); return result; } /** * Reports a Pattern match to a given {@link SeamSearchRequestor} * * @param collector * @param file * @param offset * @param length * @return */ public static boolean acceptPaternMatch(SeamSearchRequestor collector, IFile file, int offset, int length) { try { IDocument document= getOpenDocument(file, evalNonFileBufferDocuments()); if (document != null) { DocumentCharSequence documentCharSequence= new DocumentCharSequence(document); // assume all documents are non-binary return acceptPaternMatch(collector, file, offset, length, documentCharSequence); } else { FileCharSequenceProvider fileCharSequenceProvider = new FileCharSequenceProvider(); CharSequence seq= null; try { seq= fileCharSequenceProvider.newCharSequence(file); if (hasBinaryContent(seq, file) && !collector.reportBinaryFile(file)) { return true; } return acceptPaternMatch(collector, file, offset, length, seq); } catch (FileCharSequenceProvider.FileCharSequenceException e) { e.throwWrappedException(); } finally { if (seq != null) { try { fileCharSequenceProvider.releaseCharSequence(seq); } catch (IOException e) { SearchPlugin.log(e); } } } } } catch (UnsupportedCharsetException e) { SearchPlugin.log(e); } catch (IllegalCharsetNameException e) { SearchPlugin.log(e); } catch (IOException e) { SearchPlugin.log(e); } catch (CoreException e) { SearchPlugin.log(e); } return false; } /** * Evaluates all files in this scope. * * @param status a {@link MultiStatus} to collect the error status that occurred while collecting resources. * @return returns the files in the scope. */ public IFile[] evaluateProjectFilesInScope(IProject project, MultiStatus status) { return new ProjectFilesOfScopeCalculator(project, fCurrentScope, status).process(); } private class ProjectFilesOfScopeCalculator implements IResourceProxyVisitor { private final IProject fProject; private final TextSearchScope fScope; private final MultiStatus fStatus; private ArrayList fFiles; public ProjectFilesOfScopeCalculator(IProject project, SeamSearchScope scope, MultiStatus status) { fProject = project; fScope = scope; fStatus= status; } public boolean visit(IResourceProxy proxy) { if (fScope == null) return false; boolean inScope= fScope.contains(proxy); if (inScope && proxy.getType() == IResource.FILE) { IFile file = (IFile)proxy.requestResource(); if(!file.isSynchronized(IResource.DEPTH_ZERO)) { // The resource is out of sync with the file system // Just ignore this resource. return false; } if (fProject == file.getProject()) { fFiles.add(proxy.requestResource()); } } return inScope; } public IFile[] process() { fFiles= new ArrayList(); try { IResource[] roots= fScope.getRoots(); for (int i= 0; i < roots.length; i++) { try { IResource resource= roots[i]; if (resource.isAccessible()) { resource.accept(this, 0); } } catch (CoreException ex) { // report and ignore fStatus.add(ex.getStatus()); } } return (IFile[]) fFiles.toArray(new IFile[fFiles.size()]); } finally { fFiles= null; } } } }