001: /*******************************************************************************
002: * Copyright (c) 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.Collections;
016: import java.util.HashMap;
017: import java.util.HashSet;
018: import java.util.Iterator;
019: import java.util.Map;
020: import java.util.Set;
021:
022: import org.eclipse.core.resources.IProject;
023: import org.eclipse.core.runtime.CoreException;
024: import org.eclipse.core.runtime.IProgressMonitor;
025: import org.eclipse.core.runtime.SubProgressMonitor;
026: import org.eclipse.jdt.core.Flags;
027: import org.eclipse.jdt.core.IField;
028: import org.eclipse.jdt.core.IJavaProject;
029: import org.eclipse.jdt.core.IMethod;
030: import org.eclipse.jdt.core.IPackageFragment;
031: import org.eclipse.jdt.core.IType;
032: import org.eclipse.jdt.core.ITypeRoot;
033: import org.eclipse.jdt.core.JavaCore;
034: import org.eclipse.jdt.core.JavaModelException;
035: import org.eclipse.jdt.core.Signature;
036: import org.eclipse.osgi.util.NLS;
037: import org.eclipse.pde.internal.core.ibundle.IBundle;
038: import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase;
039: import org.eclipse.pde.internal.core.ibundle.IManifestHeader;
040: import org.eclipse.pde.internal.core.text.bundle.ExportPackageHeader;
041: import org.eclipse.pde.internal.core.text.bundle.ExportPackageObject;
042: import org.eclipse.pde.internal.core.util.PDEJavaHelper;
043: import org.eclipse.pde.internal.ui.PDEUIMessages;
044: import org.eclipse.ui.actions.WorkspaceModifyOperation;
045: import org.osgi.framework.Constants;
046:
047: public class CalculateUsesOperation extends WorkspaceModifyOperation {
048:
049: private IProject fProject;
050: private IBundlePluginModelBase fModel;
051:
052: public CalculateUsesOperation(IProject project,
053: IBundlePluginModelBase model) {
054: fProject = project;
055: fModel = model;
056: }
057:
058: protected void execute(IProgressMonitor monitor)
059: throws CoreException, InvocationTargetException,
060: InterruptedException {
061: try {
062: Collection packages = getPublicExportedPackages();
063: if (packages.isEmpty())
064: return;
065: Map pkgsAndUses = findPackageReferences(packages, monitor);
066: handleSetUsesDirectives(pkgsAndUses);
067: } finally {
068: monitor.done();
069: }
070: }
071:
072: protected Collection getPublicExportedPackages() {
073: IBundle bundle = fModel.getBundleModel().getBundle();
074: IManifestHeader header = bundle
075: .getManifestHeader(Constants.EXPORT_PACKAGE);
076: if (header == null)
077: return Collections.EMPTY_SET;
078:
079: ArrayList list = new ArrayList();
080: ExportPackageObject[] pkgs = ((ExportPackageHeader) header)
081: .getPackages();
082: for (int i = 0; i < pkgs.length; i++) {
083: // don't calculate uses directive on private packages
084: if (!pkgs[i].isInternal())
085: list.add(pkgs[i].getName());
086: }
087: return list;
088: }
089:
090: protected Map findPackageReferences(Collection packages,
091: IProgressMonitor monitor) {
092: IJavaProject jp = JavaCore.create(fProject);
093: HashMap pkgsAndUses = new HashMap();
094: IPackageFragment[] frags = PDEJavaHelper.getPackageFragments(
095: jp, Collections.EMPTY_SET, false);
096: monitor.beginTask("", frags.length * 2); //$NON-NLS-1$
097: for (int i = 0; i < frags.length; i++) {
098: monitor
099: .subTask(NLS
100: .bind(
101: PDEUIMessages.CalculateUsesOperation_calculatingDirective,
102: frags[i].getElementName()));
103: if (packages.contains(frags[i].getElementName())) {
104: HashSet pkgs = new HashSet();
105: pkgsAndUses.put(frags[i].getElementName(), pkgs);
106: try {
107: findReferences(frags[i].getCompilationUnits(),
108: pkgs, new SubProgressMonitor(monitor, 1),
109: false);
110: findReferences(frags[i].getClassFiles(), pkgs,
111: new SubProgressMonitor(monitor, 1), true);
112: } catch (JavaModelException e) {
113: }
114: } else
115: monitor.worked(2);
116: }
117: return pkgsAndUses;
118: }
119:
120: protected void findReferences(ITypeRoot[] roots, Set pkgs,
121: IProgressMonitor monitor, boolean binary)
122: throws JavaModelException {
123: monitor.beginTask("", roots.length); //$NON-NLS-1$
124: for (int i = 0; i < roots.length; i++) {
125: findReferences(roots[i].findPrimaryType(), pkgs, binary);
126: monitor.worked(1);
127: }
128: }
129:
130: protected void findReferences(IType type, Set pkgs, boolean binary)
131: throws JavaModelException {
132: if (type == null)
133: return;
134: // ignore private classes
135: if (Flags.isPrivate(type.getFlags()))
136: return;
137:
138: IMethod[] methods = type.getMethods();
139: for (int i = 0; i < methods.length; i++) {
140: if (!Flags.isPrivate(methods[i].getFlags())) {
141: String methodSignature = methods[i].getSignature();
142: addPackages(Signature
143: .getThrownExceptionTypes(methodSignature),
144: pkgs, type, binary);
145: addPackages(Signature
146: .getParameterTypes(methodSignature), pkgs,
147: type, binary);
148: addPackage(Signature.getReturnType(methodSignature),
149: pkgs, type, binary);
150: }
151: }
152: IField[] fields = type.getFields();
153: for (int i = 0; i < fields.length; i++)
154: if (!Flags.isPrivate(fields[i].getFlags()))
155: addPackage(fields[i].getTypeSignature(), pkgs, type,
156: binary);
157: addPackage(type.getSuperclassTypeSignature(), pkgs, type,
158: binary);
159: addPackages(type.getSuperInterfaceTypeSignatures(), pkgs, type,
160: binary);
161:
162: // make sure to check sub classes defined in the class
163: IType[] subTypes = type.getTypes();
164: for (int i = 0; i < subTypes.length; i++) {
165: findReferences(subTypes[i], pkgs, binary);
166: }
167: }
168:
169: protected final void addPackage(String typeSignature, Set pkgs,
170: IType type, boolean binary) throws JavaModelException {
171: if (typeSignature == null)
172: return;
173: if (binary)
174: typeSignature = typeSignature.replace('/', '.');
175: // if typeSignature contains a '.', test to see if it is a subClass first. If not, assume it is a fully qualified name
176: if (typeSignature.indexOf('.') != -1) {
177: try {
178: String[][] temp = type.resolveType(new String(Signature
179: .toCharArray(typeSignature.toCharArray())));
180: if (temp != null) {
181: pkgs.add(temp[0][0]);
182: return;
183: }
184: } catch (IllegalArgumentException e) {
185: }
186: String pkg = Signature.getSignatureQualifier(typeSignature);
187: if (pkg.length() > 0) {
188: pkgs.add(pkg);
189: return;
190: }
191: // if typeSignature does not contain a '.', then assume the package name is in an import statement and try to resolve through the type object
192: } else {
193: String typeName = Signature
194: .getSignatureSimpleName(typeSignature);
195: String[][] result = type.resolveType(typeName);
196: if (result != null)
197: pkgs.add(result[0][0]);
198: }
199: }
200:
201: protected final void addPackages(String[] typeSignatures, Set pkgs,
202: IType type, boolean binary) throws JavaModelException {
203: for (int i = 0; i < typeSignatures.length; i++)
204: addPackage(typeSignatures[i], pkgs, type, binary);
205: }
206:
207: protected void handleSetUsesDirectives(Map pkgsAndUses) {
208: if (pkgsAndUses.isEmpty())
209: return;
210: setUsesDirectives(pkgsAndUses);
211: }
212:
213: protected void setUsesDirectives(Map pkgsAndUses) {
214: IBundle bundle = fModel.getBundleModel().getBundle();
215: IManifestHeader header = bundle
216: .getManifestHeader(Constants.EXPORT_PACKAGE);
217: // header will not equal null b/c we would not get this far (ie. no exported packages so we would have returned earlier
218: ExportPackageObject[] pkgs = ((ExportPackageHeader) header)
219: .getPackages();
220: for (int i = 0; i < pkgs.length; i++) {
221: if (!pkgsAndUses.containsKey(pkgs[i].getName()))
222: continue;
223: String value = getDirectiveValue(pkgs[i].getName(),
224: pkgsAndUses);
225: pkgs[i].setUsesDirective(value);
226: }
227: }
228:
229: protected String getDirectiveValue(String pkgName, Map pkgsAndUses) {
230: Set usesPkgs = (Set) pkgsAndUses.get(pkgName);
231: usesPkgs.remove(pkgName);
232: StringBuffer buffer = null;
233: Iterator it = usesPkgs.iterator();
234: while (it.hasNext()) {
235: String usedPkgName = (String) it.next();
236: if (usedPkgName.startsWith("java.")) { //$NON-NLS-1$
237: // we should not include java.* packages (bug 167968)
238: it.remove();
239: continue;
240: }
241: if (buffer == null)
242: buffer = new StringBuffer();
243: else
244: buffer.append(',');
245: buffer.append(usedPkgName);
246: it.remove();
247: }
248: if (usesPkgs.isEmpty())
249: pkgsAndUses.remove(pkgName);
250: return (buffer == null) ? null : buffer.toString();
251: }
252:
253: }
|