001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.corext.refactoring;
011:
012: import java.util.ArrayList;
013: import java.util.Arrays;
014: import java.util.HashMap;
015: import java.util.HashSet;
016: import java.util.Iterator;
017: import java.util.List;
018: import java.util.Map;
019: import java.util.Set;
020:
021: import org.eclipse.core.runtime.CoreException;
022: import org.eclipse.core.runtime.IProgressMonitor;
023:
024: import org.eclipse.core.resources.IResource;
025:
026: import org.eclipse.ltk.core.refactoring.IRefactoringStatusEntryComparator;
027: import org.eclipse.ltk.core.refactoring.RefactoringStatus;
028: import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry;
029:
030: import org.eclipse.jdt.core.ICompilationUnit;
031: import org.eclipse.jdt.core.IJavaElement;
032: import org.eclipse.jdt.core.JavaCore;
033: import org.eclipse.jdt.core.JavaModelException;
034: import org.eclipse.jdt.core.WorkingCopyOwner;
035: import org.eclipse.jdt.core.search.IJavaSearchScope;
036: import org.eclipse.jdt.core.search.SearchEngine;
037: import org.eclipse.jdt.core.search.SearchMatch;
038: import org.eclipse.jdt.core.search.SearchPattern;
039: import org.eclipse.jdt.core.search.SearchRequestor;
040:
041: import org.eclipse.jdt.internal.corext.util.SearchUtils;
042:
043: /**
044: * Convenience wrapper for {@link SearchEngine} - performs searching and sorts the results by {@link IResource}.
045: * TODO: throw CoreExceptions from search(..) methods instead of wrapped JavaModelExceptions.
046: */
047: public class RefactoringSearchEngine {
048:
049: private RefactoringSearchEngine() {
050: //no instances
051: }
052:
053: //TODO: throw CoreException
054: public static ICompilationUnit[] findAffectedCompilationUnits(
055: SearchPattern pattern, IJavaSearchScope scope,
056: final IProgressMonitor pm, RefactoringStatus status,
057: final boolean tolerateInAccurateMatches)
058: throws JavaModelException {
059:
060: boolean hasNonCuMatches = false;
061:
062: class ResourceSearchRequestor extends SearchRequestor {
063: boolean hasPotentialMatches = false;
064: Set resources = new HashSet(5);
065: private IResource fLastResource;
066:
067: public void acceptSearchMatch(SearchMatch match) {
068: if (!tolerateInAccurateMatches
069: && match.getAccuracy() == SearchMatch.A_INACCURATE) {
070: hasPotentialMatches = true;
071: }
072: if (fLastResource != match.getResource()) {
073: fLastResource = match.getResource();
074: resources.add(fLastResource);
075: }
076: }
077: }
078: ResourceSearchRequestor requestor = new ResourceSearchRequestor();
079: try {
080: new SearchEngine().search(pattern, SearchUtils
081: .getDefaultSearchParticipants(), scope, requestor,
082: pm);
083: } catch (CoreException e) {
084: throw new JavaModelException(e);
085: }
086:
087: List result = new ArrayList(requestor.resources.size());
088: for (Iterator iter = requestor.resources.iterator(); iter
089: .hasNext();) {
090: IResource resource = (IResource) iter.next();
091: IJavaElement element = JavaCore.create(resource);
092: if (element instanceof ICompilationUnit) {
093: result.add(element);
094: } else {
095: hasNonCuMatches = true;
096: }
097: }
098: addStatusErrors(status, requestor.hasPotentialMatches,
099: hasNonCuMatches);
100: return (ICompilationUnit[]) result
101: .toArray(new ICompilationUnit[result.size()]);
102: }
103:
104: //TODO: throw CoreException
105: public static ICompilationUnit[] findAffectedCompilationUnits(
106: SearchPattern pattern, IJavaSearchScope scope,
107: final IProgressMonitor pm, RefactoringStatus status)
108: throws JavaModelException {
109: return findAffectedCompilationUnits(pattern, scope, pm, status,
110: false);
111: }
112:
113: /**
114: * Performs a search and groups the resulting {@link SearchMatch}es by
115: * {@link SearchResultGroup#getCompilationUnit()}.
116: * @param pattern the search pattern
117: * @param scope the search scope
118: * @param monitor the progress monitor
119: * @param status an error is added here if inaccurate or non-cu matches have been found
120: * @return a {@link SearchResultGroup}[], where each {@link SearchResultGroup}
121: * has a different {@link SearchMatch#getResource() getResource()}s.
122: * @see SearchMatch
123: * @throws JavaModelException when the search failed
124: */
125: //TODO: throw CoreException
126: public static SearchResultGroup[] search(SearchPattern pattern,
127: IJavaSearchScope scope, IProgressMonitor monitor,
128: RefactoringStatus status) throws JavaModelException {
129: return internalSearch(new SearchEngine(), pattern, scope,
130: new CollectingSearchRequestor(), monitor, status);
131: }
132:
133: //TODO: throw CoreException
134: public static SearchResultGroup[] search(SearchPattern pattern,
135: WorkingCopyOwner owner, IJavaSearchScope scope,
136: IProgressMonitor monitor, RefactoringStatus status)
137: throws JavaModelException {
138: return internalSearch(owner != null ? new SearchEngine(owner)
139: : new SearchEngine(), pattern, scope,
140: new CollectingSearchRequestor(), monitor, status);
141: }
142:
143: //TODO: throw CoreException
144: public static SearchResultGroup[] search(SearchPattern pattern,
145: IJavaSearchScope scope,
146: CollectingSearchRequestor requestor,
147: IProgressMonitor monitor, RefactoringStatus status)
148: throws JavaModelException {
149: return internalSearch(new SearchEngine(), pattern, scope,
150: requestor, monitor, status);
151: }
152:
153: //TODO: throw CoreException
154: public static SearchResultGroup[] search(SearchPattern pattern,
155: WorkingCopyOwner owner, IJavaSearchScope scope,
156: CollectingSearchRequestor requestor,
157: IProgressMonitor monitor, RefactoringStatus status)
158: throws JavaModelException {
159: return internalSearch(owner != null ? new SearchEngine(owner)
160: : new SearchEngine(), pattern, scope, requestor,
161: monitor, status);
162: }
163:
164: //TODO: throw CoreException
165: private static SearchResultGroup[] internalSearch(
166: SearchEngine searchEngine, SearchPattern pattern,
167: IJavaSearchScope scope,
168: CollectingSearchRequestor requestor,
169: IProgressMonitor monitor, RefactoringStatus status)
170: throws JavaModelException {
171: try {
172: searchEngine.search(pattern, SearchUtils
173: .getDefaultSearchParticipants(), scope, requestor,
174: monitor);
175: } catch (CoreException e) {
176: throw new JavaModelException(e);
177: }
178: return groupByCu(requestor.getResults(), status);
179: }
180:
181: public static SearchResultGroup[] groupByCu(SearchMatch[] matches,
182: RefactoringStatus status) {
183: return groupByCu(Arrays.asList(matches), status);
184: }
185:
186: /**
187: * @param matchList a List of SearchMatch
188: * @param status the status to report errors.
189: * @return a SearchResultGroup[], grouped by SearchMatch#getResource()
190: */
191: public static SearchResultGroup[] groupByCu(List matchList,
192: RefactoringStatus status) {
193: Map/*<IResource, List<SearchMatch>>*/grouped = new HashMap();
194: boolean hasPotentialMatches = false;
195: boolean hasNonCuMatches = false;
196:
197: for (Iterator iter = matchList.iterator(); iter.hasNext();) {
198: SearchMatch searchMatch = (SearchMatch) iter.next();
199: if (searchMatch.getAccuracy() == SearchMatch.A_INACCURATE)
200: hasPotentialMatches = true;
201: if (!grouped.containsKey(searchMatch.getResource()))
202: grouped
203: .put(searchMatch.getResource(),
204: new ArrayList(1));
205: ((List) grouped.get(searchMatch.getResource()))
206: .add(searchMatch);
207: }
208:
209: for (Iterator iter = grouped.keySet().iterator(); iter
210: .hasNext();) {
211: IResource resource = (IResource) iter.next();
212: IJavaElement element = JavaCore.create(resource);
213: if (!(element instanceof ICompilationUnit)) {
214: iter.remove();
215: hasNonCuMatches = true;
216: }
217: }
218:
219: SearchResultGroup[] result = new SearchResultGroup[grouped
220: .keySet().size()];
221: int i = 0;
222: for (Iterator iter = grouped.keySet().iterator(); iter
223: .hasNext();) {
224: IResource resource = (IResource) iter.next();
225: List searchMatches = (List) grouped.get(resource);
226: SearchMatch[] matchArray = (SearchMatch[]) searchMatches
227: .toArray(new SearchMatch[searchMatches.size()]);
228: result[i] = new SearchResultGroup(resource, matchArray);
229: i++;
230: }
231: addStatusErrors(status, hasPotentialMatches, hasNonCuMatches);
232: return result;
233: }
234:
235: public static SearchPattern createOrPattern(
236: IJavaElement[] elements, int limitTo) {
237: if (elements == null || elements.length == 0)
238: return null;
239: Set set = new HashSet(Arrays.asList(elements));
240: Iterator iter = set.iterator();
241: IJavaElement first = (IJavaElement) iter.next();
242: SearchPattern pattern = SearchPattern.createPattern(first,
243: limitTo, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE);
244: if (pattern == null) // check for bug 90138
245: throw new IllegalArgumentException(
246: "Invalid java element: " + first.getHandleIdentifier() + "\n" + first.toString()); //$NON-NLS-1$ //$NON-NLS-2$
247: while (iter.hasNext()) {
248: IJavaElement each = (IJavaElement) iter.next();
249: SearchPattern nextPattern = SearchPattern.createPattern(
250: each, limitTo,
251: SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE);
252: if (nextPattern == null) // check for bug 90138
253: throw new IllegalArgumentException(
254: "Invalid java element: " + each.getHandleIdentifier() + "\n" + each.toString()); //$NON-NLS-1$ //$NON-NLS-2$
255: pattern = SearchPattern.createOrPattern(pattern,
256: nextPattern);
257: }
258: return pattern;
259: }
260:
261: private static boolean containsStatusEntry(
262: final RefactoringStatus status,
263: final RefactoringStatusEntry other) {
264: return status.getEntries(
265: new IRefactoringStatusEntryComparator() {
266: public final int compare(
267: final RefactoringStatusEntry entry1,
268: final RefactoringStatusEntry entry2) {
269: return entry1.getMessage().compareTo(
270: entry2.getMessage());
271: }
272: }, other).length > 0;
273: }
274:
275: private static void addStatusErrors(RefactoringStatus status,
276: boolean hasPotentialMatches, boolean hasNonCuMatches) {
277: if (hasPotentialMatches) {
278: final RefactoringStatusEntry entry = new RefactoringStatusEntry(
279: RefactoringStatus.ERROR,
280: RefactoringCoreMessages.RefactoringSearchEngine_potential_matches);
281: if (!containsStatusEntry(status, entry))
282: status.addEntry(entry);
283: }
284: if (hasNonCuMatches) {
285: final RefactoringStatusEntry entry = new RefactoringStatusEntry(
286: RefactoringStatus.ERROR,
287: RefactoringCoreMessages.RefactoringSearchEngine_non_cu_matches);
288: if (!containsStatusEntry(status, entry))
289: status.addEntry(entry);
290: }
291: }
292: }
|