/******************************************************************************* * Copyright (c) 2010 the CHISEL group and contributors. * 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: * Del Myers - initial API and implementation *******************************************************************************/ package ca.uvic.chisel.logging.eclipse.internal; import java.io.File; import java.io.FileFilter; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.net.URL; import java.util.Comparator; import java.util.LinkedList; import java.util.List; import java.util.TreeSet; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Platform; import org.eclipse.swt.widgets.Event; import org.eclipse.ui.IMemento; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchListener; import org.eclipse.ui.WorkbenchException; import org.eclipse.ui.XMLMemento; import org.osgi.framework.Bundle; import ca.uvic.chisel.logging.eclipse.DefaultInterpreter; import ca.uvic.chisel.logging.eclipse.DefaultSWTInterpreter; import ca.uvic.chisel.logging.eclipse.ILogObjectInterpreter; import ca.uvic.chisel.logging.eclipse.ILoggingCategory; import ca.uvic.chisel.logging.eclipse.WorkbenchLoggingPlugin; /** * @author Del Myers * */ public class LoggingCategory implements ILoggingCategory { private static final ILogObjectInterpreter defaultInterpreter = new DefaultInterpreter(); private static final ILogObjectInterpreter swtInterpreter = new DefaultSWTInterpreter(); private class InterpreterProxy { boolean interpretSubTypes; Class<?> target; ILogObjectInterpreter interpreter; public InterpreterProxy(boolean interpretSubTypes, Class<?> target, ILogObjectInterpreter interpreter) { this.interpretSubTypes = interpretSubTypes; this.target = target; this.interpreter = interpreter; } } private class ProxySorter implements Comparator<InterpreterProxy> { private Class<?> target; public ProxySorter(Class<?> target) { this.target = target; } /* (non-Javadoc) * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ public int compare(InterpreterProxy o1, InterpreterProxy o2) { if (o1.target.equals(o2.target)) { return 0; } //calculate the distance for each proxy from the target. return findDistance(o1) - findDistance(o2); } /** * @param proxy */ private int findDistance(InterpreterProxy proxy) { int distance = 0; if (proxy.target.equals(target)) { //distance is equal to 0: they are the same class distance = 0; } else { distance = 1; Class<?> parent = target; //walk up the call chain until the interface is found. boolean found = false; while (parent != null && !found) { if (proxy.target.equals(parent)) { found = true; break; } Class<?>[] interfaces = parent.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { if (interfaces[i].equals(proxy.target)) { distance += i; found = true; break; } } if (!found) { distance *= 10; parent = parent.getSuperclass(); } } } return distance; } } private List<InterpreterProxy> interpreters; private String categoryID; private String categoryName; private String disclaimer; private URL url; private boolean isHTML; private Log log; private XMLMemento memento; private String provider; public LoggingCategory(IConfigurationElement element) { this.log = new Log(this); this.categoryID = element.getAttribute("id"); this.categoryName = element.getAttribute("name"); this.provider = element.getAttribute("provider"); this.disclaimer = element.getChildren("disclaimer")[0].getValue(); this.isHTML = Boolean.parseBoolean(element.getAttribute("isHTML")); try { this.url = new URL(element.getAttribute("url")); } catch (Exception e) { url = null; } if (categoryID == null || disclaimer == null) { throw new RuntimeException("Malformed Element"); } WorkbenchLoggingPlugin.getDefault().getWorkbench().addWorkbenchListener(new IWorkbenchListener() { public boolean preShutdown(IWorkbench workbench, boolean forced) { saveState(); return true; } public void postShutdown(IWorkbench workbench) { } }); } protected synchronized void saveState() { if (memento != null) { IPath stateLocation = WorkbenchLoggingPlugin.getDefault().getStateLocation(); File stateDirectory = stateLocation.toFile(); File mementoFile = new File(stateDirectory, getCategoryID() + ".state"); try { FileWriter writer = new FileWriter(mementoFile); memento.save(writer); writer.close(); } catch (IOException e) { WorkbenchLoggingPlugin.getDefault().log(e); } } } /* (non-Javadoc) * @see ca.uvic.chisel.logging.eclipse.ILoggingCategory#getDisclaimer() */ public String getDisclaimer() { return disclaimer; } /* (non-Javadoc) * @see ca.uvic.chisel.logging.eclipse.ILoggingCategory#getID() */ public String getCategoryID() { return categoryID; } /* (non-Javadoc) * @see ca.uvic.chisel.logging.eclipse.ILoggingCategory#getInterpreter(java.lang.Class) */ public ILogObjectInterpreter getInterpreter(Class<?> clazz) { if (interpreters == null) { loadInterpreters(); } if (clazz == null) return defaultInterpreter; TreeSet<InterpreterProxy> interpreterSet = new TreeSet<InterpreterProxy>(new ProxySorter(clazz)); for (InterpreterProxy proxy : interpreters) { if (!proxy.interpretSubTypes) { if (clazz.equals(proxy.target)) { interpreterSet.add(proxy); } } else { if (proxy.target.isAssignableFrom(clazz)) { interpreterSet.add(proxy); } } } if (interpreterSet.size() == 0) { if (Event.class.isAssignableFrom(clazz)) { return swtInterpreter; } else { return defaultInterpreter; } } else { return interpreterSet.first().interpreter; } } /** * */ private void loadInterpreters() { interpreters = new LinkedList<InterpreterProxy>(); IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint("ca.uvic.chisel.logging.eclipse.interpreter"); IConfigurationElement[] elements = point.getConfigurationElements(); for (IConfigurationElement element:elements) { if ("interpreter".equals(element.getName())) { String categoryID = element.getAttribute("categoryID"); if (getCategoryID().equals(categoryID)) { try { ILogObjectInterpreter interpreter = (ILogObjectInterpreter) element.createExecutableExtension("class"); String target = element.getAttribute("target"); Bundle bundle = Platform.getBundle(element.getContributor().getName()); Class<?> targetClass = bundle.loadClass(target); boolean interpretSubTypes = Boolean.parseBoolean(element.getAttribute("implements")); interpreters.add(new InterpreterProxy(interpretSubTypes, targetClass, interpreter)); } catch (Exception e) { WorkbenchLoggingPlugin.getDefault().log(e); } } } } } /* (non-Javadoc) * @see ca.uvic.chisel.logging.eclipse.ILoggingCategory#getURL() */ public URL getURL() { return url; } /* (non-Javadoc) * @see ca.uvic.chisel.logging.eclipse.ILoggingCategory#isHTML() */ public boolean isHTML() { return isHTML; } public Log getLog() { return log; } public String getName() { return categoryName; } public synchronized IMemento getMemento() { if (memento != null) return memento; IPath stateLocation = WorkbenchLoggingPlugin.getDefault().getStateLocation(); File stateDirectory = stateLocation.toFile(); File mementoFile = new File(stateDirectory, getCategoryID() + ".state"); if (mementoFile.exists()) { try { Reader reader = new FileReader(mementoFile); memento = XMLMemento.createReadRoot(reader); reader.close(); } catch (FileNotFoundException e) { } catch (WorkbenchException e) { } catch (IOException e) { WorkbenchLoggingPlugin.getDefault().log(e); } } if (memento == null){ //the memento couldn't be read, create a new memento memento = XMLMemento.createWriteRoot("loggingCategory"); memento.putBoolean("enabled", true); saveState(); } return memento; } public File getLogLocation() { File stateLocation = WorkbenchLoggingPlugin.getDefault().getStateLocation().toFile(); File categoryLocation = new File(stateLocation, getCategoryID()); if (!categoryLocation.isDirectory()) { if (!categoryLocation.isDirectory()) { categoryLocation.delete(); } categoryLocation.mkdirs(); } return categoryLocation; } public boolean isEnabled() { IMemento memento = getMemento(); if (memento == null) { return false; } return memento.getBoolean("enabled"); } public void setEnabled(boolean enabled) { IMemento memento = getMemento(); if (memento != null){ memento.putBoolean("enabled", enabled); saveState(); } } public String getProvider() { return provider; } public File[] getFilesToUpload() { IMemento memento = log.getCategory().getMemento(); File logLocation = log.getCategory().getLogLocation(); if (logLocation.isDirectory()) { String lastUpload = memento.getString("lastUpload"); long uploadTime = 0; try { if (lastUpload != null) { String timeString = lastUpload.substring(0, lastUpload.length()-".zip".length()); uploadTime = Long.parseLong(timeString); } } catch (NumberFormatException e) { } final long fTime = uploadTime; File[] children = logLocation.listFiles(new FileFilter(){ public boolean accept(File pathname) { String fileName = pathname.getName(); if (fileName.endsWith(".zip")) { long date; try { String fileDate = fileName.substring(0, fileName.length()-".zip".length()); String[] parts = fileDate.split("\\-"); date = Long.parseLong(parts[0]); return date > fTime; } catch (Exception e) { } } return false; }}); return children; } return new File[0]; } /** * Returns true if there is any data to upload to the server. * @return true if there is any data to upload to the server. */ public boolean isStale() { File[] backupFiles = getFilesToUpload(); return (log.getLogFile().length() > 32) || ( backupFiles != null && backupFiles.length > 0); } }