Added documentation, fleshed out accessors for class Timeline.

This commit is contained in:
Jonathan Bernard 2010-01-06 09:57:17 -06:00
parent 6d212ea771
commit 7f2c1a6d53
9 changed files with 160 additions and 65 deletions

View File

@ -1,3 +1,4 @@
.*.swp
.*.swo
staging
dist

BIN
CHANGE ME Normal file

Binary file not shown.

BIN
doc/uml.tsm Normal file

Binary file not shown.

View File

@ -8,8 +8,12 @@ class TimeStamperMainController {
def model
def view
def syncTimers = [:]
void mvcGroupInit(Map args) {
def configFile
logger.traceIfEnabled("Initializing TimeStamperMain MVC...")
def thisMVC = ['model': model, 'view': view, 'controller': this]
@ -23,13 +27,13 @@ class TimeStamperMainController {
// load application properties
Properties prop = new Properties()
String userHomeDir = System.getProperty('user.home')
model.configFile = new File(userHomeDir, ".timestamperrc")
if (!model.configFile.exists()) model.configFile.createNewFile()
configFile = new File(userHomeDir, ".timestamperrc")
if (!configFile.exists()) configFile.createNewFile()
logger.traceIfEnabled("Reading configuration from "
+ "'${model.configFile.name}'")
+ "'${configFile.name}'")
try { model.configFile.withInputStream { prop.load(it) } }
try { configFile.withInputStream { prop.load(it) } }
catch (IOException ioe) {
logger.error('Unable to load configuration', ioe)
}
@ -45,8 +49,9 @@ class TimeStamperMainController {
logger.traceIfEnabled("Reading Timeline properties from '${lastUsed}'")
File propertyFile = new File(lastUsed)
if (!propertyFile.exists()) propertyFile.createNewFile()
model.timelinePropertiesFile = new File(lastUsed)
if (!model.timelinePropertiesFile.exists())
model.timelinePropertiesFile.createNewFile()
load(propertyFile)
}

View File

@ -13,7 +13,7 @@ class TimeStamperMainModel {
@Bindable Timeline timeline
@Bindable TimelineProperties timelineProperties
Properties config
File configFile
File timelinePropertiesFile
def notesDialogMVC
def punchcardDialogMVC

View File

@ -6,8 +6,8 @@ import java.util.Timer;
import java.util.TimerTask;
/**
*
* @author Jonathan Bernard ({@literal jonathan.bernard@gemalto.com})
* A remote target synchronized against the local timeline.
* @author Jonathan Bernard (jonathan.bernard@gemalto.com)
*/
public class SyncTarget {
@ -23,6 +23,9 @@ public class SyncTarget {
protected boolean pullEnabled = true;
protected boolean syncOnExit = true;
/**
*
*/
protected class SyncTask extends TimerTask {
@Override public void run() {
synchronized(this) {
@ -109,21 +112,21 @@ public class SyncTarget {
public long getSyncInterval() { return syncInterval; }
public synchronized void enablePush(boolean enablePush) {
this.pullEnabled = enablePush;
public synchronized void setPushEnabled(boolean pushEnabled) {
this.pullEnabled = pushEnabled;
}
public boolean isPushEnabled() { return pushEnabled; }
public boolean getPushEnabled() { return pushEnabled; }
public synchronized void enablePull(boolean enablePull) {
this.pullEnabled = enablePull;
public synchronized void setPullEnabled(boolean pullEnabled) {
this.pullEnabled = pullEnabled;
}
public boolean isPullEnabled() { return pullEnabled; }
public boolean getPullEnabled() { return pullEnabled; }
public synchronized void enableSyncOnExit(boolean syncOnExit) {
public synchronized void setSyncOnExit(boolean syncOnExit) {
this.syncOnExit = syncOnExit;
}
public boolean isSyncOnExitEnabled() { return syncOnExit; }
public boolean getSyncOnExit() { return syncOnExit; }
}

View File

@ -8,10 +8,11 @@ import java.util.Iterator;
import java.util.TreeSet;
/**
* @author Jonathan Bernard {@literal <jdbernard@gmail.com>}
* A Timeline object represents a series of markers at specific points in time.
* The markers have a name or symbol (the 'mark') and notes associated with that
* mark.
* It represents on logical timeline. The markers have a name or symbol (the
* 'mark') and notes associated with that mark.
* @author Jonathan Bernard {@literal <jdbernard@gmail.com>}
* @see com.jdbernard.timestamper.core.TimelineSource
*/
public class Timeline implements Iterable<TimelineMarker> {
@ -19,31 +20,39 @@ public class Timeline implements Iterable<TimelineMarker> {
public static SimpleDateFormat longFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
private TreeSet<TimelineMarker> timelineList;
/**
* Create a new, empty Timeline.
*/
public Timeline() {
timelineList = new TreeSet<TimelineMarker>();
}
public void addMarker(TimelineMarker tm) { timelineList.add(tm); }
/**
* Add a marker to the timeline.
* @param tm The TimelineMarker to add.
* @return <code>true</code> if this Timeline was modified.
*/
public boolean addMarker(TimelineMarker tm) { return timelineList.add(tm); }
public void addMarker(Date timestamp, String name, String notes) {
timelineList.add(new TimelineMarker(timestamp, name, notes));
}
public String getLastName(Date timestamp) {
TimelineMarker lastMarker = getLastMarker(timestamp);
return (lastMarker == null ?
"No previous marker." :
lastMarker.getMark());
}
public String getLastNotes(Date timestamp) {
TimelineMarker lastMarker = getLastMarker(timestamp);
return (lastMarker == null ?
"No previous marker." :
lastMarker.getNotes());
/**
* Add a marker to the timeline.
* @param timestamp The date and time of the marker.
* @param name The name of the marker (activity, project, etc)
* @param notes Additional notes about this marker.
* @return <code>true</code> if this Timeline was modified.
*/
public boolean addMarker(Date timestamp, String name, String notes) {
return timelineList.add(new TimelineMarker(timestamp, name, notes));
}
/**
* Get the last marker placed before or on the given timestamp. If you
* think of the markers as demarcating time, then this is effectivly,
* "get the current task."
* @param timestamp The cut-off point for the query.
* @return The latest TimelineMarker placed on or before the given
* timestamp.
*/
public TimelineMarker getLastMarker(Date timestamp) {
TimelineMarker lastMarker = null;
for (TimelineMarker tm : timelineList) {
@ -55,8 +64,13 @@ public class Timeline implements Iterable<TimelineMarker> {
return lastMarker;
}
public void removeMarker(TimelineMarker marker) {
timelineList.remove(marker);
/**
* Remove a TimelineMarker from this Timelnie.
* @param marker The marker to remove.
* @return <code>true</code> if this Timeline was changed.
*/
public boolean removeMarker(TimelineMarker marker) {
return timelineList.remove(marker);
}
public Iterator<TimelineMarker> iterator() {
@ -84,14 +98,31 @@ public class Timeline implements Iterable<TimelineMarker> {
return difference;
}
public void addAll(Timeline t) {
/**
* Add all TimelineMarkers from <code>t</code> to <code>this</code>
* Timeline, excluding markers already present in <code>this</code>.
* @param t
* @return <code>true</code> if this Timeline was modified.
*/
public boolean addAll(Timeline t) {
boolean modified = false;
for (TimelineMarker tm : t) {
if (!timelineList.contains(tm))
if (!timelineList.contains(tm)) {
timelineList.add(tm);
modified = true;
}
}
public void addAll(Collection<TimelineMarker> c) {
timelineList.addAll(c);
return modified;
}
/**
* Add all TimelineMarkers from <code>c</code> to <code>this</code>
* Timeline, excluding markers already present in <code>this</code>.
* @param c A Collection of TimelineMarkers
* @return <code>true</code> if this TImeline was modified.
*/
public boolean addAll(Collection<TimelineMarker> c) {
return timelineList.addAll(c);
}
}

View File

@ -4,7 +4,9 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
@ -15,8 +17,32 @@ import java.util.regex.Pattern;
/**
*
* Represents a Timeline configuration. A configuration has one primary, or
* local, Timeline with an associated TimelineSource, and a list of remote
* Timelines synched to the local Timeline.
* <br>
* <table>
* <tr><th>Property</th><th>Description</th></tr>
* <tr><td><code>timeline.uri</code></td><td>The URI of the primary (local)
* timeline</td></tr>
* <tr><td><code>remote.timeline.</code><i>name</i><code>.uri</code></td>
* <td>The URI for the <i>name</i> remote timeline.</td></tr>
* <tr><td><code>remote.timeline.</code><i>name</i><code>.push</code></td>
* <td><code>true</code> to enable pushing updates to the <i>name</i>
* remote timeline, <code>false</code> to disable.</td></tr>
* <tr><td><code>remote.timeline.</code><i>name</i><code>.pull</code></td>
* <td><code>true</code> to enable pulling updates from the <i>name</i>
* remote timeline, <code>false</code> to disable.</td></tr>
* <tr><td><code>remote.timeline.</code><i>name</i><code>.save-on-exit</code>
* </td><td><code>true</code> to force sync the <i>name</i> remote
* timeline on exit.</td></tr>
* <tr><td><code>remote.timeline.</code><i>name</i>
* <code>.update-interval</code></td><td>The time in milliseconds between
* synching the <i>name</i> remote timeline.</td></tr></table>
* @author Jonathan Bernard ({@literal jonathan.bernard@gemalto.com})
* @see com.jdbernard.timestamper.core.Timeline
* @see com.jdbernard.timestamper.core.TimelineSource
* @see com.jdbernard.timestamper.core.SyncTarget
*/
public class TimelineProperties {
@ -26,13 +52,19 @@ public class TimelineProperties {
private static final Pattern remoteTimelinePropPattern =
Pattern.compile("\\Q" + REMOTE_TIMELINE_BASE + "\\E([^\\s\\.=]+?)[\\.=].*");
private File propertyFile;
private Timeline timeline;
private TimelineSource timelineSource;
private LinkedList<SyncTarget> syncTargets = new LinkedList<SyncTarget>();
/**
* Create new TimelineProperties, using default values. This will create
* a new configuration using a FileTimelineSource pointed at
* <code>'timeline.default.txt'</code> in the current directory and no
* remote Timelines. It will save this configuration to
* <code>'timeline.default.properties'</code> in the current directory.
*/
public TimelineProperties() {
this.propertyFile = new File("timeline.default.properties");
File propertyFile = new File("timeline.default.properties");
Properties config = new Properties();
File timelineFile = new File("timeline.default.txt");
@ -53,14 +85,17 @@ public class TimelineProperties {
}
}
public TimelineProperties(File propertyFile) throws IOException {
/**
* Load TimelineProperties from an InputStream.
* @param is
*/
public TimelineProperties(InputStream is) throws IOException {
String strURI;
URI timelineURI;
this.propertyFile = propertyFile;
Properties config = new Properties();
try {
config.load(new InputStreamReader(new FileInputStream(propertyFile)));
config.load(new InputStreamReader(is));
} catch (IOException ioe) {
// TODO
}
@ -112,11 +147,11 @@ public class TimelineProperties {
syncTargets.add(st);
// check for synch options
st.enablePull(Boolean.parseBoolean(
st.setPullEnabled(Boolean.parseBoolean(
config.getProperty(remoteBase + ".pull", "true")));
st.enablePush(Boolean.parseBoolean(
st.setPushEnabled(Boolean.parseBoolean(
config.getProperty(remoteBase + ".push", "true")));
st.enableSyncOnExit(Boolean.parseBoolean(
st.setSyncOnExit(Boolean.parseBoolean(
config.getProperty(remoteBase + ".sync-on-exit", "true")));
st.setSyncInterval(Long.parseLong(
config.getProperty(remoteBase + ".update-interval",
@ -125,7 +160,7 @@ public class TimelineProperties {
}
}
public void save() throws IOException {
public void save(OutputStream os) throws IOException {
Properties config = new Properties();
timelineSource.persist(timeline);
@ -137,27 +172,22 @@ public class TimelineProperties {
config.setProperty(remoteBase + ".uri",
st.getSource().getURI().toString());
config.setProperty(remoteBase + ".pull",
Boolean.toString(st.isPullEnabled()));
Boolean.toString(st.getPullEnabled()));
config.setProperty(remoteBase + ".push",
Boolean.toString(st.isPushEnabled()));
Boolean.toString(st.getPushEnabled()));
config.setProperty(remoteBase + ".sync-on-exit",
Boolean.toString(st.isSyncOnExitEnabled()));
Boolean.toString(st.getSyncOnExit()));
config.setProperty(remoteBase + ".update-interval",
Long.toString(st.getSyncInterval()));
}
try {
config.store(new FileOutputStream(propertyFile), "");
config.store(os, "");
} catch (IOException ioe) {
// TODO
}
}
public void save(File newFile) throws IOException {
propertyFile = newFile;
save();
}
public Timeline getTimeline() { return timeline; }
public void setTimelineSource(TimelineSource newSource) {

View File

@ -4,8 +4,8 @@ import java.io.IOException;
import java.net.URI;
/**
*
* @author Jonathan Bernard ({@literal jonathan.bernard@gemalto.com})
* A means of loading and persisting a Timeline.
* @author Jonathan Bernard (jonathan.bernard@gemalto.com)
*/
public abstract class TimelineSource {
@ -13,11 +13,36 @@ public abstract class TimelineSource {
public TimelineSource(URI uri) { this.uri = uri; }
/**
* Read the Timeline from the source.
* @throws IOException
*/
public abstract Timeline read() throws IOException;
/**
* Persist a give timeline to this source.
* @param t
* @throws IOException
*/
public abstract void persist(Timeline t) throws IOException;
/**
* Is this source authenticated and ready for IO.
* @return <code>true</code> if the source is authenticated (or if no
* authentication is required).
*/
public abstract boolean isAuthenticated();
/**
* Authenticate the client to this source.
* @throws AuthenticationException
*/
public abstract void authenticate() throws AuthenticationException;
/**
* Get the URI representing this source.
* @return The {@link java.net.URI} representing this source.
*/
public URI getURI() {
return uri;
}