org.eclipse.ocl.xtext.oclstdlib.scoping.JavaClassScope.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ocl.xtext.oclstdlib.scoping.JavaClassScope.java

Source

/*******************************************************************************
 * 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) {
                }
            }
        }
    }
}