/*******************************************************************************
* Copyright (c) 2009 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.javasketch.internal;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.SQLException;
import java.util.Date;
import java.util.Properties;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.model.IProcess;
import ca.uvic.chisel.hsqldb.server.DBPlugin;
import ca.uvic.chisel.hsqldb.server.DefaultDataPortal;
import ca.uvic.chisel.hsqldb.server.IDataPortal;
import ca.uvic.chisel.javasketch.FilterSettings;
import ca.uvic.chisel.javasketch.IFilterChangedListener;
import ca.uvic.chisel.javasketch.IProgramSketch;
import ca.uvic.chisel.javasketch.SketchPlugin;
import ca.uvic.chisel.javasketch.data.model.ITrace;
import ca.uvic.chisel.javasketch.data.model.imple.internal.TraceImpl;
import ca.uvic.chisel.javasketch.launching.ITraceClient;
import ca.uvic.chisel.javasketch.launching.internal.JavaAgentTraceClient;
/**
* Represents a trace from a java launch.
* @author Del Myers
*
*/
public class DBProgramSketch implements IProgramSketch, ISchedulingRule {
private Properties props;
private Date date;
private IPath path;
//private IProject project;
private IDataPortal dataPortal;
private ITrace trace;
private FilterSettings filterSettings;
private boolean deleted;
private ILaunchConfiguration configuration;
private File filtersFile;
/**
* Creates a trace from the path in trace store
* @param traceStore the path on the files system at which the data is stored
* for this trace.
* @throws IOException if there was a problem loading the properties for this file.
*/
public DBProgramSketch(File traceStore) throws IOException {
this.path = new Path(traceStore.getAbsolutePath());
this.filtersFile = new File(traceStore, ".filters");
//find the properties file.
File properties = new File(traceStore, JavaAgentTraceClient.PROCESS_PROPERTIES_FILE);
Properties props = new Properties();
FileInputStream fis = new FileInputStream(properties);
try {
props.load(fis);
} catch (IOException e) {
fis.close();
throw e;
}
this.props = props;
fis.close();
File lcFile = new File(traceStore, JavaAgentTraceClient.CONFIGURATION_FILE);
FileReader reader = new FileReader(lcFile);
try {
char[] buffer = new char[1024];
int read = -1;
StringBuilder sb = new StringBuilder();
while ((read = reader.read(buffer))>=0) {
sb.append(buffer, 0, read);
}
try {
this.configuration = DebugPlugin.getDefault().getLaunchManager().getLaunchConfiguration(sb.toString());
} catch (CoreException e) {
throw new IOException(e);
}
} finally {
reader.close();
}
}
/* (non-Javadoc)
* @see ca.uvic.chisel.javasketch.IProgramSketch#getProcessName()
*/
@Override
public String getProcessName() {
return props.getProperty(JavaAgentTraceClient.HOST_PROPERTY);
}
/* (non-Javadoc)
* @see ca.uvic.chisel.javasketch.IProgramSketch#getProcessTime()
*/
@Override
public Date getProcessTime() {
if (date == null) {
String timeString = props.getProperty(JavaAgentTraceClient.ATTACH_TIME_PROPERTY);
long time = System.currentTimeMillis();
if (timeString == null) {
timeString = "" + System.currentTimeMillis();
}
try {
time = Long.parseLong(timeString);
} catch (NumberFormatException e) {}
date = new Date(time);
}
return date;
}
/* (non-Javadoc)
* @see ca.uvic.chisel.javasketch.IProgramSketch#getTraceData()
*/
@Override
public ITrace getTraceData() {
if (deleted) {
return null;
}
if (this.trace == null) {
try {
if (TraceImpl.exists(getID(), getProcessTime(), getPortal())) {
trace = TraceImpl.load(getID(), getProcessTime(), getPortal());
} else {
trace = TraceImpl.create(getID(), getProcessTime(), getPortal());
}
} catch (CoreException e) {
SketchPlugin.getDefault().log(e);
}
}
return trace;
}
public boolean delete() {
//make sure the view is closed
this.deleted = true;
clearData();
if (trace != null) {
((TraceImpl)trace).dispose();
trace = null;
}
try {
if (dataPortal != null) {
getPortal().close();
}
} catch (CoreException e) {
return false;
}
File dataLocation = path.toFile();
recursiveDelete(dataLocation);
return (!dataLocation.exists());
}
/**
* @param dataLocation
*/
private void recursiveDelete(File dataLocation) {
if (dataLocation.isDirectory()) {
for (File child : dataLocation.listFiles()) {
recursiveDelete(child);
}
}
if (dataLocation.exists()) {
if (!dataLocation.delete()) {
System.out.println("could not delete " + dataLocation.toString());
}
}
}
/**
* Closes and clears all of the database files.
* @return
* @throws CoreException
* @throws
*/
public boolean reset() throws CoreException {
clearData();
try {
if (((DefaultDataPortal)getPortal()).clear()) {
if (trace != null) {
((TraceImpl)trace).dispose();
trace = null;
}
return true;
}
} catch (SQLException e) {
throw new CoreException(SketchPlugin.getDefault().createStatus(e));
}
return false;
}
public IDataPortal getPortal() throws CoreException {
if (dataPortal == null) {
dataPortal = DBPlugin.getDefault().getDataPortal(path);
}
return dataPortal;
}
/**
*
* @return the path at which (temporary) trace files are stored.
*/
public URL getTracePath() {
try {
return path.toFile().toURI().toURL();
} catch (MalformedURLException e) {
SketchPlugin.getDefault().log(e);
}
return null;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj.getClass().equals(this.getClass()))) {
return false;
}
IProgramSketch that = (IProgramSketch) obj;
return this.getID().equals(that.getID());
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return getID().hashCode();
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return getProcessName();
}
// /* (non-Javadoc)
// * @see ca.uvic.chisel.javasketch.IProgramSketch#getTracedProject()
// */
// @Override
// public IProject getTracedProject() {
// return project;
// }
/* (non-Javadoc)
* @see ca.uvic.chisel.javasketch.IProgramSketch#getTracedLaunchConfiguration()
*/
@Override
public ILaunchConfiguration getTracedLaunchConfiguration() {
return configuration;
}
/* (non-Javadoc)
* @see ca.uvic.chisel.javasketch.IProgramSketch#getRule()
*/
@Override
public ISchedulingRule getRule() {
return this;
}
/* (non-Javadoc)
* @see ca.uvic.chisel.javasketch.IProgramSketch#getTracer()
*/
@Override
public ITraceClient getTracer() {
ILaunch[] launches = DebugPlugin.getDefault().getLaunchManager().getLaunches();
for (ILaunch launch : launches) {
for (IProcess process : launch.getProcesses()) {
if (process instanceof ITraceClient) {
if (((ITraceClient)process).getID().equals(getID())) {
return ((ITraceClient)process);
}
}
}
}
return null;
}
/* (non-Javadoc)
* @see ca.uvic.chisel.javasketch.IProgramSketch#isAnalysing()
*/
@Override
public boolean isAnalysing() {
Job[] jobs = Job.getJobManager().find(IProgramSketch.class);
for (Job job : jobs) {
if (job.getRule().isConflicting(this)) {
return (job.getState() != Job.NONE);
}
}
return false;
}
/* (non-Javadoc)
* @see ca.uvic.chisel.javasketch.IProgramSketch#isRunning()
*/
@Override
public boolean isRunning() {
ITraceClient client = getTracer();
return (client != null && !client.isTerminated());
}
/* (non-Javadoc)
* @see ca.uvic.chisel.javasketch.IProgramSketch#getID()
*/
@Override
public String getID() {
String id = props.getProperty("id");
return id;
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule)
*/
@Override
public boolean contains(ISchedulingRule rule) {
//only contains this rule
return (rule != null && rule.equals(this));
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.jobs.ISchedulingRule#isConflicting(org.eclipse.core.runtime.jobs.ISchedulingRule)
*/
@Override
public boolean isConflicting(ISchedulingRule rule) {
return (rule != null && rule.equals(this));
}
/* (non-Javadoc)
* @see ca.uvic.chisel.javasketch.IProgramSketch#getLabel()
*/
@Override
public String getLabel() {
if (deleted) {
return "Deleted Trace";
}
String label = props.getProperty(JavaAgentTraceClient.LABEL_PROPERTY);
if (label == null) {
label = getProcessName();
}
return label;
}
/* (non-Javadoc)
* @see ca.uvic.chisel.javasketch.IProgramSketch#getFilterSettings()
*/
@Override
public FilterSettings getFilterSettings() {
if (filterSettings == null) {
if (!filtersFile.exists()) {
try {
filterSettings = FilterSettings.newSettings(configuration);
filterSettings.save(filtersFile);
} catch (IOException e) {
SketchPlugin.getDefault().log(e);
} catch (CoreException e) {
SketchPlugin.getDefault().log(e);
}
} else {
try {
FileReader reader = new FileReader(filtersFile);
filterSettings = FilterSettings.load(reader, configuration);
reader.close();
} catch (IOException e) {
SketchPlugin.getDefault().log(e);
}
}
filterSettings.addFilterChangedListener(new IFilterChangedListener() {
@Override
public void referenceChanged(IProgramSketch old, FilterSettings settings) {
save();
}
@Override
public void projectClassesChanged(boolean old, FilterSettings settings) {
save();
}
@Override
public void inclusionChanged(String[] old, FilterSettings settings) {
save();
}
@Override
public void exclusionChanged(String[] old, FilterSettings settings) {
save();
}
private void save() {
try {
filterSettings.save(filtersFile);
} catch (IOException e) {}
}
});
}
return filterSettings;
}
/**
*
*/
public void clearData() {
if (trace != null) {
trace.invalidate();
}
}
/* (non-Javadoc)
* @see ca.uvic.chisel.javasketch.IProgramSketch#isConnected()
*/
@Override
public boolean isConnected() {
return this.trace != null;
}
}