1 /*******************************************************************************
2  * Copyright (c) 2005, 2019 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.pde.internal.core.util;
15 
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.LinkedHashMap;
21 import java.util.ListIterator;
22 import org.eclipse.core.resources.IProject;
23 import org.eclipse.core.resources.IResource;
24 import org.eclipse.core.runtime.CoreException;
25 import org.eclipse.core.runtime.IPath;
26 import org.eclipse.core.runtime.Path;
27 import org.eclipse.jdt.core.IJavaElement;
28 import org.eclipse.jdt.core.IJavaProject;
29 import org.eclipse.jdt.core.IPackageFragment;
30 import org.eclipse.jdt.core.IPackageFragmentRoot;
31 import org.eclipse.jdt.core.IType;
32 import org.eclipse.jdt.core.JavaCore;
33 import org.eclipse.jdt.core.JavaModelException;
34 import org.eclipse.jdt.core.search.IJavaSearchScope;
35 import org.eclipse.jdt.core.search.SearchEngine;
36 import org.eclipse.jdt.launching.JavaRuntime;
37 import org.eclipse.osgi.service.resolver.BundleDescription;
38 import org.eclipse.osgi.service.resolver.ExportPackageDescription;
39 import org.eclipse.osgi.service.resolver.ImportPackageSpecification;
40 import org.eclipse.osgi.service.resolver.State;
41 import org.eclipse.osgi.service.resolver.StateHelper;
42 import org.eclipse.pde.core.plugin.IPluginLibrary;
43 import org.eclipse.pde.core.plugin.IPluginModelBase;
44 import org.eclipse.pde.core.plugin.PluginRegistry;
45 import org.eclipse.pde.internal.core.ClasspathUtilCore;
46 import org.eclipse.pde.internal.core.PDECore;
47 import org.eclipse.pde.internal.core.PDEPreferencesManager;
48 import org.eclipse.pde.internal.core.SearchablePluginsManager;
49 
50 public class PDEJavaHelper {
51 
52 	/*static class Requestor extends TypeNameRequestor {
53 		int count = 0;
54 
55 		public void acceptType(int modifiers, char[] packageName, char[] simpleTypeName,
56 				char[][] enclosingTypeNames, String path) {
57 			count += 1;
58 		}
59 
60 		public boolean hasMatches() {
61 			return count > 0;
62 		}
63 	}*/
64 
isDiscouraged(String fullyQualifiedName, IJavaProject project, BundleDescription desc)65 	public static boolean isDiscouraged(String fullyQualifiedName, IJavaProject project, BundleDescription desc) {
66 		// allow classes within the project itself
67 		try {
68 			IType type = project.findType(fullyQualifiedName.replace('$', '.'));
69 			if (type != null && type.exists()) {
70 				HashMap<String, IPackageFragment> map = PDEJavaHelper.getPackageFragmentsHash(project,
71 						Collections.emptyList(), false);
72 				if (map.containsValue(type.getPackageFragment())) {
73 					return false;
74 				}
75 			}
76 		} catch (JavaModelException e) {
77 		}
78 
79 		// just grab the package
80 		int dot = fullyQualifiedName.lastIndexOf('.');
81 		if (dot != -1) {
82 			fullyQualifiedName = fullyQualifiedName.substring(0, dot);
83 		} else {
84 			fullyQualifiedName = "."; //$NON-NLS-1$
85 		}
86 
87 		State state = desc.getContainingState();
88 		StateHelper helper = state.getStateHelper();
89 		ExportPackageDescription[] exports = helper.getVisiblePackages(desc);
90 		for (ExportPackageDescription export : exports) {
91 			BundleDescription exporter = export.getExporter();
92 			if (exporter == null) {
93 				continue;
94 			}
95 
96 			if (fullyQualifiedName.equals(export.getName()) && helper.getAccessCode(desc, export) == StateHelper.ACCESS_DISCOURAGED) {
97 				return true;
98 			}
99 
100 		}
101 
102 		return false;
103 	}
104 
isOnClasspath(String fullyQualifiedName, IJavaProject project)105 	public static boolean isOnClasspath(String fullyQualifiedName, IJavaProject project) {
106 		if (fullyQualifiedName.indexOf('$') != -1) {
107 			fullyQualifiedName = fullyQualifiedName.replace('$', '.');
108 		}
109 		try {
110 			IType type = project.findType(fullyQualifiedName);
111 			return type != null && type.exists();
112 		} catch (JavaModelException e) {
113 		}
114 		return false;
115 		/*try {
116 			Requestor requestor = new Requestor();
117 			new SearchEngine().searchAllTypeNames(
118 					fullyQualifiedName.substring(0, fullyQualifiedName.lastIndexOf('.')).toCharArray(),
119 					SearchPattern.R_EXACT_MATCH|SearchPattern.R_CASE_SENSITIVE,
120 					fullyQualifiedName.substring(fullyQualifiedName.lastIndexOf('.') + 1).toCharArray(),
121 					SearchPattern.R_EXACT_MATCH|SearchPattern.R_CASE_SENSITIVE,
122 					IJavaSearchConstants.TYPE,
123 					SearchEngine.createJavaSearchScope(new IJavaElement[] {project}),
124 					requestor,
125 					IJavaSearchConstants.FORCE_IMMEDIATE_SEARCH,
126 					new NullProgressMonitor());
127 			return requestor.hasMatches();
128 		} catch (JavaModelException e) {
129 		}
130 		return false;*/
131 	}
132 
getSearchScope(IJavaProject project)133 	public static IJavaSearchScope getSearchScope(IJavaProject project) {
134 		return SearchEngine.createJavaSearchScope(getNonJRERoots(project));
135 	}
136 
getSearchScope(IProject project)137 	public static IJavaSearchScope getSearchScope(IProject project) {
138 		return getSearchScope(JavaCore.create(project));
139 	}
140 
getNonJRERoots(IJavaProject project)141 	public static IPackageFragmentRoot[] getNonJRERoots(IJavaProject project) {
142 		ArrayList<IPackageFragmentRoot> result = new ArrayList<>();
143 		try {
144 			IPackageFragmentRoot[] roots = project.getAllPackageFragmentRoots();
145 			for (int i = 0; i < roots.length; i++) {
146 				if (!isJRELibrary(roots[i])) {
147 					result.add(roots[i]);
148 				}
149 			}
150 		} catch (JavaModelException e) {
151 		}
152 		return result.toArray(new IPackageFragmentRoot[result.size()]);
153 	}
154 
isJRELibrary(IPackageFragmentRoot root)155 	public static boolean isJRELibrary(IPackageFragmentRoot root) {
156 		try {
157 			IPath path = root.getRawClasspathEntry().getPath();
158 			if (path.equals(new Path(JavaRuntime.JRE_CONTAINER)) || path.equals(new Path(JavaRuntime.JRELIB_VARIABLE))) {
159 				return true;
160 			}
161 		} catch (JavaModelException e) {
162 		}
163 		return false;
164 	}
165 
166 	/**
167 	 * @param packageName - the name of the package
168 	 * @param pluginID - the id of the containing plug-in - can be null if <code>project</code> is not null
169 	 * @param project - if null will search for an external package fragment, otherwise will search in project
170 	 */
getPackageFragment(String packageName, String pluginID, IProject project)171 	public static IPackageFragment getPackageFragment(String packageName, String pluginID, IProject project) {
172 		if (project == null) {
173 			return getExternalPackageFragment(packageName, pluginID);
174 		}
175 
176 		IJavaProject jp = JavaCore.create(project);
177 		if (jp != null) {
178 			try {
179 				IPackageFragmentRoot[] roots = jp.getAllPackageFragmentRoots();
180 				for (IPackageFragmentRoot root : roots) {
181 					IPackageFragment frag = root.getPackageFragment(packageName);
182 					if (frag.exists()) {
183 						return frag;
184 					}
185 				}
186 			} catch (JavaModelException e) {
187 			}
188 		}
189 		return null;
190 	}
191 
getExternalPackageFragment(String packageName, String pluginID)192 	private static IPackageFragment getExternalPackageFragment(String packageName, String pluginID) {
193 		if (pluginID == null) {
194 			return null;
195 		}
196 		IPluginModelBase base = null;
197 		try {
198 			IPluginModelBase plugin = PluginRegistry.findModel(pluginID);
199 			if (plugin == null) {
200 				return null;
201 			}
202 			ImportPackageSpecification[] packages = plugin.getBundleDescription().getImportPackages();
203 			for (ImportPackageSpecification spec : packages) {
204 				if (spec.getName().equals(packageName)) {
205 					ExportPackageDescription desc = (ExportPackageDescription) spec.getSupplier();
206 					if (desc != null) {
207 						base = PluginRegistry.findModel(desc.getExporter().getSymbolicName());
208 					}
209 					break;
210 				}
211 			}
212 			if (base == null) {
213 				return null;
214 			}
215 			IResource res = base.getUnderlyingResource();
216 			if (res != null) {
217 				IJavaProject jp = JavaCore.create(res.getProject());
218 				if (jp != null) {
219 					try {
220 						IPackageFragmentRoot[] roots = jp.getAllPackageFragmentRoots();
221 						for (IPackageFragmentRoot root : roots) {
222 							IPackageFragment frag = root.getPackageFragment(packageName);
223 							if (frag.exists()) {
224 								return frag;
225 							}
226 						}
227 					} catch (JavaModelException e) {
228 					}
229 				}
230 			}
231 			IProject proj = PDECore.getWorkspace().getRoot().getProject(SearchablePluginsManager.PROXY_PROJECT_NAME);
232 			if (proj == null) {
233 				return searchWorkspaceForPackage(packageName, base);
234 			}
235 			IJavaProject jp = JavaCore.create(proj);
236 			IPath path = new Path(base.getInstallLocation());
237 			// if model is in jar form
238 			if (!path.toFile().isDirectory()) {
239 				IPackageFragmentRoot root = jp.findPackageFragmentRoot(path);
240 				if (root != null) {
241 					IPackageFragment frag = root.getPackageFragment(packageName);
242 					if (frag.exists()) {
243 						return frag;
244 					}
245 				}
246 				// else model is in folder form, try to find model's libraries on filesystem
247 			} else {
248 				IPluginLibrary[] libs = base.getPluginBase().getLibraries();
249 				for (IPluginLibrary lib : libs) {
250 					if (IPluginLibrary.RESOURCE.equals(lib.getType())) {
251 						continue;
252 					}
253 					String libName = ClasspathUtilCore.expandLibraryName(lib.getName());
254 					IPackageFragmentRoot root = jp.findPackageFragmentRoot(path.append(libName));
255 					if (root != null) {
256 						IPackageFragment frag = root.getPackageFragment(packageName);
257 						if (frag.exists()) {
258 							return frag;
259 						}
260 					}
261 				}
262 			}
263 		} catch (JavaModelException e) {
264 		}
265 		return searchWorkspaceForPackage(packageName, base);
266 	}
267 
searchWorkspaceForPackage(String packageName, IPluginModelBase base)268 	private static IPackageFragment searchWorkspaceForPackage(String packageName, IPluginModelBase base) {
269 		IPluginLibrary[] libs = base.getPluginBase().getLibraries();
270 		ArrayList<IPath> libPaths = new ArrayList<>();
271 		IPath path = new Path(base.getInstallLocation());
272 		if (libs.length == 0) {
273 			libPaths.add(path);
274 		}
275 		for (IPluginLibrary lib : libs) {
276 			if (IPluginLibrary.RESOURCE.equals(lib.getType())) {
277 				continue;
278 			}
279 			String libName = ClasspathUtilCore.expandLibraryName(lib.getName());
280 			libPaths.add(path.append(libName));
281 		}
282 		IProject[] projects = PDECore.getWorkspace().getRoot().getProjects();
283 		for (int i = 0; i < projects.length; i++) {
284 			try {
285 				if (!projects[i].hasNature(JavaCore.NATURE_ID) || !projects[i].isOpen()) {
286 					continue;
287 				}
288 				IJavaProject jp = JavaCore.create(projects[i]);
289 				ListIterator<IPath> li = libPaths.listIterator();
290 				while (li.hasNext()) {
291 					IPackageFragmentRoot root = jp.findPackageFragmentRoot(li.next());
292 					if (root != null) {
293 						IPackageFragment frag = root.getPackageFragment(packageName);
294 						if (frag.exists()) {
295 							return frag;
296 						}
297 					}
298 				}
299 			} catch (CoreException e) {
300 			}
301 		}
302 		return null;
303 	}
304 
getPackageFragments(IJavaProject jProject, Collection<?> existingPackages, boolean allowJava)305 	public static IPackageFragment[] getPackageFragments(IJavaProject jProject, Collection<?> existingPackages, boolean allowJava) {
306 		// for unique package fragments, use getPackageFragmentsHash2
307 		HashMap<String, IPackageFragment> map = getPackageFragmentsHash2(jProject, existingPackages, allowJava);
308 		return map.values().toArray(new IPackageFragment[map.size()]);
309 	}
310 
getPackageFragmentsHash(IJavaProject jProject, Collection<?> existingPackages, boolean allowJava)311 	public static HashMap<String, IPackageFragment> getPackageFragmentsHash(IJavaProject jProject, Collection<?> existingPackages, boolean allowJava) {
312 		HashMap<String, IPackageFragment> map = new LinkedHashMap<>();
313 		try {
314 			IPackageFragmentRoot[] roots = getRoots(jProject);
315 			for (IPackageFragmentRoot root : roots) {
316 				IJavaElement[] children = root.getChildren();
317 				for (IJavaElement element : children) {
318 					IPackageFragment fragment = (IPackageFragment) element;
319 					String name = fragment.getElementName();
320 					if (name.length() == 0) {
321 						name = "."; //$NON-NLS-1$
322 					}
323 					if ((fragment.hasChildren() || fragment.getNonJavaResources().length > 0) && !existingPackages.contains(name)) {
324 						if (!name.equals("java") || !name.startsWith("java.") || allowJava) { //$NON-NLS-1$ //$NON-NLS-2$
325 							map.put(fragment.getElementName(), fragment);
326 						}
327 					}
328 				}
329 			}
330 		} catch (JavaModelException e) {
331 		}
332 		return map;
333 	}
getPackageFragmentsHash2(IJavaProject jProject, Collection<?> existingPackages, boolean allowJava)334 	public static HashMap<String, IPackageFragment> getPackageFragmentsHash2(IJavaProject jProject, Collection<?> existingPackages, boolean allowJava) {
335 		HashMap<String, IPackageFragment> map = new LinkedHashMap<>();
336 		try {
337 			IPackageFragmentRoot[] roots = getRoots(jProject);
338 			for (IPackageFragmentRoot root : roots) {
339 				IJavaElement[] children = root.getChildren();
340 				for (IJavaElement element : children) {
341 					IPackageFragment fragment = (IPackageFragment) element;
342 					String name = fragment.getElementName();
343 					if (name.length() == 0) {
344 						name = "."; //$NON-NLS-1$
345 					}
346 					if ((fragment.hasChildren() || fragment.getNonJavaResources().length > 0) && !existingPackages.contains(name)) {
347 						if (!name.equals("java") || !name.startsWith("java.") || allowJava) { //$NON-NLS-1$ //$NON-NLS-2$
348 							map.put(fragment.getPath().makeRelative() + "_" + fragment.getElementName(), fragment); //$NON-NLS-1$
349 						}
350 					}
351 				}
352 			}
353 		} catch (JavaModelException e) {
354 		}
355 		return map;
356 	}
357 
getRoots(IJavaProject jProject)358 	private static IPackageFragmentRoot[] getRoots(IJavaProject jProject) {
359 		ArrayList<IPackageFragmentRoot> result = new ArrayList<>();
360 		try {
361 			IPackageFragmentRoot[] roots = jProject.getPackageFragmentRoots();
362 			for (int i = 0; i < roots.length; i++) {
363 				if (roots[i].getKind() == IPackageFragmentRoot.K_SOURCE || jProject.getProject().equals(roots[i].getCorrespondingResource()) || (roots[i].isArchive() && !roots[i].isExternal())) {
364 					result.add(roots[i]);
365 				}
366 			}
367 		} catch (JavaModelException e) {
368 		}
369 		return result.toArray(new IPackageFragmentRoot[result.size()]);
370 	}
371 
getJavaSourceLevel(IProject project)372 	public static String getJavaSourceLevel(IProject project) {
373 		return getJavaLevel(project, JavaCore.COMPILER_SOURCE);
374 	}
375 
getJavaComplianceLevel(IProject project)376 	public static String getJavaComplianceLevel(IProject project) {
377 		return getJavaLevel(project, JavaCore.COMPILER_COMPLIANCE);
378 	}
379 
380 	/**
381 	 * Precedence order from high to low:  (1) Project specific option;
382 	 * (2) General preference option; (3) Default option; (4) Java 1.3
383 	 * @param project
384 	 * @param optionName
385 	 */
getJavaLevel(IProject project, String optionName)386 	public static String getJavaLevel(IProject project, String optionName) {
387 		// Returns the corresponding java project
388 		// No need to check for null, will return null
389 		IJavaProject javaProject = JavaCore.create(project);
390 		String value = null;
391 		// Preferred to use the project
392 		if ((javaProject != null) && javaProject.exists()) {
393 			// Get the project specific option if one exists. Rolls up to the
394 			// general preference option if no project specific option exists.
395 			value = javaProject.getOption(optionName, true);
396 			if (value != null) {
397 				return value;
398 			}
399 		}
400 		// Get the general preference option
401 		value = new PDEPreferencesManager(JavaCore.PLUGIN_ID).getString(optionName);
402 		if (value != null) {
403 			return value;
404 		}
405 		// Get the default option
406 		value = JavaCore.getOption(optionName);
407 		if (value != null) {
408 			return value;
409 		}
410 		// Return the default
411 		return JavaCore.VERSION_1_3;
412 	}
413 
414 }
415