Added documentation, fleshed out accessors for class Timeline.
This commit is contained in:
parent
6d212ea771
commit
7f2c1a6d53
BIN
doc/uml.tsm
Normal file
BIN
doc/uml.tsm
Normal file
Binary file not shown.
@ -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)
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ class TimeStamperMainModel {
|
||||
@Bindable Timeline timeline
|
||||
@Bindable TimelineProperties timelineProperties
|
||||
Properties config
|
||||
File configFile
|
||||
File timelinePropertiesFile
|
||||
|
||||
def notesDialogMVC
|
||||
def punchcardDialogMVC
|
||||
|
@ -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; }
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user