Version 1.1: Added support for web timelines.
Web timelines as defined by the JDB Labs Web TimeStamper tool are now supported. * `TimelineSource` now also takes the timeline config file as constructor input. * Refactored `Timeline` to use reduce implementation redundencies: internal implementations do not duplicate functionality. * Improved comments in `TimelineProperties`. * Updated `TimelineSourceFactory` to handle timelines that need to use `JDBLabsWebTimelineSource`.
This commit is contained in:
parent
c061ea6c1f
commit
3ca6909b95
BIN
lib/compile/jar/commons-beanutils-1.8.0.jar
Normal file
BIN
lib/compile/jar/commons-beanutils-1.8.0.jar
Normal file
Binary file not shown.
BIN
lib/compile/jar/commons-codec-1.4.jar
Normal file
BIN
lib/compile/jar/commons-codec-1.4.jar
Normal file
Binary file not shown.
BIN
lib/compile/jar/http-builder-0.5.1.jar
Normal file
BIN
lib/compile/jar/http-builder-0.5.1.jar
Normal file
Binary file not shown.
BIN
lib/compile/jar/httpclient-4.1.1.jar
Normal file
BIN
lib/compile/jar/httpclient-4.1.1.jar
Normal file
Binary file not shown.
BIN
lib/compile/jar/httpcore-4.1.jar
Normal file
BIN
lib/compile/jar/httpcore-4.1.jar
Normal file
Binary file not shown.
BIN
lib/compile/jar/jcl-over-slf4j-1.6.1.jar
Normal file
BIN
lib/compile/jar/jcl-over-slf4j-1.6.1.jar
Normal file
Binary file not shown.
BIN
lib/compile/jar/slf4j-api-1.6.1.jar
Normal file
BIN
lib/compile/jar/slf4j-api-1.6.1.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/commons-beanutils-1.8.0.jar
Normal file
BIN
lib/runtime/jar/commons-beanutils-1.8.0.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/commons-codec-1.4.jar
Normal file
BIN
lib/runtime/jar/commons-codec-1.4.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/commons-collections-3.2.1.jar
Normal file
BIN
lib/runtime/jar/commons-collections-3.2.1.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/commons-lang-2.4.jar
Normal file
BIN
lib/runtime/jar/commons-lang-2.4.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/ezmorph-1.0.6.jar
Normal file
BIN
lib/runtime/jar/ezmorph-1.0.6.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/http-builder-0.5.1.jar
Normal file
BIN
lib/runtime/jar/http-builder-0.5.1.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/httpclient-4.1.1.jar
Normal file
BIN
lib/runtime/jar/httpclient-4.1.1.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/httpclient-cache-4.1.1.jar
Normal file
BIN
lib/runtime/jar/httpclient-cache-4.1.1.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/httpcore-4.1.jar
Normal file
BIN
lib/runtime/jar/httpcore-4.1.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/httpmime-4.1.1.jar
Normal file
BIN
lib/runtime/jar/httpmime-4.1.1.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/jcl-over-slf4j-1.6.1.jar
Normal file
BIN
lib/runtime/jar/jcl-over-slf4j-1.6.1.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/jdb-util-1.1.jar
Normal file
BIN
lib/runtime/jar/jdb-util-1.1.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/json-lib-2.3-jdk15.jar
Normal file
BIN
lib/runtime/jar/json-lib-2.3-jdk15.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/logback-classic-0.9.26.jar
Normal file
BIN
lib/runtime/jar/logback-classic-0.9.26.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/logback-core-0.9.26.jar
Normal file
BIN
lib/runtime/jar/logback-core-0.9.26.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/nekohtml-1.9.9.jar
Normal file
BIN
lib/runtime/jar/nekohtml-1.9.9.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/signpost-commonshttp4-1.2.1.1.jar
Normal file
BIN
lib/runtime/jar/signpost-commonshttp4-1.2.1.1.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/signpost-core-1.2.1.1.jar
Normal file
BIN
lib/runtime/jar/signpost-core-1.2.1.1.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/slf4j-api-1.6.1.jar
Normal file
BIN
lib/runtime/jar/slf4j-api-1.6.1.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/xercesImpl-2.8.1.jar
Normal file
BIN
lib/runtime/jar/xercesImpl-2.8.1.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/xml-apis-1.3.04.jar
Normal file
BIN
lib/runtime/jar/xml-apis-1.3.04.jar
Normal file
Binary file not shown.
BIN
lib/runtime/jar/xml-resolver-1.2.jar
Normal file
BIN
lib/runtime/jar/xml-resolver-1.2.jar
Normal file
Binary file not shown.
@ -1,6 +1,6 @@
|
||||
#Thu, 16 Jun 2011 12:41:01 -0500
|
||||
#Mon, 27 Jun 2011 17:12:00 -0500
|
||||
name=timestamper-lib
|
||||
version=1.0
|
||||
version=1.1
|
||||
lib.local=true
|
||||
|
||||
build.number=2
|
||||
build.number=1
|
||||
|
Binary file not shown.
BIN
release/timestamper-lib-1.1.jar
Normal file
BIN
release/timestamper-lib-1.1.jar
Normal file
Binary file not shown.
12
resources/main/test.groovy
Normal file
12
resources/main/test.groovy
Normal file
@ -0,0 +1,12 @@
|
||||
import groovyx.net.http.HTTPBuilder
|
||||
import com.jdbernard.util.SmartConfig
|
||||
import com.jdblabs.timestamper.core.*
|
||||
|
||||
smartConfig = new SmartConfig("temp.config")
|
||||
smartConfig."web.username" = "jdbernard"
|
||||
smartConfig."web.password" = "Y0uthc"
|
||||
smartConfig."web.timelineId" = "work"
|
||||
|
||||
uri = new URI("http://timestamper-local:8000")
|
||||
|
||||
wtls = new JDBLabsWebTimelineSource(uri, smartConfig)
|
@ -1,5 +1,6 @@
|
||||
package com.jdblabs.timestamper.core;
|
||||
|
||||
import com.jdbernard.util.SmartConfig;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
@ -15,7 +16,7 @@ public class FileTimelineSource extends TimelineSource {
|
||||
|
||||
private File file;
|
||||
|
||||
public FileTimelineSource(URI uri) {
|
||||
public FileTimelineSource(URI uri, SmartConfig config) {
|
||||
super(uri);
|
||||
this.file = new File(uri);
|
||||
}
|
||||
|
@ -0,0 +1,165 @@
|
||||
package com.jdblabs.timestamper.core
|
||||
|
||||
import com.jdbernard.util.SmartConfig
|
||||
import groovyx.net.http.HTTPBuilder
|
||||
import java.text.SimpleDateFormat
|
||||
|
||||
import static groovyx.net.http.ContentType.*
|
||||
import static groovyx.net.http.Method.*
|
||||
|
||||
public class JDBLabsWebTimelineSource extends TimelineSource {
|
||||
|
||||
private static final String CONFIG_UNAME = "web.username"
|
||||
private static final String CONFIG_PWD = "web.password"
|
||||
private static final String CONFIG_TIMELINE = "web.timelineId"
|
||||
|
||||
private static isoDateFormat
|
||||
|
||||
static {
|
||||
isoDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
|
||||
isoDateFormat.timeZone = TimeZone.getTimeZone("UTC")
|
||||
}
|
||||
|
||||
private String username
|
||||
private String password
|
||||
private String timelineId
|
||||
|
||||
private URI baseUri
|
||||
private HTTPBuilder http
|
||||
|
||||
private Map entryHashes
|
||||
|
||||
public JDBLabsWebTimelineSource(URI uri, SmartConfig config) {
|
||||
super(uri)
|
||||
|
||||
// load web-timeline specific properties
|
||||
username = config.getProperty(CONFIG_UNAME, "")
|
||||
password = config.getProperty(CONFIG_PWD, "")
|
||||
timelineId = config.getProperty(CONFIG_TIMELINE, "")
|
||||
|
||||
baseUri = new URI(uri.scheme + "://" + uri.authority)
|
||||
http = new HTTPBuilder(baseUri)
|
||||
|
||||
entryHashes = [:]
|
||||
}
|
||||
|
||||
public Timeline read() {
|
||||
def timelineJSON
|
||||
def entryListJSON
|
||||
def startDate, endDate
|
||||
Timeline timeline
|
||||
|
||||
// make sure we have a fresh session
|
||||
authenticate()
|
||||
|
||||
// load the timeline information
|
||||
timelineJSON = http.get(
|
||||
path: "/ts_api/timelines/${username}/${timelineId}",
|
||||
contentType: JSON) { resp, json -> json }
|
||||
|
||||
timeline = new Timeline()
|
||||
|
||||
// create start and end times
|
||||
startDate = Calendar.getInstance()
|
||||
startDate.timeInMillis = 0
|
||||
startDate = isoDateFormat.format(startDate.time)
|
||||
|
||||
endDate = isoDateFormat.format(Calendar.getInstance().time)
|
||||
|
||||
// load the timeline entries
|
||||
entryListJSON = http.get(
|
||||
path: "/ts_api/entries/${username}/${timelineId}",
|
||||
contentType: JSON,
|
||||
query: [
|
||||
byDate: true,
|
||||
startDate: startDate,
|
||||
endDate: endDate ] ) { resp, json -> json }
|
||||
|
||||
entryListJSON.each { entry ->
|
||||
|
||||
// parse and create the timeline marker
|
||||
def timestamp = isoDateFormat.parse(entry.timestamp)
|
||||
def marker = new TimelineMarker(timestamp, entry.mark, entry.notes)
|
||||
|
||||
// add it to the timeline and our map of hashes
|
||||
timeline.addMarker(marker)
|
||||
entryHashes[fullHash(marker)] = entry.id
|
||||
}
|
||||
|
||||
// return the created timeline
|
||||
return timeline
|
||||
}
|
||||
|
||||
public void persist(Timeline t) {
|
||||
Map deletedEntries
|
||||
List newEntries
|
||||
|
||||
// make sure we have a fresh session
|
||||
authenticate()
|
||||
|
||||
// find differences since we last persisted
|
||||
deletedEntries = entryHashes.clone() // shallow copy
|
||||
newEntries = []
|
||||
|
||||
t.each { marker ->
|
||||
def hash = fullHash(marker)
|
||||
|
||||
// this marker is present, remove from deletedEntries
|
||||
if (deletedEntries.containsKey(hash)) {
|
||||
deletedEntries.remove(hash) }
|
||||
|
||||
// this marker is not present, add to newEntries
|
||||
else { newEntries << marker }
|
||||
}
|
||||
|
||||
// delete all entries that used to be present but are not any longer
|
||||
deletedEntries.each { hash, entryId ->
|
||||
http.request(DELETE) {
|
||||
uri.path = "/ts_api/entries/${username}/${timelineId}/${entryId}"
|
||||
}
|
||||
|
||||
// TODO: error handling, make sure this only happens on success
|
||||
entryHashes.remove(hash)
|
||||
}
|
||||
|
||||
// add all new entries
|
||||
newEntries.each { entry ->
|
||||
|
||||
def entryBody = [
|
||||
mark: entry.mark,
|
||||
notes: entry.notes,
|
||||
timestamp: isoDateFormat.format(entry.timestamp)
|
||||
]
|
||||
|
||||
// TODO: error handling
|
||||
http.post(
|
||||
path: "/ts_api/entries/${username}/${timelineId}",
|
||||
contentType: JSON,
|
||||
requestContentType: JSON,
|
||||
body: entryBody) { resp, json ->
|
||||
entryHashes.put(fullHash(entry), entry)
|
||||
json
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean isAuthenticated() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void authenticate() {
|
||||
// TODO: error detection
|
||||
http.post(
|
||||
path: '/ts_api/login',
|
||||
contentType: JSON,
|
||||
requestContentType: JSON,
|
||||
body: [ username: this.username,
|
||||
password: this.password ]) { resp, json -> json }
|
||||
|
||||
}
|
||||
|
||||
protected int fullHash(TimelineMarker tm) {
|
||||
return 61 * tm.hashCode() + (tm.mark != null ? tm.mark.hashCode() : 0);
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ public class Timeline implements Iterable<TimelineMarker> {
|
||||
|
||||
public static SimpleDateFormat shortFormat = new SimpleDateFormat("HH:mm:ss");
|
||||
public static SimpleDateFormat longFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
|
||||
private TreeSet<TimelineMarker> timelineList;
|
||||
protected TreeSet<TimelineMarker> timelineList;
|
||||
|
||||
/**
|
||||
* Create a new, empty Timeline.
|
||||
@ -42,7 +42,7 @@ public class Timeline implements Iterable<TimelineMarker> {
|
||||
* @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));
|
||||
return addMarker(new TimelineMarker(timestamp, name, notes));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -107,11 +107,7 @@ public class Timeline implements Iterable<TimelineMarker> {
|
||||
public boolean addAll(Timeline t) {
|
||||
boolean modified = false;
|
||||
for (TimelineMarker tm : t) {
|
||||
if (!timelineList.contains(tm)) {
|
||||
timelineList.add(tm);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
modified = addMarker(tm) || modified; }
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ public class TimelineProperties {
|
||||
URI timelineURI = timelineFile.toURI();
|
||||
|
||||
timeline = new Timeline();
|
||||
timelineSource = TimelineSourceFactory.newInstance(timelineURI);
|
||||
timelineSource = TimelineSourceFactory.newInstance(timelineURI, config);
|
||||
persistOnUpdate = true;
|
||||
try { timelineSource.persist(timeline); }
|
||||
catch (IOException ioe) {
|
||||
@ -84,8 +84,8 @@ public class TimelineProperties {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load TimelineProperties from an InputStream.
|
||||
* @param is
|
||||
* Load TimelineProperties from a config file.
|
||||
* @param propFile
|
||||
*/
|
||||
public TimelineProperties(File propFile) throws IOException {
|
||||
String strURI;
|
||||
@ -97,8 +97,10 @@ public class TimelineProperties {
|
||||
persistOnUpdate = (Boolean) config.getProperty(
|
||||
LOCAL_TIMELINE_PERSIST_ON_UPDATE, true);
|
||||
|
||||
// load local timeline
|
||||
// get the URI for the primary timeline
|
||||
strURI = (String) config.getProperty(LOCAL_TIMELINE_URI, "");
|
||||
|
||||
// no primary timeline, default to file-based timeline
|
||||
if ("".equals(strURI)) {
|
||||
File defaultTimelineFile = new File("timeline.default.txt");
|
||||
try {
|
||||
@ -108,7 +110,7 @@ public class TimelineProperties {
|
||||
// TODO
|
||||
}
|
||||
timelineURI = defaultTimelineFile.toURI();
|
||||
} else {
|
||||
} else { // we do have a URI
|
||||
try { timelineURI = new URI(strURI); }
|
||||
catch (URISyntaxException urise) {
|
||||
throw new IOException("Unable to load the timeline: the timeline "
|
||||
@ -116,7 +118,8 @@ public class TimelineProperties {
|
||||
}
|
||||
}
|
||||
|
||||
timelineSource = TimelineSourceFactory.newInstance(timelineURI);
|
||||
// create our timeline source and read the timeline
|
||||
timelineSource = TimelineSourceFactory.newInstance(timelineURI, config);
|
||||
timeline = timelineSource.read();
|
||||
|
||||
// search keys for remote timeline entries
|
||||
@ -143,7 +146,7 @@ public class TimelineProperties {
|
||||
|
||||
// add a new SyncTarget to the list
|
||||
st = new SyncTarget(stName, TimelineSourceFactory
|
||||
.newInstance(timelineURI), timeline);
|
||||
.newInstance(timelineURI, config), timeline);
|
||||
syncTargets.add(st);
|
||||
|
||||
// check for synch options
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.jdblabs.timestamper.core;
|
||||
|
||||
import com.jdbernard.util.SmartConfig;
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
|
||||
@ -9,10 +10,10 @@ import java.net.URI;
|
||||
*/
|
||||
public class TimelineSourceFactory {
|
||||
|
||||
public static TimelineSource newInstance(URI uri) {
|
||||
public static TimelineSource newInstance(URI uri, SmartConfig config) {
|
||||
// File based
|
||||
if ("file".equalsIgnoreCase(uri.getScheme())) {
|
||||
return new FileTimelineSource(uri);
|
||||
return new FileTimelineSource(uri, config);
|
||||
}
|
||||
|
||||
// Twitter
|
||||
@ -23,6 +24,11 @@ public class TimelineSourceFactory {
|
||||
+ "sources are not yet supported.");
|
||||
}
|
||||
|
||||
// Other HTTP, assume JDB Labs web app
|
||||
else if ("http".equalsIgnoreCase(uri.getScheme())) {
|
||||
return new JDBLabsWebTimelineSource(uri, config);
|
||||
}
|
||||
|
||||
// SSH
|
||||
else if ("ssh".equalsIgnoreCase(uri.getScheme())) {
|
||||
throw new UnsupportedOperationException("SSH based timeline sources"
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.jdblabs.timestamper.core;
|
||||
|
||||
import com.jdbernard.util.SmartConfig;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user