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 model
|
||||||
def view
|
def view
|
||||||
|
|
||||||
|
def syncTimers = [:]
|
||||||
|
|
||||||
void mvcGroupInit(Map args) {
|
void mvcGroupInit(Map args) {
|
||||||
|
|
||||||
|
def configFile
|
||||||
|
|
||||||
logger.traceIfEnabled("Initializing TimeStamperMain MVC...")
|
logger.traceIfEnabled("Initializing TimeStamperMain MVC...")
|
||||||
|
|
||||||
def thisMVC = ['model': model, 'view': view, 'controller': this]
|
def thisMVC = ['model': model, 'view': view, 'controller': this]
|
||||||
@ -23,13 +27,13 @@ class TimeStamperMainController {
|
|||||||
// load application properties
|
// load application properties
|
||||||
Properties prop = new Properties()
|
Properties prop = new Properties()
|
||||||
String userHomeDir = System.getProperty('user.home')
|
String userHomeDir = System.getProperty('user.home')
|
||||||
model.configFile = new File(userHomeDir, ".timestamperrc")
|
configFile = new File(userHomeDir, ".timestamperrc")
|
||||||
if (!model.configFile.exists()) model.configFile.createNewFile()
|
if (!configFile.exists()) configFile.createNewFile()
|
||||||
|
|
||||||
logger.traceIfEnabled("Reading configuration from "
|
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) {
|
catch (IOException ioe) {
|
||||||
logger.error('Unable to load configuration', ioe)
|
logger.error('Unable to load configuration', ioe)
|
||||||
}
|
}
|
||||||
@ -45,8 +49,9 @@ class TimeStamperMainController {
|
|||||||
|
|
||||||
logger.traceIfEnabled("Reading Timeline properties from '${lastUsed}'")
|
logger.traceIfEnabled("Reading Timeline properties from '${lastUsed}'")
|
||||||
|
|
||||||
File propertyFile = new File(lastUsed)
|
model.timelinePropertiesFile = new File(lastUsed)
|
||||||
if (!propertyFile.exists()) propertyFile.createNewFile()
|
if (!model.timelinePropertiesFile.exists())
|
||||||
|
model.timelinePropertiesFile.createNewFile()
|
||||||
|
|
||||||
load(propertyFile)
|
load(propertyFile)
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ class TimeStamperMainModel {
|
|||||||
@Bindable Timeline timeline
|
@Bindable Timeline timeline
|
||||||
@Bindable TimelineProperties timelineProperties
|
@Bindable TimelineProperties timelineProperties
|
||||||
Properties config
|
Properties config
|
||||||
File configFile
|
File timelinePropertiesFile
|
||||||
|
|
||||||
def notesDialogMVC
|
def notesDialogMVC
|
||||||
def punchcardDialogMVC
|
def punchcardDialogMVC
|
||||||
|
@ -6,8 +6,8 @@ import java.util.Timer;
|
|||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* A remote target synchronized against the local timeline.
|
||||||
* @author Jonathan Bernard ({@literal jonathan.bernard@gemalto.com})
|
* @author Jonathan Bernard (jonathan.bernard@gemalto.com)
|
||||||
*/
|
*/
|
||||||
public class SyncTarget {
|
public class SyncTarget {
|
||||||
|
|
||||||
@ -23,6 +23,9 @@ public class SyncTarget {
|
|||||||
protected boolean pullEnabled = true;
|
protected boolean pullEnabled = true;
|
||||||
protected boolean syncOnExit = true;
|
protected boolean syncOnExit = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
protected class SyncTask extends TimerTask {
|
protected class SyncTask extends TimerTask {
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
@ -109,21 +112,21 @@ public class SyncTarget {
|
|||||||
|
|
||||||
public long getSyncInterval() { return syncInterval; }
|
public long getSyncInterval() { return syncInterval; }
|
||||||
|
|
||||||
public synchronized void enablePush(boolean enablePush) {
|
public synchronized void setPushEnabled(boolean pushEnabled) {
|
||||||
this.pullEnabled = enablePush;
|
this.pullEnabled = pushEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPushEnabled() { return pushEnabled; }
|
public boolean getPushEnabled() { return pushEnabled; }
|
||||||
|
|
||||||
public synchronized void enablePull(boolean enablePull) {
|
public synchronized void setPullEnabled(boolean pullEnabled) {
|
||||||
this.pullEnabled = enablePull;
|
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;
|
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;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Jonathan Bernard {@literal <jdbernard@gmail.com>}
|
|
||||||
* A Timeline object represents a series of markers at specific points in time.
|
* 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
|
* It represents on logical timeline. The markers have a name or symbol (the
|
||||||
* mark.
|
* '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> {
|
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");
|
public static SimpleDateFormat longFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
|
||||||
private TreeSet<TimelineMarker> timelineList;
|
private TreeSet<TimelineMarker> timelineList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new, empty Timeline.
|
||||||
|
*/
|
||||||
public Timeline() {
|
public Timeline() {
|
||||||
timelineList = new TreeSet<TimelineMarker>();
|
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));
|
* 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)
|
||||||
public String getLastName(Date timestamp) {
|
* @param notes Additional notes about this marker.
|
||||||
TimelineMarker lastMarker = getLastMarker(timestamp);
|
* @return <code>true</code> if this Timeline was modified.
|
||||||
return (lastMarker == null ?
|
*/
|
||||||
"No previous marker." :
|
public boolean addMarker(Date timestamp, String name, String notes) {
|
||||||
lastMarker.getMark());
|
return timelineList.add(new TimelineMarker(timestamp, name, notes));
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLastNotes(Date timestamp) {
|
|
||||||
TimelineMarker lastMarker = getLastMarker(timestamp);
|
|
||||||
return (lastMarker == null ?
|
|
||||||
"No previous marker." :
|
|
||||||
lastMarker.getNotes());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
public TimelineMarker getLastMarker(Date timestamp) {
|
||||||
TimelineMarker lastMarker = null;
|
TimelineMarker lastMarker = null;
|
||||||
for (TimelineMarker tm : timelineList) {
|
for (TimelineMarker tm : timelineList) {
|
||||||
@ -55,8 +64,13 @@ public class Timeline implements Iterable<TimelineMarker> {
|
|||||||
return lastMarker;
|
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() {
|
public Iterator<TimelineMarker> iterator() {
|
||||||
@ -84,14 +98,31 @@ public class Timeline implements Iterable<TimelineMarker> {
|
|||||||
return difference;
|
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) {
|
for (TimelineMarker tm : t) {
|
||||||
if (!timelineList.contains(tm))
|
if (!timelineList.contains(tm)) {
|
||||||
timelineList.add(tm);
|
timelineList.add(tm);
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAll(Collection<TimelineMarker> c) {
|
/**
|
||||||
timelineList.addAll(c);
|
* 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.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.Collection;
|
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})
|
* @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 {
|
public class TimelineProperties {
|
||||||
|
|
||||||
@ -26,13 +52,19 @@ public class TimelineProperties {
|
|||||||
private static final Pattern remoteTimelinePropPattern =
|
private static final Pattern remoteTimelinePropPattern =
|
||||||
Pattern.compile("\\Q" + REMOTE_TIMELINE_BASE + "\\E([^\\s\\.=]+?)[\\.=].*");
|
Pattern.compile("\\Q" + REMOTE_TIMELINE_BASE + "\\E([^\\s\\.=]+?)[\\.=].*");
|
||||||
|
|
||||||
private File propertyFile;
|
|
||||||
private Timeline timeline;
|
private Timeline timeline;
|
||||||
private TimelineSource timelineSource;
|
private TimelineSource timelineSource;
|
||||||
private LinkedList<SyncTarget> syncTargets = new LinkedList<SyncTarget>();
|
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() {
|
public TimelineProperties() {
|
||||||
this.propertyFile = new File("timeline.default.properties");
|
File propertyFile = new File("timeline.default.properties");
|
||||||
Properties config = new Properties();
|
Properties config = new Properties();
|
||||||
|
|
||||||
File timelineFile = new File("timeline.default.txt");
|
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;
|
String strURI;
|
||||||
URI timelineURI;
|
URI timelineURI;
|
||||||
|
|
||||||
this.propertyFile = propertyFile;
|
|
||||||
Properties config = new Properties();
|
Properties config = new Properties();
|
||||||
try {
|
try {
|
||||||
config.load(new InputStreamReader(new FileInputStream(propertyFile)));
|
config.load(new InputStreamReader(is));
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
@ -112,11 +147,11 @@ public class TimelineProperties {
|
|||||||
syncTargets.add(st);
|
syncTargets.add(st);
|
||||||
|
|
||||||
// check for synch options
|
// check for synch options
|
||||||
st.enablePull(Boolean.parseBoolean(
|
st.setPullEnabled(Boolean.parseBoolean(
|
||||||
config.getProperty(remoteBase + ".pull", "true")));
|
config.getProperty(remoteBase + ".pull", "true")));
|
||||||
st.enablePush(Boolean.parseBoolean(
|
st.setPushEnabled(Boolean.parseBoolean(
|
||||||
config.getProperty(remoteBase + ".push", "true")));
|
config.getProperty(remoteBase + ".push", "true")));
|
||||||
st.enableSyncOnExit(Boolean.parseBoolean(
|
st.setSyncOnExit(Boolean.parseBoolean(
|
||||||
config.getProperty(remoteBase + ".sync-on-exit", "true")));
|
config.getProperty(remoteBase + ".sync-on-exit", "true")));
|
||||||
st.setSyncInterval(Long.parseLong(
|
st.setSyncInterval(Long.parseLong(
|
||||||
config.getProperty(remoteBase + ".update-interval",
|
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();
|
Properties config = new Properties();
|
||||||
timelineSource.persist(timeline);
|
timelineSource.persist(timeline);
|
||||||
|
|
||||||
@ -137,27 +172,22 @@ public class TimelineProperties {
|
|||||||
config.setProperty(remoteBase + ".uri",
|
config.setProperty(remoteBase + ".uri",
|
||||||
st.getSource().getURI().toString());
|
st.getSource().getURI().toString());
|
||||||
config.setProperty(remoteBase + ".pull",
|
config.setProperty(remoteBase + ".pull",
|
||||||
Boolean.toString(st.isPullEnabled()));
|
Boolean.toString(st.getPullEnabled()));
|
||||||
config.setProperty(remoteBase + ".push",
|
config.setProperty(remoteBase + ".push",
|
||||||
Boolean.toString(st.isPushEnabled()));
|
Boolean.toString(st.getPushEnabled()));
|
||||||
config.setProperty(remoteBase + ".sync-on-exit",
|
config.setProperty(remoteBase + ".sync-on-exit",
|
||||||
Boolean.toString(st.isSyncOnExitEnabled()));
|
Boolean.toString(st.getSyncOnExit()));
|
||||||
config.setProperty(remoteBase + ".update-interval",
|
config.setProperty(remoteBase + ".update-interval",
|
||||||
Long.toString(st.getSyncInterval()));
|
Long.toString(st.getSyncInterval()));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
config.store(new FileOutputStream(propertyFile), "");
|
config.store(os, "");
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save(File newFile) throws IOException {
|
|
||||||
propertyFile = newFile;
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Timeline getTimeline() { return timeline; }
|
public Timeline getTimeline() { return timeline; }
|
||||||
|
|
||||||
public void setTimelineSource(TimelineSource newSource) {
|
public void setTimelineSource(TimelineSource newSource) {
|
||||||
|
@ -4,8 +4,8 @@ import java.io.IOException;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* A means of loading and persisting a Timeline.
|
||||||
* @author Jonathan Bernard ({@literal jonathan.bernard@gemalto.com})
|
* @author Jonathan Bernard (jonathan.bernard@gemalto.com)
|
||||||
*/
|
*/
|
||||||
public abstract class TimelineSource {
|
public abstract class TimelineSource {
|
||||||
|
|
||||||
@ -13,11 +13,36 @@ public abstract class TimelineSource {
|
|||||||
|
|
||||||
public TimelineSource(URI uri) { this.uri = uri; }
|
public TimelineSource(URI uri) { this.uri = uri; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the Timeline from the source.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public abstract Timeline read() 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;
|
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();
|
public abstract boolean isAuthenticated();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate the client to this source.
|
||||||
|
* @throws AuthenticationException
|
||||||
|
*/
|
||||||
public abstract void authenticate() 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() {
|
public URI getURI() {
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user