Java tutorial
/******************************************************************************* * Copyright (c) 2014 Willink Transformations and others. * All rights reserved. This program and the accompanying materials * are 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: * E.D.Willink - initial API and implementation *******************************************************************************/ package org.eclipse.ocl.xtext.oclstdlib.scoping; import static java.util.Collections.emptySet; import static java.util.Collections.singleton; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IParent; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.ocl.pivot.utilities.ClassUtil; import org.eclipse.ocl.xtext.base.scoping.AbstractJavaClassScope; import org.eclipse.ocl.xtext.base.utilities.BaseCSResource; import org.eclipse.ocl.xtext.oclstdlibcs.JavaClassCS; import org.eclipse.ocl.xtext.oclstdlibcs.JavaImplementationCS; import org.eclipse.ocl.xtext.oclstdlibcs.OCLstdlibCSFactory; import org.eclipse.xtext.naming.QualifiedName; import org.eclipse.xtext.resource.EObjectDescription; import org.eclipse.xtext.resource.IEObjectDescription; import org.osgi.framework.Bundle; import org.osgi.framework.BundleReference; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; /** * A JavaClassScope supports lookup of Java class names from the OCLstdlib editor. Names are resolved against * a local cache. All names for completion assist are resolved against the full classpath. *<p> * This provides much less functionality that the Xtext JdtBased/ClasspathBased TypeScopes, but much less is * all that is needed. */ public class JavaClassScope extends AbstractJavaClassScope { // private static final Logger logger = Logger.getLogger(JavaClassScope.class); public static @NonNull JavaClassScope getAdapter(@NonNull BaseCSResource csResource, @NonNull ClassLoader classLoader) { AbstractJavaClassScope adapter = ClassUtil.getAdapter(AbstractJavaClassScope.class, csResource); if (adapter == null) { adapter = new JavaClassScope(classLoader); csResource.eAdapters().add(adapter); } return (JavaClassScope) adapter; } public static @NonNull JavaClassScope getAdapter(@NonNull BaseCSResource csResource, @NonNull IProject project) { AbstractJavaClassScope adapter = ClassUtil.getAdapter(AbstractJavaClassScope.class, csResource); if (adapter == null) { adapter = new JavaClassScope(project); csResource.eAdapters().add(adapter); } return (JavaClassScope) adapter; } /** * ClassLoader to help resolve references in a non Eclipse context. */ private final @Nullable ClassLoader classLoader; /** * IProject to help resolve references in an Eclipse context. */ private final @Nullable IProject project; /** * Map from known class names to their allocated EObjects. */ private final @NonNull Map<String, JavaClassCS> name2class = new HashMap<String, JavaClassCS>(); private boolean doneFullScan = false; public JavaClassScope(@NonNull ClassLoader classLoader) { this.classLoader = classLoader; this.project = null; } public JavaClassScope(@NonNull IProject project) { this.classLoader = null; this.project = project; } @Override public void getAdapter(@NonNull BaseCSResource importedResource) { if (classLoader != null) { getAdapter(importedResource, classLoader); } else if (project != null) { getAdapter(importedResource, project); } } @Override protected Iterable<IEObjectDescription> getAllLocalElements() { // if (true) throw new UnsupportedOperationException(); Set<String> classNames; if (doneFullScan) { classNames = name2class.keySet(); } else { doneFullScan = true; classNames = new HashSet<String>(65536); if (classLoader instanceof BundleReference) { Bundle bundle = ((BundleReference) classLoader).getBundle(); IProject iProject = ResourcesPlugin.getWorkspace().getRoot().getProject(bundle.getSymbolicName()); IJavaProject javaProject = JavaCore.create(iProject); try { // IClasspathEntry[] resolvedClasspath = javaProject.getResolvedClasspath(true); // scanClassPath(resolvedClasspath, classNames); IPackageFragmentRoot[] packageFragmentRoots = javaProject.getAllPackageFragmentRoots(); scanJavaElements(packageFragmentRoots, classNames); } catch (JavaModelException e) { } } else if (project != null) { IJavaProject javaProject = JavaCore.create(project); try { IPackageFragmentRoot[] packageFragmentRoots = javaProject.getAllPackageFragmentRoots(); scanJavaElements(packageFragmentRoots, classNames); } catch (JavaModelException e) { } } else { // scanClassPath(classNames); // scanBundles(classNames); } } List<String> sortedNames = new ArrayList<String>(classNames); Collections.sort(sortedNames); List<IEObjectDescription> results = new ArrayList<IEObjectDescription>(); for (String className : sortedNames) { if (className != null) { results.add(getEObjectDescription(className)); } } return results; } protected IEObjectDescription getEObjectDescription(@NonNull String name) { JavaClassCS csJavaClass; synchronized (name2class) { csJavaClass = name2class.get(name); if (csJavaClass == null) { csJavaClass = OCLstdlibCSFactory.eINSTANCE.createJavaClassCS(); csJavaClass.setName(name); name2class.put(name, csJavaClass); } } return EObjectDescription.create(name, csJavaClass); } @Override public Iterable<IEObjectDescription> getElements(QualifiedName name) { IEObjectDescription result = getSingleElement(name); if (result != null) return singleton(result); return emptySet(); } @Override protected Iterable<IEObjectDescription> getLocalElementsByEObject(EObject object, URI uri) { QualifiedName qualifiedName = QualifiedName.create(((JavaClassCS) object).getName()); return Collections.singletonList(EObjectDescription.create(qualifiedName, object)); } @Override protected Iterable<IEObjectDescription> getLocalElementsByName(final QualifiedName name) { Iterable<IEObjectDescription> localElements = getAllLocalElements(); Iterable<IEObjectDescription> result = Iterables.filter(localElements, new Predicate<IEObjectDescription>() { @Override public boolean apply(IEObjectDescription input) { if (isIgnoreCase()) { QualifiedName lowerCase = name.toLowerCase(); QualifiedName inputLowerCase = input.getName().toLowerCase(); return lowerCase.equals(inputLowerCase); } else { return name.equals(input.getName()); } } }); return result; } @Override public IEObjectDescription getSingleElement(QualifiedName qualifiedName) { String name = qualifiedName.toString(); if (name == null) { return null; } JavaClassCS csJavaClass = name2class.get(name); if (csJavaClass == null) { ClassLoader classLoader2 = classLoader; if (classLoader2 != null) { try { Class<?> loadClass = classLoader2.loadClass(name); if (loadClass == null) { return null; } } catch (ClassNotFoundException e) { return null; } } IProject project2 = project; if (project2 != null) { IJavaProject javaProject = JavaCore.create(project2); try { IType type = javaProject.findType(name); if (type == null) { return null; } } catch (JavaModelException e) { return null; } } } return getEObjectDescription(name); } /** * Refresh the known classes in the CS Resource root. */ @Override public void installContents(@NonNull BaseCSResource csResource) { Set<JavaClassCS> javaClasses = new HashSet<JavaClassCS>(); EList<EObject> contents = csResource.getContents(); for (int i = contents.size(); --i >= 0;) { EObject eObject = contents.get(i); if (eObject instanceof JavaClassCS) { contents.remove(i); } } for (TreeIterator<EObject> tit = csResource.getAllContents(); tit.hasNext();) { EObject eObject = tit.next(); if (eObject instanceof JavaImplementationCS) { JavaClassCS implementation = ((JavaImplementationCS) eObject).getImplementation(); if (implementation != null) { javaClasses.add(implementation); } } } contents.addAll(javaClasses); } protected @Nullable String resolveClassName(@NonNull String name) { if (!name.endsWith(".class")) { return null; } String className = name.substring(0, name.length() - 6); int dollarIndex = className.lastIndexOf('$'); if ((dollarIndex <= 0) || (className.length() <= dollarIndex + 1) || !Character.isDigit(className.charAt(dollarIndex + 1))) { return className.replace("/", "."); } else { return null; } } /* private void scanJar(@NonNull File file, @NonNull Set<String> classNames) { // System.out.println("registerBundle " + file); JarFile jarFile = null; try { jarFile = new JarFile(file); for (Enumeration<JarEntry> jarEntries = jarFile.entries(); jarEntries.hasMoreElements(); ) { JarEntry jarEntry = jarEntries.nextElement(); if (!jarEntry.isDirectory()) { String name = jarEntry.getName(); if (name != null) { // System.out.println(" entry " + name); String className = resolveClassName(name); if (className != null) { classNames.add(className); } } } } } catch (Exception e) { } finally{ if (jarFile != null) { try { jarFile.close(); } catch (IOException e) {} } } } */ /* protected @Nullable IProjectDescriptor registerProject(@NonNull File file) { System.out.println("registerProject " + file); FileInputStream inputStream = null; try { inputStream = new FileInputStream(file); Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream); String project = document.getDocumentElement().getElementsByTagName("name").item(0).getTextContent(); if (project != null) { @SuppressWarnings("null")@NonNull URI locationURI = URI.createFileURI(file.getParentFile().getCanonicalPath() + File.separator); // IProjectDescriptor projectDescriptor = createProjectDescriptor(project, locationURI); // project2descriptor.put(project, projectDescriptor); return null; } } catch (Exception e) { logException("Couldn't read '" + file + "'", e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { } } } return null; } */ /* private void scanBundles(@NonNull Set<String> classNames) { for (IBundleGroupProvider bundleGroupProvider : Platform.getBundleGroupProviders()) { for (IBundleGroup bundleGroup : bundleGroupProvider.getBundleGroups()) { for (Bundle bundle : bundleGroup.getBundles()) { try { String bundleName = bundle.getSymbolicName(); if (bundleName != null) { String location = bundle.getLocation(); // System.out.println(bundleName + " => " + location); if (location.startsWith("reference:")) { location = location.substring(10); } else { logger.warn("Unknown bundle location " + location); } java.net.URI locationURI = new java.net.URI(location); File file = URIUtil.toFile(locationURI); if (file != null) { if (location.endsWith(".jar")) { scanJar(file, classNames); } else { scanFolder(file, classNames, "", bundleName); } } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } */ /* private void scanClassPath(@NonNull IClasspathEntry @NonNull [] resolvedClasspath, @NonNull Set<String> classNames) { // String property = System.getProperty("java.class.path"); // String separator = System.getProperty("path.separator"); // if (property != null) { // String[] entries = property.split(separator); // for (String entry : entries) { for (IClasspathEntry classpathEntry : resolvedClasspath) { int entryKind = classpathEntry.getEntryKind(); if (entryKind == IClasspathEntry.CPE_SOURCE) { IPath path = classpathEntry.getPath(); File fileEntry = path.toFile(); try { File f = fileEntry.getCanonicalFile(); if (f.getPath().endsWith(".jar")) { scanJar(f, classNames); } else { scanFolder(f, classNames, "", path.toString()); // } // eclipse bin folder? /* File parentFile = f.getParentFile(); File dotProject = new File(parentFile, ".project"); if (dotProject.exists()) { IProjectDescriptor projectDescriptor = registerProject(dotProject); if (projectDescriptor != null) { File plugIn = new File(parentFile, "plugin.xml"); if (plugIn.exists()) { PluginReader pluginReader = new PluginReader(projectDescriptor); saxParser.parse(plugIn, pluginReader); pluginReader.scanContents(saxParser); } } } * / } } catch (Exception e) {} } } } */ /* protected boolean scanFolder(@NonNull File f, @NonNull Set<String> alreadyVisited, int depth) { try { if (!alreadyVisited.add(f.getCanonicalPath())) return true; } catch (Exception e) { logException("Failed to scan '" + f + "'", e); return true; } File[] files = f.listFiles(); boolean containsProject = false; File dotProject = null; if (files != null) { for (File file : files) { if (file.exists() && file.isDirectory() && (depth < 2) && !file.getName().startsWith(".")) { containsProject |= scanFolder(file, alreadyVisited, depth + 1); } else if (".project".equals(file.getName())) { dotProject = file; } else if (file.getName().endsWith(".jar")) { scanJar(file); } } } if (!containsProject && dotProject != null) registerProject(dotProject); return containsProject || dotProject != null; } */ /* private void scanFolder(@NonNull File folder, @NonNull Set<String> classNames, @NonNull String prefix, @NonNull String bundle) { // System.out.println("scanFolder " + folder); File[] files = folder.listFiles(); if (files != null) { for (File file : files) { if (file.exists()) { String name = file.getName(); if (name != null) { int prefixLength = prefix.length(); if (file.isDirectory()) { if ((prefixLength < 10000) && !file.getName().startsWith(".")) { if (prefixLength > 0) { scanFolder(file, classNames, prefix + "." + name, bundle); } else if (bundle.startsWith(name)) { scanFolder(file, classNames, name, bundle); } else { // Skip over output path scanFolder(file, classNames, prefix, bundle); } } } else { // System.out.println(" entry " + name); String className = resolveClassName(name); if (className != null) { System.out.println(" entry " + prefix + "." + className); classNames.add(prefix + "." + className); } } } } } } } */ private void scanJavaElements(IJavaElement[] elements, Set<String> classNames) { for (IJavaElement element : elements) { // System.out.println(getClass().getSimpleName() + " : " + element); if (element instanceof IType) { IType iType = (IType) element; classNames.add(iType.getFullyQualifiedName()); try { if (iType.hasChildren()) { scanJavaElements(iType.getChildren(), classNames); } } catch (JavaModelException e) { } } else if ((element instanceof IParent) && !(element instanceof IMember)) { try { IParent iParent = (IParent) element; if (iParent.hasChildren()) { scanJavaElements(iParent.getChildren(), classNames); } } catch (JavaModelException e) { } } } } }