/*******************************************************************************
* Copyright (c) 2009 Red Hat, Inc.
* 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:
* Red Hat - initial API and implementation
*******************************************************************************/
package org.eclipse.linuxtools.internal.callgraph.core;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
public abstract class SystemTapParser extends Job {
protected IProgressMonitor monitor;
protected String sourcePath;
protected String viewID;
protected SystemTapView view;
protected boolean realTime = false;
protected Object data;
protected BufferedReader internalData;
private String secondaryID = ""; //$NON-NLS-1$
public boolean done;
public SystemTapParser() {
super("Parsing data"); //$NON-NLS-1$
this.sourcePath = PluginConstants.getDefaultIOPath();
this.viewID = null;
initialize();
done = false;
//PURELY FOR TESTING
if (monitor == null){
monitor = new NullProgressMonitor();
}
}
public SystemTapParser(String name, String filePath) {
super(name);
// BY DEFAULT READ/WRITE FROM HERE
if (filePath != null) {
this.sourcePath = filePath;
} else {
this.sourcePath = PluginConstants.getDefaultIOPath();
}
this.viewID = null;
initialize();
}
/**
* Initialize will be called in the constructors for this class. Use this
* method to initialize variables.
*/
protected abstract void initialize();
/**
* Implement this method to execute parsing. The return from
* executeParsing() will be the return value of the run command.
*
* SystemTapParser will call executeParsing() within its run method. (i.e.
* will execute in a separate, non-UI thread)
*
* @return
*/
public abstract IStatus nonRealTimeParsing();
/**
* Implement this method if your parser is to execute in realtime. This method
* will be called as part of a while loop in a separate Job. Use the setInternalData
* method to initialize some data object for use in realTimeParsing. The default
* setInternalMethod method will set internalData to a BufferedReader
* <br> <br>
* After the isDone flag is set to true, the realTimeParsing() method will
* be run one more time to catch any stragglers.
*/
public abstract IStatus realTimeParsing();
/**
* Cleans names of form 'name").return', returning just the name
*
* @param name
*/
protected String cleanFunctionName(String name) {
return name.split("\"")[0]; //$NON-NLS-1$
}
/**
* Checks for quotations and brackets in the function name
*
* @param name
*/
protected boolean isFunctionNameClean(String name) {
if (name.contains("\"") || name.contains(")")) //$NON-NLS-1$ //$NON-NLS-2$
return false;
return true;
}
/**
* Creates a popup error dialog in a separate UI thread. Dialog title is
* 'Unexpected symbol,' name is 'ParseError' and body is the specified
* message.
*
* @param message
*/
protected void parsingError(String message) {
SystemTapUIErrorMessages mess = new SystemTapUIErrorMessages(
Messages.getString("SystemTapParser.ParseErr"), //$NON-NLS-1$
Messages.getString("SystemTapParser.ErrSymbol"), //$NON-NLS-1$
message);
mess.schedule();
}
/**
* Load the specified viewID by creating a StapUIJob. Does not return until the StapUIJob has.
* Returns true if the makeView was successful, false otherwise.
*/
private boolean makeView() {
// Create a UIJob to handle the rest
if (viewID != null && viewID.length() > 0) {
try {
StapUIJob uijob = new StapUIJob(
Messages.getString("StapGraphParser.JobName"), this, viewID); //$NON-NLS-1$
uijob.schedule();
uijob.join();
view = uijob.getViewer();
return true;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return false;
}
@Override
protected IStatus run(IProgressMonitor monitor) {
// Generate real-time job
IStatus returnStatus = Status.CANCEL_STATUS;
this.monitor = monitor;
if (this.monitor == null) {
this.monitor = new NullProgressMonitor();
}
makeView();
if (realTime) {
try {
setInternalData();
while (!done){
returnStatus = realTimeParsing();
if (monitor.isCanceled() || returnStatus == Status.CANCEL_STATUS) {
done = true;
return Status.CANCEL_STATUS;
}
Thread.sleep(500);
}
if (!monitor.isCanceled()) returnStatus = realTimeParsing();
done = true;
return returnStatus;
} catch (InterruptedException e) {
SystemTapUIErrorMessages m = new SystemTapUIErrorMessages(
Messages.getString("SystemTapParser.InternalData"), //$NON-NLS-1$
Messages.getString("SystemTapParser.FailedToSetData"), //$NON-NLS-1$
Messages.getString("SystemTapParser.FailedToSetDataMessage")); //$NON-NLS-1$
m.schedule();
return Status.CANCEL_STATUS;
} catch (FileNotFoundException e) {
SystemTapUIErrorMessages m = new SystemTapUIErrorMessages(
Messages.getString("SystemTapParser.InternalData"), //$NON-NLS-1$
Messages.getString("SystemTapParser.FailedToSetData"), //$NON-NLS-1$
Messages.getString("SystemTapParser.FailedToSetDataMessage")); //$NON-NLS-1$
m.schedule();
return Status.CANCEL_STATUS;
}
} else {
returnStatus = nonRealTimeParsing();
if (!returnStatus.isOK()){
return returnStatus;
}
setData(this);
return returnStatus;
}
}
/**
* For easier JUnit testing only. Allows public access to run method without
* scheduling an extra job.
*
* @param m
* @return
*/
public IStatus testRun(IProgressMonitor m, boolean realTime) {
try {
internalData = new BufferedReader(new FileReader(new File(
sourcePath)));
if (realTime) {
return realTimeParsing();
} else {
return nonRealTimeParsing();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return Status.CANCEL_STATUS;
}
/**
* @return the Data object
*/
public Object getData() {
return data;
}
/**
* Generic method for setting the internalData object. This will be called
* by a real-time-parser immediately before its main polling loop. By default,
* this method will attempt to create a bufferedReader around File(filePath)
* @throws FileNotFoundException
*/
protected void setInternalData() throws FileNotFoundException {
File file = new File(sourcePath);
internalData = new BufferedReader(new FileReader(file));
}
/**
* Gets the file to read from
*
* @return
*/
public String getFile() {
return sourcePath;
}
/**
* Sets the file to read from
*
* @param source
*/
public void setSourcePath(String source) {
this.sourcePath = source;
}
/**
* Will terminate the parser at the next opportunity (~once every 0.5s)s
*
* @param val
*/
public void setDone(boolean val) {
done = val;
}
public void setMonitor(IProgressMonitor m) {
this.monitor = m;
}
/**
* Set whether or not this parser runs in real time. If viewID has already
* been set, this will also attempt to open the view.
*/
public void setRealTime(boolean val) {
realTime = val;
}
/**
* Set the viewID to use for this parser -- see the callgraph.core view
* extension point. If realTime is set to true, this will also attempt to
* open the view.
*/
public void setViewID(String value) {
viewID = value;
}
/**
* Called at the end of a non-realtime run.
* Feel free to override this method if using non-realtime functions.
* The setData method will be called after executeParsing() is run.
* The getData() method will be used by the SystemTapView to get the
* data associated with this parser.
* <br><br>
* Alternatively, you can cast the parser within SystemTapView to your
* own parser class and access its data structures that way.
*/
public void setData(Object obj) {
data = obj;
}
/**
* Sends a message to cancel the job. Job may not terminate immediately.
*/
public void cancelJob() {
done = true;
}
public boolean isDone() {
return done;
}
public void setKillButtonEnabled(boolean val) {
if (view != null) {
view.setKillButtonEnabled(val);
}
}
public void setSecondaryID(String secondaryID) {
this.secondaryID = secondaryID;
}
public String getSecondaryID() {
return secondaryID;
}
}