All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.anwiba.eclipse.project.dependency.runner.WorkspaceDependenciesInvestigator Maven / Gradle / Ivy

/*
 * #%L
 * anwiba commons core
 * %%
 * Copyright (C) 2007 - 2017 Andreas Bartels
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 2.1 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

package net.anwiba.eclipse.project.dependency.runner;

import net.anwiba.commons.eclipse.logging.ILogger;
import net.anwiba.commons.internal.eclipse.logging.Level;
import net.anwiba.commons.lang.object.ObjectUtilities;
import net.anwiba.commons.thread.cancel.ICanceler;
import net.anwiba.eclipse.project.dependency.internal.java.Dependency;
import net.anwiba.eclipse.project.dependency.internal.java.Import;
import net.anwiba.eclipse.project.dependency.internal.java.Library;
import net.anwiba.eclipse.project.dependency.internal.java.Package;
import net.anwiba.eclipse.project.dependency.internal.java.Path;
import net.anwiba.eclipse.project.dependency.internal.java.Project;
import net.anwiba.eclipse.project.dependency.internal.java.Type;
import net.anwiba.eclipse.project.dependency.internal.java.WorkspaceBuilder;
import net.anwiba.eclipse.project.dependency.java.IImport;
import net.anwiba.eclipse.project.dependency.java.ILibrary;
import net.anwiba.eclipse.project.dependency.java.IPath;
import net.anwiba.eclipse.project.dependency.java.IWorkspace;
import net.anwiba.eclipse.project.dependency.java.LibraryType;
import net.anwiba.eclipse.project.dependency.java.TypeType;
import net.anwiba.eclipse.project.dependency.object.ItemType;
import net.anwiba.eclipse.project.name.INameCollector;

import java.net.URI;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IImportDeclaration;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.internal.core.ExternalPackageFragmentRoot;
import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;

@SuppressWarnings("restriction")
public final class WorkspaceDependenciesInvestigator {

  private final INameCollector nameCollector;
  private final IJavaModel model;
  private final ILogger logger;
  private final IWorkspace previousInvestigatedWorkspace;
  private final INameHitMaps nameHitMaps;

  public WorkspaceDependenciesInvestigator(
    final IWorkspace previousInvestigatedWorkspace,
    final ILogger logger,
    final IJavaModel model,
    final INameHitMaps nameHitMaps) {
    this.previousInvestigatedWorkspace = previousInvestigatedWorkspace;
    this.logger = logger;
    this.model = model;
    this.nameHitMaps = nameHitMaps;
    this.nameCollector = new NameCollector(nameHitMaps);
  }

  public IWorkspace investigate(final IProgressMonitor monitor, final ICanceler canceler)
      throws JavaModelException,
        InterruptedException {
    this.nameHitMaps.reset();
    final URI locationURI = this.model.getWorkspace().getRoot().getLocationURI();
    final WorkspaceBuilder builder = new WorkspaceBuilder(locationURI);
    // addLibraries(builder);
    if (canceler.isCanceled()) {
      throw new InterruptedException();
    }
    addProjects(monitor, canceler, builder);
    addDependencies(monitor, canceler, builder);
    monitor.subTask("build dependencies"); //$NON-NLS-1$
    final IWorkspace workspace = builder.build();
    return workspace;
  }

  private void addDependencies(final IProgressMonitor monitor, final ICanceler canceler, final WorkspaceBuilder builder)
      throws JavaModelException,
        InterruptedException {
    for (final IJavaProject javaProject : this.model.getJavaProjects()) {
      final String message = MessageFormat.format("scanne dependencies for project {0}", javaProject.getElementName()); //$NON-NLS-1$
      this.logger.log(Level.INFO, message);
      monitor.subTask(message);
      final Project project = builder.getProject(javaProject.getPath().toPortableString());
      if (project == null) {
        continue;
      }
      final Set libraries = new HashSet<>();
      ClasspathCollector.collect(canceler, libraries, project);
      for (final IClasspathEntry classpathEntry : javaProject.getRawClasspath()) {
        if (canceler.isCanceled()) {
          throw new InterruptedException();
        }
        final int entryKind = classpathEntry.getEntryKind();
        switch (entryKind) {
          case IClasspathEntry.CPE_LIBRARY:
          case IClasspathEntry.CPE_PROJECT: {
            final org.eclipse.core.runtime.IPath path = classpathEntry.getPath();
            final Library library = builder.getLibrary(path.toPortableString());
            if (library == null || libraries.contains(library)) {
              continue;
            }
            ClasspathCollector.collect(canceler, libraries, library);
            if (libraries.contains(project)) {
              final String submessage =
                  MessageFormat.format("dependencies for project {0} builds cycle over library {1}", //$NON-NLS-1$
                      javaProject.getElementName(), library.getName());
              this.logger.log(Level.ERROR, submessage);
              this.logger.log(Level.ERROR, ObjectUtilities.toString(library));
              throw new JavaModelException(new Exception(submessage), IStatus.ERROR);
            }
            libraries.add(library);
            project.getDependencies().add(new Dependency(library, classpathEntry.isExported()));
            break;
          }
          case IClasspathEntry.CPE_CONTAINER: {
            break;
          }
          case IClasspathEntry.CPE_SOURCE: {
            break;
          }
          case IClasspathEntry.CPE_VARIABLE: {
            break;
          }
          default:
            break;
        }
        project.setClasspath(libraries);
      }
    }
  }

  private void addProjects(final IProgressMonitor monitor, final ICanceler canceler, final WorkspaceBuilder builder)
      throws JavaModelException,
        InterruptedException {
    for (final IJavaProject javaProject : this.model.getJavaProjects()) {
      final String elementName = javaProject.getElementName();
      final String message = MessageFormat.format("scanne content for project {0}", elementName); //$NON-NLS-1$
      this.logger.log(Level.INFO, message);
      monitor.subTask(message);
      final Project project =
          new Project(javaProject.getPath().toPortableString(), javaProject.getProject().getLocationURI());
      builder.add(project);
      adjust(monitor, canceler, builder, project, null, javaProject.getChildren());
    }
  }

  // private void addLibraries(final WorkspaceBuilder builder) {
  // if (this.previousInvestigatedWorkspace != null) {
  // for (final String key : this.previousInvestigatedWorkspace.getLibraries().keySet()) {
  // final Library library = (Library) this.previousInvestigatedWorkspace.getLibraries().get(key);
  // if (library == null || LibraryType.PROJECT.equals(library.getLibraryType())) {
  // continue;
  // }
  // library.reset();
  // builder.add(library);
  // }
  // }
  // }

  private void adjust(
      final IProgressMonitor monitor,
      final ICanceler canceler,
      final WorkspaceBuilder builder,
      final Library library,
      final Path path,
      final IJavaElement... children) throws InterruptedException {
    final String message = MessageFormat.format("scanne content dependencies for library {0}", library.getName()); //$NON-NLS-1$
    // this.logger.log(Level.INFO, message);
    monitor.subTask(message);
    for (final IJavaElement javaElement : children) {
      if (canceler.isCanceled()) {
        throw new InterruptedException();
      }
      if (javaElement.getElementName().length() == 0) {
        continue;
      }
      final ItemType itemType = ItemType.getByElementType(javaElement.getElementType());
      try {
        switch (itemType) {
          case PACKAGE_ROOT: {
            if (javaElement instanceof ExternalPackageFragmentRoot) {
              break;
            }
            if (javaElement instanceof JarPackageFragmentRoot) {
              final JarPackageFragmentRoot jarPackageFragmentRoot = (JarPackageFragmentRoot) javaElement;
              final org.eclipse.core.runtime.IPath jarPath = jarPackageFragmentRoot.getPath();
              if (builder.getLibrary(jarPath.toPortableString()) != null) {
                library.add(new Dependency(builder.getLibrary(jarPath.toPortableString()), false));
                break;
              }
              final Library jarFile = new Library(jarPath.toPortableString(), LibraryType.JAR);
              builder.add(jarFile);
              library.add(new Dependency(jarFile, false));
              adjust(monitor, canceler, builder, jarFile, null, jarPackageFragmentRoot.getChildren());
              monitor.subTask(message);
              break;
            }
            final IPackageFragmentRoot fragmentRoot = (IPackageFragmentRoot) javaElement;
            final IJavaElement[] children2 = fragmentRoot.getChildren();
            adjust(monitor, canceler, builder, library, null, children2);
            break;
          }
          case PACKAGE: {
            final IPackageFragment packagFragment = (IPackageFragment) javaElement;
            if (path == null) {
              final Path packagePath = create(path, packagFragment.getElementName());
              final Package pakkage = new Package(library, packagePath);
              builder.add(pakkage);
              adjust(monitor, canceler, builder, library, packagePath, packagFragment.getChildren());
              break;
            }
            adjust(monitor, canceler, builder, library, create(path, packagFragment
                .getPath()
                .lastSegment()), packagFragment.getChildren());
            break;
          }
          case CLASS: {
            if (!(javaElement instanceof IClassFile)) {
              continue;
            }
            final IClassFile classFile = (IClassFile) javaElement;
            final Package pakkage = builder.getPackage(path.getIdentifier());
            try {
              final IJavaElement[] childrens = classFile.getChildren();
              for (final IJavaElement element : childrens) {
                if (!(element instanceof IType)) {
                  continue;
                }
                final IType type = (IType) element;
                adjust(monitor, canceler, builder, library, pakkage, type, new IImportDeclaration[0]);
              }

            } catch (final Exception e) {
              this.logger.log(Level.WARNING, MessageFormat
                  .format("{0}\n\t scanning java element ''{1}.{2} type {3}'' faild", message, pakkage
                      .getName(), classFile.getElementName(), classFile.getType().getElementName()));
            }
            break;
          }
          case COMPILATION_UNIT: {
            if (!(javaElement instanceof ICompilationUnit)) {
              continue;
            }
            final ICompilationUnit compilationUnit = (ICompilationUnit) javaElement;
            final Package pakkage = builder.getPackage(path.getIdentifier());

            for (final IType type : compilationUnit.getTypes()) {
              this.nameCollector.add(type.getElementName());
              adjust(monitor, canceler, builder, library, pakkage, type, compilationUnit.getImports());
            }
            break;
          }
          case TYPE: {
            throw new RuntimeException("Unreachable code reached"); //$NON-NLS-1$
          }
          case UNKOWN: {
            break;
          }
        }

      } catch (final JavaModelException exception) {
        this.logger.log(Level.WARNING, MessageFormat
            .format("scanning java element ''{0}'' type {1} faild", javaElement.getElementName(), itemType.name()), //$NON-NLS-1$
            exception);
      }
    }
  }

  private void adjust(
      final IProgressMonitor monitor,
      final ICanceler cancler,
      final WorkspaceBuilder builder,
      final Library library,
      final Package pakkage,
      final IType typeElement,
      final IImportDeclaration[] imports) throws InterruptedException {
    if (cancler.isCanceled()) {
      throw new InterruptedException();
    }
    if (typeElement.getElementName().length() == 0) {
      return;
    }
    final Path path = create(null, typeElement.getFullyQualifiedName());
    final List importedTypes = getImportedTypes(imports);
    final List annotations = getAnnotations(typeElement);
    try {
      final List superTypes = getSuperTypes(typeElement, importedTypes, path);
      final Set methodTypes = getMethodTypes(typeElement, importedTypes, path);
      final Set annotationTypes = getAnnotationTypes(annotations, importedTypes, path);
      final Type type = new Type(library, path, pakkage, typeElement.getElementName(), typeElement.isInterface()
          ? TypeType.INTERFACE
          : TypeType.CLASS, importedTypes, superTypes, methodTypes, annotationTypes);
      builder.add(type);
      for (final IType childType : typeElement.getTypes()) {
        adjust(monitor, cancler, builder, library, pakkage, childType, imports);
      }
    } catch (final JavaModelException exception) {
      this.logger
          .log(Level.WARNING, MessageFormat.format("scanning java element ''{0}'' faild", typeElement.getElementName()), //$NON-NLS-1$
              exception);
      final Type type = new Type(
          library,
          path,
          pakkage,
          typeElement.getElementName(),
          TypeType.CLASS,
          importedTypes,
          new ArrayList(),
          new HashSet(),
          new HashSet());
      builder.add(type);
    }
  }

  private List getAnnotations(final IType typeElement) {
    try {
      return Arrays.asList(typeElement.getAnnotations());

    } catch (final JavaModelException exception) {
      return new ArrayList<>();
    }
  }

  private List getImportedTypes(final IImportDeclaration[] importDeclarations) {
    final List importedTypes = new ArrayList<>();
    for (final IImportDeclaration importDeclaration : importDeclarations) {
      final String importName = importDeclaration.getElementName();
      final Path importPath = create(null, importName);
      importedTypes.add(new Import(importName, importName.endsWith("*") //$NON-NLS-1$
          ? importPath.getParent()
          : importPath));
    }
    return importedTypes;
  }

  private Set getMethodTypes(final IType typeElement, final List imports, final Path path)
      throws JavaModelException {
    final IMethod[] methods = typeElement.getMethods();
    final Set methodTypes = new HashSet<>();
    for (final IMethod method : methods) {
      final String returnType = method.getReturnType();
      addToPaths(imports, path, methodTypes, returnType);
      final String[] parameterTypes = method.getParameterTypes();
      for (final String parameterType : parameterTypes) {
        addToPaths(imports, path, methodTypes, parameterType);
      }
      final String[] exceptionTypes = method.getExceptionTypes();
      for (final String exceptionType : exceptionTypes) {
        addToPaths(imports, path, methodTypes, exceptionType);
      }
    }
    return methodTypes;
  }

  private void addToPaths(
      final List imports,
      final Path path,
      final Set paths,
      final String parameterType) {
    String signatureSimpleName;
    signatureSimpleName = Signature.getSignatureSimpleName(parameterType);
    if ("void".equals(signatureSimpleName)) { //$NON-NLS-1$
      return;
    }
    paths.add(createTypePath(imports, path, signatureSimpleName));
  }

  private Set getAnnotationTypes(
      final List annotations,
      final List imports,
      final Path path) {
    final Set annotationPaths = new HashSet<>();
    for (final IAnnotation annotation : annotations) {
      final String qualifiedName = annotation.getElementName();
      annotationPaths.add(createTypePath(imports, path, qualifiedName));
    }
    return annotationPaths;
  }

  private List getSuperTypes(final IType typeElement, final List imports, final Path path)
      throws JavaModelException {
    final String superclassName = typeElement.getSuperclassName();
    final List superTypes = new ArrayList<>();
    if (superclassName != null) {
      final IPath superTypePath = createTypePath(imports, path, superclassName);
      superTypes.add(superTypePath);
    }
    final String[] superInterfaceNames = typeElement.getSuperInterfaceNames();
    for (final String superInterfaceName : superInterfaceNames) {
      final IPath createSuperTypePath = createTypePath(imports, path, superInterfaceName);
      createSuperTypePath.getClass();
      superTypes.add(createSuperTypePath);
    }
    return superTypes;
  }

  private IPath createTypePath(final List imports, final Path path, final String typeName) {
    if (typeName == null) {
      return null;
    }
    final String name = removeGenerics(typeName);
    Path dummy = create(null, name);
    if (dummy.getParent().isEmpty() && !path.getParent().isEmpty()) {
      for (final IImport impcrt : imports) {
        if (name.equals(impcrt.getPath().lastSegment())) {
          return impcrt.getPath();
        }
      }
      dummy = create((Path) path.getParent(), name);
      return dummy;
    }
    return dummy;
  }

  private String removeGenerics(final String name) {
    if (!name.contains("<")) { //$NON-NLS-1$
      return name;
    }
    return name.substring(0, name.indexOf('<'));
  }

  private Path create(final Path path, final String segment) {
    if (path == null) {
      final StringTokenizer tokenizer = new StringTokenizer(segment, "."); //$NON-NLS-1$
      final List tokens = new ArrayList<>();
      while (tokenizer.hasMoreElements()) {
        tokens.add(tokenizer.nextToken());
      }
      return new Path(tokens.toArray(new String[tokens.size()]));
    }
    final String[] segements = path.getSegments();
    final String[] result = new String[segements.length + 1];
    System.arraycopy(segements, 0, result, 0, segements.length);
    result[segements.length] = segment;
    return new Path(result);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy