/******************************************************************************* | |
* Copyright (c) 2009, 2019 Mia-Software and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License v2.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/epl-v20.html | |
* | |
* Contributors: | |
* Sebastien Minguet (Mia-Software) - initial API and implementation | |
* Frederic Madiot (Mia-Software) - initial API and implementation | |
* Fabien Giquel (Mia-Software) - initial API and implementation | |
* Gabriel Barbier (Mia-Software) - initial API and implementation | |
* Erwan Breton (Sodifrance) - initial API and implementation | |
* Romain Dervaux (Mia-Software) - initial API and implementation | |
* Nicolas Bros (Mia-Software) - Bug 335003 - [Discoverer] : Existing Discoverers Refactoring based on new framework | |
*******************************************************************************/ | |
package org.eclipse.modisco.java.discoverer; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.HashMap; | |
import java.util.LinkedHashSet; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Map.Entry; | |
import java.util.Set; | |
import org.eclipse.core.resources.IProject; | |
import org.eclipse.core.runtime.IProgressMonitor; | |
import org.eclipse.emf.common.util.URI; | |
import org.eclipse.jdt.core.IJavaProject; | |
import org.eclipse.jdt.core.IPackageFragmentRoot; | |
import org.eclipse.jdt.core.JavaModelException; | |
import org.eclipse.modisco.infra.common.core.logging.MoDiscoLogger; | |
import org.eclipse.modisco.infra.discovery.core.annotations.Parameter; | |
import org.eclipse.modisco.java.Model; | |
import org.eclipse.modisco.java.discoverer.internal.IModelReader; | |
import org.eclipse.modisco.java.discoverer.internal.JavaActivator; | |
import org.eclipse.modisco.java.discoverer.internal.Messages; | |
import org.eclipse.modisco.java.discoverer.internal.io.java.JavaReader; | |
import org.eclipse.modisco.java.discoverer.internal.io.java.binding.BindingManager; | |
import org.eclipse.modisco.java.discoverer.internal.io.library.LibraryReader; | |
import org.eclipse.modisco.java.emf.JavaFactory; | |
import org.eclipse.modisco.kdm.source.extension.discovery.AbstractRegionDiscoverer2; | |
/** | |
* Abstract class to discover a Java model from a project and optionally its | |
* libraries. | |
*/ | |
public abstract class AbstractDiscoverJavaModelFromProject<T> extends AbstractRegionDiscoverer2<T> { | |
private ElementsToAnalyze fElementsToAnalyze; | |
@Parameter(name = "ELEMENTS_TO_ANALYZE", description = "The Java projects or packages that will be analyzed. ") | |
public void setElementsToAnalyze(final ElementsToAnalyze elementsToAnalyze) { | |
this.fElementsToAnalyze = elementsToAnalyze; | |
} | |
protected ElementsToAnalyze getElementsToAnalyze() { | |
return this.fElementsToAnalyze; | |
} | |
/** | |
* A parameter key for indicating to log warnings from java analysis. | |
* | |
* For instance, sometimes java bindings (reference to a Java type, method, | |
* ...) cannot be completed. Such java binding problems occurs typically | |
* when there are some missing libraries in the Java project classpath. Such | |
* java bindings problems will result in missing information in the | |
* resulting Java model (occurrences of | |
* {@link org.eclipse.modisco.java.UnresolvedItem}) | |
*/ | |
private boolean fLogJavaAnalysisWarnings = false; | |
@Parameter(name = "LOG_JAVA_ANALYSIS_WARNINGS", description = "Whether to log warnings from java analysis.") | |
public void setLogJavaAnalysisWarnings(final boolean logJavaAnalysisWarnings) { | |
this.fLogJavaAnalysisWarnings = logJavaAnalysisWarnings; | |
} | |
protected boolean isLogJavaAnalysisWarnings() { | |
return this.fLogJavaAnalysisWarnings; | |
} | |
private boolean fDeepAnalysis = true; | |
@Parameter(name = "DEEP_ANALYSIS", description = "If true, analyze method bodies. If false, only analyze fields and method signatures.") | |
public void setDeepAnalysis(final boolean deepAnalysis) { | |
this.fDeepAnalysis = deepAnalysis; | |
} | |
protected boolean isDeepAnalysis() { | |
return this.fDeepAnalysis; | |
} | |
private boolean fIncrementalMode; | |
@Parameter(name = "INCREMENTAL_MODE", description = "Optimize memory use by analyzing incrementally (more time expensive).") | |
public void setIncrementalMode(final boolean incrementalMode) { | |
this.fIncrementalMode = incrementalMode; | |
} | |
protected boolean isIncrementalMode() { | |
return this.fIncrementalMode; | |
} | |
private String includedElementsRegEx; | |
@Parameter(name = "INCLUDED_ELEMENTS_REGEX", description = "A regular expression on qualified names for elements (types & packages) to be included during analysis") | |
public void setIncludedElementsRegEx(final String includedElementsRegEx) { | |
this.includedElementsRegEx = includedElementsRegEx; | |
} | |
protected String getIncludedElementsRegEx() { | |
return this.includedElementsRegEx; | |
} | |
private String excludedElementsRegEx; | |
@Parameter(name = "EXCLUDED_ELEMENTS_REGEX", description = "A regular expression on qualified names for elements (types & packages) to be excluded during analysis") | |
public void setExcludedElementsRegEx(final String excludedElementsRegEx) { | |
this.excludedElementsRegEx = excludedElementsRegEx; | |
} | |
protected String getExcludedElementsRegEx() { | |
return this.excludedElementsRegEx; | |
} | |
@SuppressWarnings("static-method") /* designed for overridability */ | |
public JavaFactory getEFactory() { | |
return org.eclipse.modisco.java.emf.JavaFactory.eINSTANCE; | |
} | |
protected void analyzeJavaProject(final IJavaProject source, final IProgressMonitor monitor) { | |
if (source == null) { | |
throw new IllegalArgumentException("source is null"); //$NON-NLS-1$ | |
} | |
IProject project = source.getProject(); | |
setDefaultTargetURI(URI | |
.createPlatformResourceURI(project.getFullPath().append(project.getName()) | |
.toString().concat(JavaDiscoveryConstants.JAVA_MODEL_FILE_SUFFIX), true)); | |
if (this.fElementsToAnalyze == null) { | |
this.fElementsToAnalyze = new ElementsToAnalyze(source); | |
} | |
ElementsToAnalyze elementsToDiscover = computeElementsToDiscover(this.fElementsToAnalyze); | |
createTargetModel(); | |
Model model = getEFactory().createModel(); | |
BindingManager globalBindings = getBindingManager(); | |
getTargetModel().getContents().add(model); | |
IModelReader reader = null; | |
for (Entry<IModelReader, Object> readerEntry : getReaders(elementsToDiscover).entrySet()) { | |
if (monitor.isCanceled()) { | |
return; | |
} | |
reader = readerEntry.getKey(); | |
Object element = readerEntry.getValue(); | |
reader.readModel(element, model, globalBindings, monitor); | |
} | |
if (reader != null) { | |
reader.terminate(monitor); | |
} | |
model.setName(project.getName()); | |
endAnalyzeJavaProject(model); | |
} | |
protected void endAnalyzeJavaProject(final Model model) { | |
// | |
} | |
/* | |
* This method makes sure that one ElementsToAnalyze instance is still coherent | |
* to one Java project (jars and dependencies may have changed), and update it if needed. | |
*/ | |
public static ElementsToAnalyze computeElementsToDiscover( | |
final ElementsToAnalyze userElementsToAnalyze) { | |
try { | |
IJavaProject javaProject = userElementsToAnalyze.getJavaProject(); | |
if (javaProject == null) { | |
return userElementsToAnalyze.clone(); | |
} | |
List<Object> discoverableElements = computeDiscoverableElements(userElementsToAnalyze | |
.getJavaProject()); | |
ElementsToAnalyze elementsToAnalyze = userElementsToAnalyze.clone(); | |
// make sure the source java project is selected | |
elementsToAnalyze.addElementToDiscover(javaProject); | |
// remove any project/library that is not on the project classpath | |
List<Object> elementsToRemove = new ArrayList<Object>(); | |
for (Object oldParameter : elementsToAnalyze.getElementsToDiscover()) { | |
if (!oldParameter.equals(javaProject) | |
&& !discoverableElements.contains(oldParameter)) { | |
elementsToRemove.add(oldParameter); | |
} | |
} | |
for (Object oldParameterToRemove : elementsToRemove) { | |
elementsToAnalyze.removeElementToDiscover(oldParameterToRemove); | |
} | |
return elementsToAnalyze; | |
} catch (CloneNotSupportedException e) { | |
MoDiscoLogger.logError(e, JavaActivator.getDefault()); | |
return null; | |
} | |
} | |
public static List<Object> computeDiscoverableElements(final IJavaProject javaProject) { | |
// retrieve required projects and libraries | |
Set<IJavaProject> projects = null; | |
Set<IPackageFragmentRoot> libraries = null; | |
final List<Object> discoverableElements = new ArrayList<Object>(); | |
try { | |
projects = computeRequiredProjects(javaProject); | |
libraries = computeRequiredLibraries(projects); | |
} catch (JavaModelException e) { | |
MoDiscoLogger.logError(e, JavaActivator.getDefault()); | |
return discoverableElements; | |
} | |
discoverableElements.addAll(projects); | |
discoverableElements.addAll(libraries); | |
return discoverableElements; | |
} | |
@Override | |
public String toString() { | |
return Messages.DiscoverJavaModelFromJavaProject_title; | |
} | |
public static Set<IJavaProject> computeRequiredProjects(final IJavaProject project) | |
throws JavaModelException { | |
Set<IJavaProject> projects = new LinkedHashSet<IJavaProject>(); | |
if (project == null) { | |
return projects; | |
} | |
// we keep package fragments which are binaries | |
projects.add(project); | |
for (String projectName : project.getRequiredProjectNames()) { | |
IJavaProject requiredProject = project.getJavaModel().getJavaProject(projectName); | |
if (requiredProject.getProject().isAccessible()) { | |
projects.add(requiredProject); | |
} | |
} | |
return projects; | |
} | |
protected static Set<IPackageFragmentRoot> computeRequiredLibraries( | |
final Collection<IJavaProject> projects) throws JavaModelException { | |
Set<IPackageFragmentRoot> libraries = new LinkedHashSet<IPackageFragmentRoot>(); | |
// we keep package fragments which are binaries | |
for (IJavaProject project : projects) { | |
libraries.addAll(computeRequiredLibraries(project)); | |
} | |
return libraries; | |
} | |
public static Set<IPackageFragmentRoot> computeRequiredLibraries(final IJavaProject project) | |
throws JavaModelException { | |
Set<IPackageFragmentRoot> libraries = new LinkedHashSet<IPackageFragmentRoot>(); | |
// we keep package fragments which are binaries | |
for (IPackageFragmentRoot lib : project.getPackageFragmentRoots()) { | |
if (lib.exists() && lib.getKind() == IPackageFragmentRoot.K_BINARY) { | |
libraries.add(lib); | |
} | |
} | |
return libraries; | |
} | |
protected Map<IModelReader, Object> getReaders(final ElementsToAnalyze elementsToDiscover) { | |
Map<IModelReader, Object> readers = new HashMap<IModelReader, Object>(); | |
for (Object element : elementsToDiscover.getElementsToDiscover()) { | |
Map<String, Object> elementOptions = elementsToDiscover.getDiscoveryOptions(element); | |
if (element instanceof IJavaProject) { | |
JavaReader javaReader = getJavaReader(elementOptions); | |
javaReader.setIncremental(isIncrementalMode()); | |
javaReader.setDeepAnalysis(isDeepAnalysis()); | |
javaReader.setIncludedElementsRegEx(getIncludedElementsRegEx()); | |
javaReader.setExcludedElementsRegEx(getExcludedElementsRegEx()); | |
readers.put(javaReader, element); | |
} else if (element instanceof IPackageFragmentRoot) { | |
LibraryReader libraryReader = getLibraryReader(elementOptions); | |
readers.put(libraryReader, element); | |
} | |
} | |
return readers; | |
} | |
protected LibraryReader getLibraryReader(final Map<String, Object> elementOptions) { | |
return new LibraryReader(getEFactory(), elementOptions); | |
} | |
protected JavaReader getJavaReader(final Map<String, Object> elementOptions) { | |
return new JavaReader(getEFactory(), elementOptions, this); | |
} | |
protected BindingManager getBindingManager() { | |
return new BindingManager(getEFactory()); | |
} | |
} |