./CodeAnalyzer/src/de/fzi/cloneanalyzer/core/CloneAnalyzerPlugin.java
package de.fzi.cloneanalyzer.core;
import java.lang.reflect.InvocationTargetException;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPluginDescriptor;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.Bundle;
import de.fzi.cloneanalyzer.analyzer.CloneInstanceFactory;
import de.fzi.cloneanalyzer.analyzer.IAnalyzer;
import de.fzi.cloneanalyzer.analyzer.IterativeAnalyzer;
import de.fzi.cloneanalyzer.annotation.AnnotationManager;
import de.fzi.cloneanalyzer.config.IConfig;
import de.fzi.cloneanalyzer.config.PluginConfig;
import de.fzi.cloneanalyzer.exceptions.CloneException;
import de.fzi.cloneanalyzer.reader.ProjectLineElementReader;
import de.fzi.cloneanalyzer.util.EclipseUtil;
import de.fzi.cloneanalyzer.util.FileConsoleLogger;
import de.fzi.cloneanalyzer.util.IntTreeMap;
import de.fzi.cloneanalyzer.util.TimeLogger;
import de.fzi.cloneanalyzer.viewer.CloneTreeViewer;
/**
* The main plugin class the current instance of the CloneAnalyzerPlugin can be
* accessed by: CloneAnalyzerPlugin.getDefault()
*
*/
public class CloneAnalyzerPlugin extends AbstractUIPlugin {
private static CloneAnalyzerPlugin plugin; //The shared instance
private ResourceBundle resourceBundle;
private CloneSetStructure data;
private CloneTreeViewer treeViewer;
private IConfig config;
private Shell shell;
private IWorkbenchWindow wbw;
private CloneInstance selectedCloneInstance;
private CloneInstance compareCloneInstance;
private static final int SHOW_THRESHOLD = 1000;
private FileConsoleLogger logger;
private IntTreeMap map;
private boolean showReminder = false;
private boolean saveAllInfos = true;
/**
* The constructor
*/
public CloneAnalyzerPlugin(IPluginDescriptor descriptor) {
super(descriptor);
plugin = this;
/*
* try { resourceBundle = ResourceBundle
* .getBundle("CloneAnalyzer.CloneAnalyzerPluginResources"); } catch
* (MissingResourceException x) { resourceBundle = null; } //setting
* default values for plugin fields data = new CloneSetStructure(); try {
* config = PluginConfig.getStdInstance(); } catch (CloneException e) {
* EclipseUtil .warning("There is a problem with the Configuration: " +
* e.getMessage()); } map = new IntTreeMap(); wbw =
* PlatformUI.getWorkbench().getActiveWorkbenchWindow(); shell =
* PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); //
* this logger writes to a certain file as well as to the console logger =
* new FileConsoleLogger("CloneAnalyzerLogger",
* CloneAnalyzerPlugin.getDefault().getStateLocation().toString() +
* "/cloneanalyzer.log");
*
* IResourceChangeListener listener = new CloneResourceChangeReporter();
* ResourcesPlugin.getWorkspace().addResourceChangeListener( listener,
* IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.POST_CHANGE);
*/
Updater updater = new Updater();
}
public void startup() throws CoreException {
super.startup();
try {
resourceBundle = ResourceBundle
.getBundle("CloneAnalyzer.CloneAnalyzerPluginResources");
} catch (MissingResourceException x) {
resourceBundle = null;
}
//setting default values for plugin fields
data = new CloneSetStructure();
try {
config = PluginConfig.getStdInstance();
} catch (CloneException e) {
EclipseUtil
.warning("There is a problem with the configuration, the plugin will not be usable until changed."
+ e.getMessage());
}
map = new IntTreeMap();
wbw = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
// this logger writes to a certain file as well as to the console
logger = new FileConsoleLogger("CloneAnalyzerLogger",
CloneAnalyzerPlugin.getDefault().getStateLocation().toString()
+ "/cloneanalyzer.log");
IResourceChangeListener listener = new CloneResourceChangeReporter();
ResourcesPlugin.getWorkspace().addResourceChangeListener(
listener,
IResourceChangeEvent.PRE_CLOSE
| IResourceChangeEvent.POST_CHANGE);
}
/**
* Returns the shared instance.
* There is only one instance per program
*/
public static CloneAnalyzerPlugin getDefault() {
return plugin;
}
/**
* Returns the workspace instance.
*/
public static IWorkspace getWorkspace() {
return ResourcesPlugin.getWorkspace();
}
/**
* Returns the string from the plugin's resource bundle, or 'key' if not
* found.
*/
public static String getResourceString(String key) {
ResourceBundle bundle = CloneAnalyzerPlugin.getDefault()
.getResourceBundle();
try {
return bundle.getString(key);
} catch (MissingResourceException e) {
return key;
}
}
/**
* Returns the plugin's resource bundle,
*/
public ResourceBundle getResourceBundle() {
return resourceBundle;
}
/**
* @return data, the current CloneSetStructure
*/
public CloneSetStructure getData() {
return data;
}
/**
* Sets the given CloneSetStructure parameter as the current CloneSet after
* setting ther CloneSetStructure the TreeView will be updated.
* Since this update of the GUI Componenet is usually pretty slow, we ask
* the user in the case of many found cloneSets, if he wants to update.
*
* ask the user, if he wants all the
*
* @param structure
*/
public void setData(CloneSetStructure structure, Shell param_shell) {
boolean showData = false;
if (structure.getSize() > SHOW_THRESHOLD) {
MessageBox m = new MessageBox(param_shell, SWT.CANCEL | SWT.OK);
m.setText("Large number of CloneSets found");
m
.setMessage("A number of CloneSets > "
+ Integer.toString(SHOW_THRESHOLD)
+ " was found. Constructing the GUI components might take a while. Continue anyway?");
if (m.open() == SWT.OK) {
showData = true;
}
} else {
showData = true;
}
if (showData) {
setDataSilent(structure);
}
}
/**
* @return
*/
private Shell Shell() {
return null;
}
/**
* set the data without updating the GUI Components
*
* @param structure
*/
protected void setDataSilent(CloneSetStructure structure) {
CloneSetStructure oldData = data;
data = structure;
}
/**
* set the data and update the GUI
*
* @param structure
*/
protected void setDataUpdate(CloneSetStructure structure) {
setDataSilent(structure);
update();
}
/**
* update the GUI, this is kind of tricky, since only certain threads can do
* this.
*
*/
public void update() {
Runnable r = new Runnable() {
public void run() {
//bring the cloneTreeViewer to top
IWorkbenchPage wp = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getActivePage();
try {
wp.showView("de.fzi.cloneanalyzer.viewer.CloneTreeViewer");
} catch (Exception e) {
e.printStackTrace();
}
treeViewer.myUpdate();
}
};
//since we wan to do updates to a GUI component,
//Eclipse, forces us, to do that in a separate thread
Display.getDefault().asyncExec(r);
}
/**
* @return
*/
public IConfig getConfig() {
return config;
}
/**
* @param config
*/
public void setConfig(IConfig config) {
this.config = config;
this.config.storeInstance();
}
/**
* closes all open Editors
*
*/
public void prepareUI() {
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.closeAllEditors(true);
}
/**
* shows an Eclipse-Progressbar while perfoming thhe calculatons in the run
* method
*
* @author biehl
*
*/
public class MyRunnableWithProgress implements IRunnableWithProgress {
Shell mshell;
public MyRunnableWithProgress() {
}
public void run(IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException {
mshell = new Shell(new Display());
TimeLogger tl = new TimeLogger();
ICancelDispatcher cancel = new MonitorCancelDispatcher(monitor);
try {
config.updateCommentFile();
} catch (CloneException e) {
throw new InterruptedException(e.getMessage());
}
try {
IAnalyzer a = new IterativeAnalyzer(config,
new CloneInstanceFactory() {
public CloneInstance newInstance(LineElement start,
LineElement end) {
return new CloneInstanceEclipse(start, end);
}
});
LineElement lastLineElement = null;
ProjectLineElementReader reader = null;
Hashtable ht = null;
AnnotationManager am = null;
CloneSetStructure css = null;
// remove all data from previous session
data.clear();
data = null;
selectedCloneInstance = null;
compareCloneInstance = null;
map.clear();
System.gc();
logger.info(config.toString());
if (!cancel.isCanceled()) {
if (monitor != null) {
tl.log("Start");
monitor
.beginTask("reading files of current projects...",
4);
}
reader = new ProjectLineElementReader();
logger.info("reading started...");
try {
lastLineElement = reader.read(config, cancel);
} catch (CloneException e) {
throw new InterruptedException(e.getMessage());
}
logger.info("...reading completed.");
ht = reader.getHashtable();
logger.info("got Hashtable.");
System.gc();
logger.info("performed gc.");
if (lastLineElement == null) {
logger.info("lastLineElement == null");
return;
}
}
if (!cancel.isCanceled()) {
logger.info("not canceled before analyzing.");
if (monitor != null) {
tl.log("Reading files");
monitor.worked(1);
monitor.setTaskName("analyzing files for clones...");
}
logger.info("analyzing started.");
css = a.buildCloneSetStructure(lastLineElement, ht, cancel);
logger.info("analyzing completed.");
StringBuffer buf = new StringBuffer();
buf
.append("\n--------------------------------------------------------\n");
buf.append("LOC (total) processed: "
+ Integer.toString(reader.getGlobalTotalLineCount())
+ "\n");
buf.append("LOC (significant) processed: "
+ Integer.toString(reader.getGlobalLineCount()) + "\n");
buf.append("No of Files: "
+ Integer.toString(reader.getCloneFileList().size())
+ "\n");
buf.append("CloneSets found: "
+ Integer.toString(css.getSize()));
logger.info(buf.toString());
System.gc();
}
if (!cancel.isCanceled()) {
if (config.getCalcAtOnce()) {
if (monitor != null) {
tl.log("IterativeAnalyzer");
monitor.worked(1);
monitor
.setTaskName("calculating positions of annotations...");
}
am = new AnnotationManager(reader.getCloneFileList());
am.calc();
System.gc();
}
}
if (!cancel.isCanceled()) {
if (monitor != null) {
tl.log("AnnotationCalculation");
monitor.worked(1);
monitor
.setTaskName("feeding elements into CloneTreeView...");
}
setData(css, mshell);
if (monitor != null) {
tl.log("Feeding CloneTreeView");
monitor.worked(1);
logger.info(tl.print());
}
System.gc();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* starts the whole analyzation process
* to do this, a separate thread is started that concurrently displays the
* state of the analyzation, using a progress bar.
*/
public void runAnalyzer() {
try {
prepareUI();
ProgressMonitorDialog pmd = new ProgressMonitorDialog(shell);
IRunnableWithProgress op = new MyRunnableWithProgress();
pmd.run(true, true, op);
update();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InterruptedException e) {
EclipseUtil.warning(e.getMessage() + "\naborted operation!");
}
}
/**
* returns a reference to the CloneTreeViewer
*
* @return a reference to the CloneTreeViewer
*/
public CloneTreeViewer getTreeViewer() {
return treeViewer;
}
/**
* sets the reference to the CloneTreeViewer
*
* @param viewer
*/
public void setTreeViewer(CloneTreeViewer viewer_param) {
treeViewer = viewer_param;
}
/**
* for opening persistent Clone Information not implemented yet
*
* @param path
*/
public void open(String path) {
data.readFile();
update();
}
/**
* for saving persistent Clone Information not implemented yet
*/
public void save(String path) {
System.out.println("saving");
data.writeFile(path, this.saveAllInfos);
}
/**
* returns a reference to the compareCloneInstance A compareCloneInstance is
* the CloneInstance that we want the selectedCloneInstance to be compared
* to can be picked in CloneTreeViewer
*
* @return a reference to the compareCloneInstance
*/
public CloneInstance getCompareCloneInstance() {
return compareCloneInstance;
}
/**
* returns a reference to the selectedCloneInstance A selectedCloneInstance
* is the CloneInstance that we want the compareCloneInstance to be compared
* to can be picked in CloneTreeViewer
*
* @return a reference to the selectedCloneInstance
*/
public CloneInstance getSelectedCloneInstance() {
return selectedCloneInstance;
}
/**
* sets a reference to the compareCloneInstance A compareCloneInstance is
* the CloneInstance that we want the selectedCloneInstance to be compared
* to can be picked in CloneTreeViewer
*
* @param instance
*/
public void setCompareCloneInstance(CloneInstance instance) {
compareCloneInstance = instance;
}
/**
* sets a reference to the selectedCloneInstance A selectedCloneInstance is
* the CloneInstance that we want the compareCloneInstance to be compared to
* can be picked in CloneTreeViewer
*
* @param instance
*/
public void setSelectedCloneInstance(CloneInstance instance) {
selectedCloneInstance = instance;
}
/**
* gets a reference to a CloneInstances that belongs to a certain key
*/
public CloneInstance getCloneInstance(int key) {
return (CloneInstance) map.get(key);
}
/**
* stores a reference to all CloneInstances in a central Hashtable this
* functionality is needed to map a marker to its corresponding
* CloneInstance object
*/
public void setCloneInstance(int key, CloneInstance ci) {
map.put(key, ci);
}
public void toggleReminder() {
showReminder = !showReminder;
}
public void toggleSaveAllInfos() {
saveAllInfos = !saveAllInfos;
}
/**
* @return Returns the showReminder.
*/
public boolean isShowReminder() {
return showReminder;
}
public String getPluginDir() {
// get Eclipse install Directory
String installDir = "";
Bundle b = getBundle();
installDir = b.getLocation();
installDir = installDir.substring(installDir.indexOf("/") + 1,
installDir.length());
System.out.println(installDir);
return installDir;
}
/**
*
*/
public void setAllExpanded() {
Iterator it = data.getClones().iterator();
while (it.hasNext()) {
((MaxCloneSet) it.next()).setExpand();
}
}
}