./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(); } } }