001: /*******************************************************************************
002: * Copyright (c) 2005, 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.pde.internal.ui.search.dependencies;
011:
012: import java.lang.reflect.InvocationTargetException;
013: import java.util.ArrayList;
014: import java.util.Collection;
015: import java.util.HashMap;
016: import java.util.Iterator;
017: import java.util.ListIterator;
018: import java.util.Stack;
019:
020: import org.eclipse.core.resources.IProject;
021: import org.eclipse.core.runtime.CoreException;
022: import org.eclipse.core.runtime.IProgressMonitor;
023: import org.eclipse.core.runtime.SubProgressMonitor;
024: import org.eclipse.jdt.core.IClassFile;
025: import org.eclipse.jdt.core.ICompilationUnit;
026: import org.eclipse.jdt.core.IJavaElement;
027: import org.eclipse.jdt.core.IJavaProject;
028: import org.eclipse.jdt.core.IPackageFragment;
029: import org.eclipse.jdt.core.IType;
030: import org.eclipse.jdt.core.JavaCore;
031: import org.eclipse.jdt.core.JavaModelException;
032: import org.eclipse.jdt.core.search.IJavaSearchConstants;
033: import org.eclipse.jdt.core.search.IJavaSearchScope;
034: import org.eclipse.jdt.core.search.SearchEngine;
035: import org.eclipse.jdt.core.search.SearchMatch;
036: import org.eclipse.jdt.core.search.SearchParticipant;
037: import org.eclipse.jdt.core.search.SearchPattern;
038: import org.eclipse.jdt.core.search.SearchRequestor;
039: import org.eclipse.jface.operation.IRunnableWithProgress;
040: import org.eclipse.pde.core.plugin.IPluginImport;
041: import org.eclipse.pde.core.plugin.IPluginModelBase;
042: import org.eclipse.pde.core.plugin.PluginRegistry;
043: import org.eclipse.pde.internal.core.ClasspathUtilCore;
044: import org.eclipse.pde.internal.core.ibundle.IBundle;
045: import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase;
046: import org.eclipse.pde.internal.core.ibundle.IManifestHeader;
047: import org.eclipse.pde.internal.core.search.PluginJavaSearchUtil;
048: import org.eclipse.pde.internal.core.text.bundle.ExportPackageHeader;
049: import org.eclipse.pde.internal.core.text.bundle.ImportPackageHeader;
050: import org.eclipse.pde.internal.core.text.bundle.ImportPackageObject;
051: import org.eclipse.pde.internal.ui.PDEUIMessages;
052: import org.osgi.framework.Constants;
053:
054: public class GatherUnusedDependenciesOperation implements
055: IRunnableWithProgress {
056:
057: class Requestor extends SearchRequestor {
058: boolean fFound = false;
059:
060: public void acceptSearchMatch(SearchMatch match)
061: throws CoreException {
062: fFound = true;
063: }
064:
065: public boolean foundMatches() {
066: return fFound;
067: }
068: }
069:
070: private IPluginModelBase fModel;
071: private ArrayList fList;
072:
073: public GatherUnusedDependenciesOperation(IPluginModelBase model) {
074: fModel = model;
075: }
076:
077: public void run(IProgressMonitor monitor)
078: throws InvocationTargetException, InterruptedException {
079:
080: ImportPackageObject[] packages = null;
081: Collection exportedPackages = null;
082: if (ClasspathUtilCore.hasBundleStructure(fModel)) {
083: IBundle bundle = ((IBundlePluginModelBase) fModel)
084: .getBundleModel().getBundle();
085: IManifestHeader header = bundle
086: .getManifestHeader(Constants.IMPORT_PACKAGE);
087: if (header instanceof ImportPackageHeader) {
088: packages = ((ImportPackageHeader) header).getPackages();
089: } else if (header != null && header.getValue() != null) {
090: header = new ImportPackageHeader(
091: Constants.IMPORT_PACKAGE, header.getValue(),
092: bundle, System.getProperty("line.separator")); //$NON-NLS-1$
093: packages = ((ImportPackageHeader) header).getPackages();
094: }
095:
096: header = bundle.getManifestHeader(Constants.EXPORT_PACKAGE);
097: if (header instanceof ExportPackageHeader) {
098: exportedPackages = ((ExportPackageHeader) header)
099: .getPackageNames();
100: } else if (header != null && header.getValue() != null) {
101: header = new ExportPackageHeader(
102: Constants.EXPORT_PACKAGE, header.getValue(),
103: bundle, System.getProperty("line.seperator")); //$NON-NLS-1$
104: exportedPackages = ((ExportPackageHeader) header)
105: .getPackageNames();
106: }
107: }
108: IPluginImport[] imports = fModel.getPluginBase().getImports();
109:
110: int totalWork = imports.length * 3
111: + (packages != null ? packages.length : 0) + 1;
112: monitor.beginTask("", totalWork); //$NON-NLS-1$
113:
114: HashMap usedPlugins = new HashMap();
115: fList = new ArrayList();
116: for (int i = 0; i < imports.length; i++) {
117: if (monitor.isCanceled())
118: break;
119: if (isUnused(imports[i], new SubProgressMonitor(monitor, 3))) {
120: fList.add(imports[i]);
121: } else
122: usedPlugins.put(imports[i].getId(), imports[i]);
123: updateMonitor(monitor, fList.size());
124: }
125:
126: ArrayList usedPackages = new ArrayList();
127: if (packages != null && !monitor.isCanceled()) {
128: for (int i = 0; i < packages.length; i++) {
129: if (monitor.isCanceled())
130: break;
131: if (isUnused(packages[i], exportedPackages,
132: new SubProgressMonitor(monitor, 1))) {
133: fList.add(packages[i]);
134: updateMonitor(monitor, fList.size());
135: } else
136: usedPackages.add(packages[i]);
137: }
138: }
139: if (!monitor.isCanceled())
140: minimizeDependencies(usedPlugins, usedPackages, monitor);
141: monitor.done();
142: }
143:
144: private void updateMonitor(IProgressMonitor monitor, int size) {
145: monitor.setTaskName(PDEUIMessages.UnusedDependencies_analyze
146: + size
147: + " " //$NON-NLS-1$
148: + PDEUIMessages.UnusedDependencies_unused
149: + " " //$NON-NLS-1$
150: + (size == 1 ? PDEUIMessages.DependencyExtent_singular
151: : PDEUIMessages.DependencyExtent_plural) + " " //$NON-NLS-1$
152: + PDEUIMessages.DependencyExtent_found);
153: }
154:
155: private boolean isUnused(IPluginImport plugin,
156: SubProgressMonitor monitor) {
157: IPluginModelBase[] models = PluginJavaSearchUtil
158: .getPluginImports(plugin);
159: return !provideJavaClasses(models, monitor);
160: }
161:
162: private boolean isUnused(ImportPackageObject pkg,
163: Collection exportedPackages, SubProgressMonitor monitor) {
164: if (exportedPackages != null
165: && exportedPackages.contains(pkg.getValue())) {
166: monitor.done();
167: return false;
168: }
169: return !provideJavaClasses(pkg, monitor);
170: }
171:
172: private boolean provideJavaClasses(IPluginModelBase[] models,
173: IProgressMonitor monitor) {
174: try {
175: IProject project = fModel.getUnderlyingResource()
176: .getProject();
177: if (!project.hasNature(JavaCore.NATURE_ID))
178: return false;
179:
180: IJavaProject jProject = JavaCore.create(project);
181: IPackageFragment[] packageFragments = PluginJavaSearchUtil
182: .collectPackageFragments(models, jProject, true);
183: SearchEngine engine = new SearchEngine();
184: IJavaSearchScope searchScope = PluginJavaSearchUtil
185: .createSeachScope(jProject);
186:
187: monitor.beginTask("", packageFragments.length * 2); //$NON-NLS-1$
188: for (int i = 0; i < packageFragments.length; i++) {
189: IPackageFragment pkgFragment = packageFragments[i];
190: if (pkgFragment.hasChildren()) {
191: Requestor requestor = new Requestor();
192: engine.search(SearchPattern.createPattern(
193: pkgFragment,
194: IJavaSearchConstants.REFERENCES),
195: new SearchParticipant[] { SearchEngine
196: .getDefaultSearchParticipant() },
197: searchScope, requestor,
198: new SubProgressMonitor(monitor, 1));
199: if (requestor.foundMatches()) {
200: if (provideJavaClasses(packageFragments[i],
201: engine, searchScope,
202: new SubProgressMonitor(monitor, 1))) {
203: return true;
204: }
205: } else
206: monitor.worked(1);
207: } else {
208: monitor.worked(2);
209: }
210: }
211: } catch (CoreException e) {
212: } finally {
213: monitor.done();
214: }
215: return false;
216: }
217:
218: private boolean provideJavaClasses(
219: IPackageFragment packageFragment, SearchEngine engine,
220: IJavaSearchScope searchScope, IProgressMonitor monitor)
221: throws JavaModelException, CoreException {
222: Requestor requestor;
223: IJavaElement[] children = packageFragment.getChildren();
224: monitor.beginTask("", children.length); //$NON-NLS-1$
225:
226: try {
227: for (int j = 0; j < children.length; j++) {
228: IType[] types = null;
229: if (children[j] instanceof ICompilationUnit) {
230: types = ((ICompilationUnit) children[j])
231: .getAllTypes();
232: } else if (children[j] instanceof IClassFile) {
233: types = new IType[] { ((IClassFile) children[j])
234: .getType() };
235: }
236: if (types != null) {
237: for (int t = 0; t < types.length; t++) {
238: requestor = new Requestor();
239: engine
240: .search(
241: SearchPattern
242: .createPattern(
243: types[t],
244: IJavaSearchConstants.REFERENCES),
245: new SearchParticipant[] { SearchEngine
246: .getDefaultSearchParticipant() },
247: searchScope, requestor,
248: new SubProgressMonitor(monitor,
249: 1));
250: if (requestor.foundMatches()) {
251: return true;
252: }
253: }
254: }
255: }
256: } finally {
257: monitor.done();
258: }
259: return false;
260: }
261:
262: private boolean provideJavaClasses(ImportPackageObject pkg,
263: IProgressMonitor monitor) {
264: try {
265: IProject project = fModel.getUnderlyingResource()
266: .getProject();
267:
268: if (!project.hasNature(JavaCore.NATURE_ID))
269: return false;
270:
271: monitor.beginTask("", 1); //$NON-NLS-1$
272: IJavaProject jProject = JavaCore.create(project);
273: SearchEngine engine = new SearchEngine();
274: IJavaSearchScope searchScope = PluginJavaSearchUtil
275: .createSeachScope(jProject);
276: Requestor requestor = new Requestor();
277: String packageName = pkg.getName();
278:
279: engine.search(SearchPattern.createPattern(packageName,
280: IJavaSearchConstants.PACKAGE,
281: IJavaSearchConstants.REFERENCES,
282: SearchPattern.R_EXACT_MATCH),
283: new SearchParticipant[] { SearchEngine
284: .getDefaultSearchParticipant() },
285: searchScope, requestor, new SubProgressMonitor(
286: monitor, 1));
287:
288: if (requestor.foundMatches())
289: return true;
290: } catch (CoreException e) {
291: } finally {
292: monitor.done();
293: }
294: return false;
295: }
296:
297: public ArrayList getList() {
298: return fList;
299: }
300:
301: public static void removeDependencies(IPluginModelBase model,
302: Object[] elements) {
303: ImportPackageHeader pkgHeader = null;
304: for (int i = 0; i < elements.length; i++) {
305: if (elements[i] instanceof IPluginImport)
306: try {
307: model.getPluginBase().remove(
308: (IPluginImport) elements[i]);
309: } catch (CoreException e) {
310: }
311: else if (elements[i] instanceof ImportPackageObject) {
312: if (pkgHeader == null)
313: pkgHeader = (ImportPackageHeader) ((ImportPackageObject) elements[i])
314: .getHeader();
315: pkgHeader
316: .removePackage((ImportPackageObject) elements[i]);
317: }
318: }
319: }
320:
321: private void minimizeDependencies(HashMap usedPlugins,
322: ArrayList usedPackages, IProgressMonitor monitor) {
323: ListIterator li = usedPackages.listIterator();
324: while (li.hasNext()) {
325: ImportPackageObject ipo = (ImportPackageObject) li.next();
326: String bundle = ipo
327: .getAttribute(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE);
328: if (usedPlugins.containsKey(bundle))
329: fList.add(ipo);
330: }
331:
332: Iterator it = usedPlugins.keySet().iterator();
333: Stack plugins = new Stack();
334: while (it.hasNext())
335: plugins.push(it.next().toString());
336:
337: while (!(plugins.isEmpty())) {
338: String pluginId = (String) plugins.pop();
339: IPluginModelBase base = PluginRegistry.findModel(pluginId);
340: if (base == null)
341: continue;
342: IPluginImport[] imports = base.getPluginBase().getImports();
343:
344: for (int j = 0; j < imports.length; j++)
345: if (imports[j].isReexported()) {
346: String reExportedId = imports[j].getId();
347: Object pluginImport = usedPlugins.remove(imports[j]
348: .getId());
349: if (pluginImport != null) {
350: fList.add(pluginImport);
351: updateMonitor(monitor, fList.size());
352: }
353: plugins.push(reExportedId);
354: }
355: }
356: }
357: }
|