Got stuff to compile, now synchronizing tags and notes. Well, now we attempt to anyways

pull/14/head
Tim Su 16 years ago
parent 06b389e413
commit f6faf9c1fa

@ -9,17 +9,17 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import android.app.Activity;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.widget.Toast;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService;
import com.todoroo.andlib.service.NotificationManager;
@ -129,10 +129,15 @@ public abstract class SynchronizationProvider<TYPE extends TaskContainer> {
}
public void synchronize(final Context context) {
// display toast
if(context instanceof Activity) {
Toast.makeText(context, R.string.SyP_progress_toast, Toast.LENGTH_LONG).show();
}
// display notification
notificationTitle = getNotificationTitle(context);
notificationIntent = PendingIntent.getActivity(context, 0, new Intent(), 0);
postUpdate(context, context.getString(R.string.SyP_progress_starting));
postUpdate(context, context.getString(R.string.SyP_progress));
final NotificationManager nm = new NotificationManager.AndroidNotificationManager(context);
nm.notify(Constants.NOTIFICATION_SYNC, notification);
@ -180,10 +185,7 @@ public abstract class SynchronizationProvider<TYPE extends TaskContainer> {
* @param data synchronization data structure
*/
protected void synchronizeTasks(SyncData data) throws IOException {
int length;
Context context = ContextManager.getContext();
Resources r = context.getResources();
// create internal data structures
HashMap<String, Integer> remoteNewTaskNameMap = new HashMap<String, Integer>();
@ -202,8 +204,6 @@ public abstract class SynchronizationProvider<TYPE extends TaskContainer> {
TaskContainer local = read(data.localCreated);
String taskTitle = local.task.getValue(Task.TITLE);
postUpdate(context, r.getString(R.string.SyP_progress_localtx,
taskTitle));
/* If there exists an incoming remote task with the same name and no
* mapping, we don't want to create this on the remote server,
@ -231,8 +231,6 @@ public abstract class SynchronizationProvider<TYPE extends TaskContainer> {
for(int i = 0; i < length; i++) {
data.localUpdated.moveToNext();
TaskContainer local = read(data.localUpdated);
postUpdate(context, r.getString(R.string.SyP_progress_localtx,
local.task.getValue(Task.TITLE)));
// if there is a conflict, merge
int remoteIndex = matchTask((ArrayList<TYPE>)data.remoteUpdated, (TYPE)local);
@ -281,9 +279,6 @@ public abstract class SynchronizationProvider<TYPE extends TaskContainer> {
length = data.remoteUpdated.size();
for(int i = 0; i < length; i++) {
TaskContainer remote = data.remoteUpdated.get(i);
postUpdate(context, r.getString(R.string.SyP_progress_remotetx,
remote.task.getValue(Task.TITLE)));
write((TYPE)remote);
}
}

@ -12,6 +12,7 @@ import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.TaskDetail;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.rmilk.data.MilkDataService;
import com.todoroo.astrid.rmilk.data.MilkTask;
/**
* Exposes {@link TaskDetail}s for Remember the Milk:
@ -42,7 +43,7 @@ public class MilkDetailExposer extends BroadcastReceiver {
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, Utilities.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
long listId = metadata.getValue(MilkDataService.LIST_ID);
long listId = metadata.getValue(MilkTask.LIST_ID);
if(listId > 0) {
TaskDetail detail = new TaskDetail(context.getString(R.string.rmilk_TLA_list,
MilkDataService.getInstance().getListName(listId)));
@ -50,7 +51,7 @@ public class MilkDetailExposer extends BroadcastReceiver {
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
int repeat = metadata.getValue(MilkDataService.REPEATING);
int repeat = metadata.getValue(MilkTask.REPEATING);
if(repeat != 0) {
TaskDetail detail = new TaskDetail(context.getString(R.string.rmilk_TLA_repeat));
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, detail);

@ -9,15 +9,18 @@ import android.content.Context;
import android.content.Intent;
import com.timsu.astrid.R;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterCategory;
import com.todoroo.astrid.api.FilterListHeader;
import com.todoroo.astrid.api.FilterListItem;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.rmilk.Utilities.ListContainer;
import com.todoroo.astrid.rmilk.data.MilkDataService;
import com.todoroo.astrid.rmilk.data.MilkTask;
/**
* Exposes filters based on RTM lists
@ -33,9 +36,12 @@ public class MilkFilterExposer extends BroadcastReceiver {
replace("$N", list.name).replace("$C", Integer.toString(list.count));
String title = context.getString(R.string.rmilk_FEx_list_title, list.name);
ContentValues values = new ContentValues();
values.put(Metadata.KEY.name, MilkDataService.METADATA_KEY);
values.put(MilkDataService.LIST_ID.name, list.id);
Filter filter = new Filter(listTitle, title, new QueryTemplate().join(MilkDataService.METADATA_JOIN).where(MilkDataService.LIST_ID.eq(list.id)),
values.put(Metadata.KEY.name, MilkTask.METADATA_KEY);
values.put(MilkTask.LIST_ID.name, list.id);
Filter filter = new Filter(listTitle, title, new QueryTemplate().join(
MilkDataService.METADATA_JOIN).where(Criterion.and(
MetadataCriteria.withKey(MilkTask.METADATA_KEY),
MilkTask.LIST_ID.eq(list.id))),
values);
return filter;

@ -3,18 +3,18 @@
*/
package com.todoroo.astrid.rmilk.data;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import android.content.Context;
import android.util.Log;
import com.todoroo.andlib.data.GenericDao;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.data.Property.CountProperty;
import com.todoroo.andlib.data.Property.IntegerProperty;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
@ -24,8 +24,8 @@ import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.Task;
@ -34,29 +34,11 @@ import com.todoroo.astrid.rmilk.Utilities.ListContainer;
import com.todoroo.astrid.rmilk.api.data.RtmList;
import com.todoroo.astrid.rmilk.api.data.RtmLists;
import com.todoroo.astrid.rmilk.sync.RTMTaskContainer;
import com.todoroo.astrid.tags.TagService;
public final class MilkDataService {
// --- public constants
/** metadata key */
public static final String METADATA_KEY = "rmilk"; //$NON-NLS-1$
/** {@link MilkList} id */
public static final LongProperty LIST_ID = new LongProperty(Metadata.TABLE,
Metadata.VALUE1.name);
/** RTM Task Series Id */
public static final LongProperty TASK_SERIES_ID = new LongProperty(Metadata.TABLE,
Metadata.VALUE2.name);
/** RTM Task Id */
public static final LongProperty TASK_ID = new LongProperty(Metadata.TABLE,
Metadata.VALUE3.name);
/** Whether task repeats in RTM (1 or 0) */
public static final IntegerProperty REPEATING = new IntegerProperty(Metadata.TABLE,
Metadata.VALUE4.name);
// --- constants
/** Utility for joining tasks with metadata */
public static final Join METADATA_JOIN = Join.left(Metadata.TABLE, Task.ID.eq(Metadata.TASK));
@ -100,7 +82,7 @@ public final class MilkDataService {
* Clears RTM metadata information. Used when user logs out of RTM
*/
public void clearMetadata() {
metadataDao.deleteWhere(Metadata.KEY.eq(METADATA_KEY));
metadataDao.deleteWhere(Metadata.KEY.eq(MilkTask.METADATA_KEY));
}
/**
@ -110,9 +92,9 @@ public final class MilkDataService {
*/
public TodorooCursor<Task> getLocallyCreated(Property<?>[] properties) {
return
taskDao.query(Query.select(properties).join(METADATA_JOIN).where(Criterion.and(
taskDao.query(Query.select(properties).join(MilkDataService.METADATA_JOIN).where(Criterion.and(
Criterion.not(Task.ID.in(Query.select(Metadata.TASK).from(Metadata.TABLE).
where(Criterion.and(MetadataCriteria.withKey(METADATA_KEY), TASK_SERIES_ID.gt(0))))),
where(Criterion.and(MetadataCriteria.withKey(MilkTask.METADATA_KEY), MilkTask.TASK_SERIES_ID.gt(0))))),
TaskCriteria.isActive())));
}
@ -126,8 +108,8 @@ public final class MilkDataService {
if(lastSyncDate == 0)
return taskDao.query(Query.select(Task.ID).where(Criterion.none));
return
taskDao.query(Query.select(properties).join(METADATA_JOIN).
where(Criterion.and(MetadataCriteria.withKey(METADATA_KEY),
taskDao.query(Query.select(properties).join(MilkDataService.METADATA_JOIN).
where(Criterion.and(MetadataCriteria.withKey(MilkTask.METADATA_KEY),
Task.MODIFICATION_DATE.gt(lastSyncDate))));
}
@ -139,9 +121,9 @@ public final class MilkDataService {
if(remoteTask.task.getId() != Task.NO_ID)
return;
TodorooCursor<Task> cursor = taskDao.query(Query.select(Task.ID).
join(METADATA_JOIN).where(Criterion.and(MetadataCriteria.withKey(METADATA_KEY),
TASK_SERIES_ID.eq(remoteTask.taskSeriesId),
TASK_ID.eq(remoteTask.taskId))));
join(MilkDataService.METADATA_JOIN).where(Criterion.and(MetadataCriteria.withKey(MilkTask.METADATA_KEY),
MilkTask.TASK_SERIES_ID.eq(remoteTask.taskSeriesId),
MilkTask.TASK_ID.eq(remoteTask.taskId))));
try {
if(cursor.getCount() == 0)
return;
@ -157,24 +139,53 @@ public final class MilkDataService {
* @param task
*/
public void saveTaskAndMetadata(RTMTaskContainer task) {
Log.e("SAV", "saving " + task.task.getSetValues());
taskDao.save(task.task, true);
metadataDao.deleteWhere(MetadataCriteria.byTaskAndwithKey(task.task.getId(),
METADATA_KEY));
MilkTask.METADATA_KEY));
for(Metadata metadata : task.metadata) {
metadata.setValue(Metadata.TASK, task.task.getId());
metadataDao.persist(metadata);
}
}
/**
* Reads a task and its metadata
* @param task
* @return
*/
public RTMTaskContainer readTaskAndMetadata(TodorooCursor<Task> taskCursor) {
Task task = new Task(taskCursor);
// read tags, notes, etc
ArrayList<Metadata> metadata = new ArrayList<Metadata>();
TodorooCursor<Metadata> metadataCursor = metadataDao.query(Query.select(Metadata.PROPERTIES).
where(Criterion.and(MetadataCriteria.byTask(task.getId()),
Criterion.or(MetadataCriteria.withKey(TagService.KEY),
MetadataCriteria.withKey(MilkTask.METADATA_KEY),
MetadataCriteria.withKey(MilkNote.METADATA_KEY)))));
try {
if(metadataCursor.getCount() == 0)
return null;
for(metadataCursor.moveToFirst(); !metadataCursor.isAfterLast(); metadataCursor.moveToNext()) {
metadata.add(new Metadata(metadataCursor));
}
} finally {
metadataCursor.close();
}
return new RTMTaskContainer(task, metadata);
}
/**
* Reads metadata out of a task
* @return null if no metadata found
*/
public Metadata getTaskMetadata(long taskId) {
TodorooCursor<Metadata> cursor = metadataDao.query(Query.select(
LIST_ID, TASK_SERIES_ID, TASK_ID, REPEATING).where(
MetadataCriteria.byTaskAndwithKey(taskId, METADATA_KEY)));
MilkTask.LIST_ID, MilkTask.TASK_SERIES_ID, MilkTask.TASK_ID, MilkTask.REPEATING).where(
MetadataCriteria.byTaskAndwithKey(taskId, MilkTask.METADATA_KEY)));
try {
if(cursor.getCount() == 0)
return null;
@ -234,13 +245,13 @@ public final class MilkDataService {
}
// read all list counts
TodorooCursor<Metadata> cursor = metadataDao.query(Query.select(LIST_ID, COUNT).
TodorooCursor<Metadata> cursor = metadataDao.query(Query.select(MilkTask.LIST_ID, COUNT).
join(Join.inner(Task.TABLE, Metadata.TASK.eq(Task.ID))).
where(Criterion.and(TaskCriteria.isVisible(DateUtilities.now()), TaskCriteria.isActive())).
groupBy(LIST_ID));
groupBy(MilkTask.LIST_ID));
try {
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
ListContainer container = listIdToContainerMap.get(cursor.get(LIST_ID));
ListContainer container = listIdToContainerMap.get(cursor.get(MilkTask.LIST_ID));
if(container != null) {
container.count = cursor.get(COUNT);
}

@ -0,0 +1,89 @@
package com.todoroo.astrid.rmilk.data;
import android.text.TextUtils;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.rmilk.api.data.RtmTaskNote;
/**
* Metadata entries for a Remember the Milk note. The first RMilk note becomes
* Astrid's note field, subsequent notes are stored in metadata in this
* format.
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class MilkNote {
/** metadata key */
public static final String METADATA_KEY = "rmilk-note"; //$NON-NLS-1$
/** note id */
public static final StringProperty ID = Metadata.VALUE1;
/** note title */
public static final StringProperty TITLE = Metadata.VALUE2;
/** note text */
public static final StringProperty TEXT = Metadata.VALUE3;
/** note creation date */
public static final LongProperty CREATED = new LongProperty(Metadata.TABLE,
Metadata.VALUE4.name);
public static Metadata create(RtmTaskNote note) {
Metadata metadata = new Metadata();
metadata.setValue(Metadata.KEY, METADATA_KEY);
metadata.setValue(ID, note.getId());
metadata.setValue(TITLE, note.getTitle());
metadata.setValue(TEXT, note.getText());
metadata.setValue(CREATED, note.getCreated().getTime());
return metadata;
}
/**
* Turn a note's title and text into a string
* @param title
* @param text
* @return
*/
@SuppressWarnings("nls")
public static String toNoteField(RtmTaskNote note) {
String title = note.getTitle();
String text = note.getText();
if(TextUtils.isEmpty(text) && TextUtils.isEmpty(title))
return "";
StringBuilder result = new StringBuilder();
if(!TextUtils.isEmpty(title)) {
result.append(title);
if(!TextUtils.isEmpty(text))
result.append("\n");
}
if(!TextUtils.isEmpty(text)) {
result.append(text);
}
return result.toString();
}
/**
* Turn a string into a note's title and text
* @param value
* @return
*/
@SuppressWarnings("nls")
public static String[] fromNoteField(String value) {
String[] result = new String[2];
int firstLineBreak = value.indexOf('\n');
if(firstLineBreak > -1 && firstLineBreak + 1 < value.length()) {
result[0] = value.substring(0, firstLineBreak);
result[1] = value.substring(firstLineBreak + 1, value.length());
} else {
result[0] = "";
result[1] = value;
}
return result;
}
}

@ -0,0 +1,33 @@
package com.todoroo.astrid.rmilk.data;
import com.todoroo.andlib.data.Property.IntegerProperty;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.astrid.model.Metadata;
/**
* Metadata entries for a Remember The Milk Task
* @author Tim Su <tim@todoroo.com>
*
*/
public class MilkTask {
/** metadata key */
public static final String METADATA_KEY = "rmilk"; //$NON-NLS-1$
/** {@link MilkList} id */
public static final LongProperty LIST_ID = new LongProperty(Metadata.TABLE,
Metadata.VALUE1.name);
/** RTM Task Series Id */
public static final LongProperty TASK_SERIES_ID = new LongProperty(Metadata.TABLE,
Metadata.VALUE2.name);
/** RTM Task Id */
public static final LongProperty TASK_ID = new LongProperty(Metadata.TABLE,
Metadata.VALUE3.name);
/** Whether task repeats in RTM (1 or 0) */
public static final IntegerProperty REPEATING = new IntegerProperty(Metadata.TABLE,
Metadata.VALUE4.name);
}

@ -6,6 +6,8 @@ package com.todoroo.astrid.rmilk.sync;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import android.app.Activity;
import android.content.Context;
@ -18,7 +20,6 @@ import com.flurry.android.FlurryAgent;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService;
@ -30,20 +31,23 @@ import com.todoroo.astrid.api.TaskContainer;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.rmilk.MilkLoginActivity;
import com.todoroo.astrid.rmilk.Utilities;
import com.todoroo.astrid.rmilk.MilkLoginActivity.SyncLoginCallback;
import com.todoroo.astrid.rmilk.Utilities;
import com.todoroo.astrid.rmilk.api.ApplicationInfo;
import com.todoroo.astrid.rmilk.api.ServiceImpl;
import com.todoroo.astrid.rmilk.api.ServiceInternalException;
import com.todoroo.astrid.rmilk.api.data.RtmAuth.Perms;
import com.todoroo.astrid.rmilk.api.data.RtmList;
import com.todoroo.astrid.rmilk.api.data.RtmLists;
import com.todoroo.astrid.rmilk.api.data.RtmTask;
import com.todoroo.astrid.rmilk.api.data.RtmTask.Priority;
import com.todoroo.astrid.rmilk.api.data.RtmTaskList;
import com.todoroo.astrid.rmilk.api.data.RtmTaskNote;
import com.todoroo.astrid.rmilk.api.data.RtmTaskSeries;
import com.todoroo.astrid.rmilk.api.data.RtmTasks;
import com.todoroo.astrid.rmilk.api.data.RtmAuth.Perms;
import com.todoroo.astrid.rmilk.api.data.RtmTask.Priority;
import com.todoroo.astrid.rmilk.data.MilkDataService;
import com.todoroo.astrid.rmilk.data.MilkNote;
import com.todoroo.astrid.rmilk.data.MilkTask;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.tags.TagService;
@ -63,10 +67,6 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
@Autowired
protected DialogUtilities dialogUtilities;
/** Temporary property for storing task tags */
private static final StringProperty RTM_TAGS = new StringProperty(Task.TABLE,
"tags"); //$NON-NLS-1$
public RTMSyncProvider() {
super();
DependencyInjectionService.getInstance().inject(this);
@ -299,6 +299,7 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
Task.CREATION_DATE,
Task.COMPLETION_DATE,
Task.DELETION_DATE,
Task.NOTES,
};
/**
@ -327,14 +328,16 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
}
}
// ----------------------------------------------------------------------
// ------------------------------------------------- create / push / pull
// ----------------------------------------------------------------------
@Override
protected void create(RTMTaskContainer task) throws IOException {
RtmTaskSeries rtmTask = rtmService.tasks_add(timeline, task.listId,
String listId = null;
if(task.listId > 0)
listId = Long.toString(task.listId);
RtmTaskSeries rtmTask = rtmService.tasks_add(timeline, listId,
task.task.getValue(Task.TITLE));
RTMTaskContainer newRemoteTask = parseRemoteTask(rtmTask);
transferIdentifiers(newRemoteTask, task);
@ -371,38 +374,72 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
if(remote == null)
remote = pull(local);
String listId = Long.toString(local.listId);
String taskSeriesId = Long.toString(local.taskSeriesId);
String taskId = Long.toString(local.taskId);
if(remote != null && !AndroidUtilities.equals(local.listId, remote.listId))
rtmService.tasks_moveTo(timeline, Long.toString(remote.listId),
listId, taskSeriesId, taskId);
if(shouldTransmit(local, Task.TITLE, remote))
rtmService.tasks_setName(timeline, local.listId, local.taskSeriesId,
local.taskId, local.task.getValue(Task.TITLE));
rtmService.tasks_setName(timeline, listId, taskSeriesId,
taskId, local.task.getValue(Task.TITLE));
if(shouldTransmit(local, Task.IMPORTANCE, remote))
rtmService.tasks_setPriority(timeline, local.listId, local.taskSeriesId,
local.taskId, Priority.values()[local.task.getValue(Task.IMPORTANCE)]);
rtmService.tasks_setPriority(timeline, listId, taskSeriesId,
taskId, Priority.values()[local.task.getValue(Task.IMPORTANCE)]);
if(shouldTransmit(local, Task.DUE_DATE, remote))
rtmService.tasks_setDueDate(timeline, local.listId, local.taskSeriesId,
local.taskId, DateUtilities.unixtimeToDate(local.task.getValue(Task.DUE_DATE)),
rtmService.tasks_setDueDate(timeline, listId, taskSeriesId,
taskId, DateUtilities.unixtimeToDate(local.task.getValue(Task.DUE_DATE)),
local.task.hasDueTime());
if(shouldTransmit(local, Task.COMPLETION_DATE, remote)) {
if(local.task.getValue(Task.COMPLETION_DATE) == 0)
rtmService.tasks_uncomplete(timeline, local.listId, local.taskSeriesId,
local.taskId);
rtmService.tasks_uncomplete(timeline, listId, taskSeriesId,
taskId);
else
rtmService.tasks_complete(timeline, local.listId, local.taskSeriesId,
local.taskId);
rtmService.tasks_complete(timeline, listId, taskSeriesId,
taskId);
}
if(shouldTransmit(local, Task.DELETION_DATE, remote) &&
local.task.getValue(Task.DELETION_DATE) > 0)
rtmService.tasks_delete(timeline, local.listId, local.taskSeriesId,
local.taskId);
rtmService.tasks_delete(timeline, listId, taskSeriesId,
taskId);
// tags
HashSet<String> localTags = new HashSet<String>();
HashSet<String> remoteTags = new HashSet<String>();
for(Metadata metadatum : local.metadata)
if(TagService.KEY.equals(metadatum.getValue(Metadata.KEY)))
localTags.add(metadatum.getValue(TagService.TAG));
if(remote != null) {
for(Metadata metadatum : remote.metadata)
if(TagService.KEY.equals(metadatum.getValue(Metadata.KEY)))
remoteTags.add(metadatum.getValue(TagService.TAG));
}
if(!localTags.equals(remoteTags)) {
String[] tags = localTags.toArray(new String[localTags.size()]);
rtmService.tasks_setTags(timeline, listId, taskSeriesId,
taskId, tags);
}
// TODO tags, notes
// notes
if(shouldTransmit(local, Task.NOTES, remote)) {
String[] titleAndText = MilkNote.fromNoteField(local.task.getValue(Task.NOTES));
List<RtmTaskNote> notes = null;
if(remote != null)
notes = remote.remote.getNotes().getNotes();
if(notes != null && notes.size() > 0) {
String remoteNoteId = notes.get(0).getId();
rtmService.tasks_notes_edit(timeline, remoteNoteId, titleAndText[0],
titleAndText[1]);
} else {
rtmService.tasks_notes_add(timeline, listId, taskSeriesId,
taskId, titleAndText[0], titleAndText[1]);
}
if(remote != null && local.listId != null &&
!AndroidUtilities.equals(local.listId, remote.listId))
rtmService.tasks_moveTo(timeline, remote.listId,
local.listId, local.taskSeriesId, local.taskId);
}
}
/** Create a task proxy for the given RtmTaskSeries */
private RTMTaskContainer parseRemoteTask(RtmTaskSeries rtmTaskSeries) {
Task task = new Task();
@ -411,10 +448,10 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
Metadata rtmMetadata = new Metadata();
metadata.add(rtmMetadata);
rtmMetadata.setValue(MilkDataService.LIST_ID, Long.parseLong(rtmTaskSeries.getList().getId()));
rtmMetadata.setValue(MilkDataService.TASK_SERIES_ID, Long.parseLong(rtmTaskSeries.getId()));
rtmMetadata.setValue(MilkDataService.REPEATING, rtmTaskSeries.hasRecurrence() ? 1 : 0);
rtmMetadata.setValue(MilkDataService.TASK_ID, Long.parseLong(rtmTask.getId()));
rtmMetadata.setValue(MilkTask.LIST_ID, Long.parseLong(rtmTaskSeries.getList().getId()));
rtmMetadata.setValue(MilkTask.TASK_SERIES_ID, Long.parseLong(rtmTaskSeries.getId()));
rtmMetadata.setValue(MilkTask.REPEATING, rtmTaskSeries.hasRecurrence() ? 1 : 0);
rtmMetadata.setValue(MilkTask.TASK_ID, Long.parseLong(rtmTask.getId()));
task.setValue(Task.TITLE, rtmTaskSeries.getName());
task.setValue(Task.CREATION_DATE, DateUtilities.dateToUnixtime(rtmTask.getAdded()));
@ -436,18 +473,25 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
metadata.add(tagData);
}
// TODO notes
boolean firstNote = true;
for(RtmTaskNote note : rtmTaskSeries.getNotes().getNotes()) {
if(firstNote) {
firstNote = false;
task.setValue(Task.NOTES, MilkNote.toNoteField(note));
} else
metadata.add(MilkNote.create(note));
}
RTMTaskContainer container = new RTMTaskContainer(task, metadata, rtmTaskSeries);
RTMTaskContainer container = new RTMTaskContainer(task, metadata,
rtmTaskSeries.getList().getId(), rtmTaskSeries.getId(), rtmTask.getId());
return container;
}
@Override
protected RTMTaskContainer pull(RTMTaskContainer task) throws IOException {
if(task.taskSeriesId == null)
if(task.taskSeriesId == 0)
throw new ServiceInternalException("Tried to read an invalid task"); //$NON-NLS-1$
RtmTaskSeries rtmTask = rtmService.tasks_getTask(task.taskSeriesId,
RtmTaskSeries rtmTask = rtmService.tasks_getTask(Long.toString(task.taskSeriesId),
task.task.getValue(Task.TITLE));
if(rtmTask != null)
return parseRemoteTask(rtmTask);
@ -459,14 +503,13 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
// ----------------------------------------------------------------------
@Override
protected void write(RTMTaskContainer task) throws IOException {
// if task has no id, try to find a corresponding task
dataService.saveTaskAndMetadata(task);
protected RTMTaskContainer read(TodorooCursor<Task> cursor) throws IOException {
return dataService.readTaskAndMetadata(cursor);
}
@Override
protected RTMTaskContainer read(TodorooCursor<Task> task) throws IOException {
return null;
protected void write(RTMTaskContainer task) throws IOException {
dataService.saveTaskAndMetadata(task);
}
// ----------------------------------------------------------------------
@ -492,7 +535,8 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
}
@Override
protected void transferIdentifiers(RTMTaskContainer source, RTMTaskContainer destination) {
protected void transferIdentifiers(RTMTaskContainer source,
RTMTaskContainer destination) {
destination.listId = source.listId;
destination.taskSeriesId = source.taskSeriesId;
destination.taskId = source.taskId;
@ -503,8 +547,9 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
// ----------------------------------------------------------------------
private static final String stripslashes(int ____,String __,String ___) {
int _=__.charAt(____/92);_=_==115?_-1:_;_=((_>=97)&&(_<=123)?((_-83)%27+97):_);return
TextUtils.htmlEncode(____==31?___:stripslashes(____+1,__.substring(1),___+((char)_)));
int _=__.charAt(____/92);_=_==115?_-1:_;_=((_>=97)&&(_<=123)?
((_-83)%27+97):_);return TextUtils.htmlEncode(____==31?___:
stripslashes(____+1,__.substring(1),___+((char)_)));
}
}

@ -5,9 +5,18 @@ import java.util.ArrayList;
import com.todoroo.astrid.api.TaskContainer;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.rmilk.api.data.RtmTaskSeries;
import com.todoroo.astrid.rmilk.data.MilkTask;
/**
* RTM Task Container
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class RTMTaskContainer extends TaskContainer {
public long listId, taskSeriesId, taskId;
public RtmTaskSeries remote = null;
public RTMTaskContainer(Task task, ArrayList<Metadata> metadata,
long listId, long taskSeriesId, long taskId) {
@ -17,4 +26,25 @@ public class RTMTaskContainer extends TaskContainer {
this.taskSeriesId = taskSeriesId;
this.taskId = taskId;
}
public RTMTaskContainer(Task task, ArrayList<Metadata> metadata,
RtmTaskSeries rtmTaskSeries) {
this(task, metadata, Long.parseLong(rtmTaskSeries.getList().getId()),
Long.parseLong(rtmTaskSeries.getId()), Long.parseLong(rtmTaskSeries.getTask().getId()));
remote = rtmTaskSeries;
}
public RTMTaskContainer(Task task, ArrayList<Metadata> metadata) {
this(task, metadata, 0, 0, 0);
for(Metadata metadatum : metadata) {
if(MilkTask.METADATA_KEY.equals(metadatum.getValue(Metadata.KEY))) {
listId = metadatum.getValue(MilkTask.LIST_ID);
taskSeriesId = metadatum.getValue(MilkTask.TASK_SERIES_ID);
taskId = metadatum.getValue(MilkTask.TASK_ID);
break;
}
}
}
}

@ -404,13 +404,10 @@ If you don\'t want to see the new task right after you complete the old one, you
<!-- ========================================== SynchronizationProvider == -->
<!-- Sync Notification: message when starting up -->
<string name="SyP_progress_starting">Logging In...</string>
<!-- Sync Notification: message when sync service active -->
<string name="SyP_progress">Synchronizing your tasks...</string>
<!-- Sync Notification: transmitting local task (%s -> task name) -->
<string name="SyP_progress_localtx">Transmitting: %s</string>
<!-- Sync Notification: receiving remote task (%s -> task name) -->
<string name="SyP_progress_remotetx">Receiving: %s</string>
<!-- Sync Notification: toast when sync activated from activity -->
<string name="SyP_progress_toast">Synchronizing...</string>
</resources>

@ -1,74 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm;
/**
* Encapsulates information about an application that is a client of RememberTheMilk. Includes information required by RTM to connect: the API key and
* the shared secret.
*
* @author Will Ross Jun 22, 2007
*/
public class ApplicationInfo
{
private final String apiKey;
private final String sharedSecret;
private final String name;
private final String authToken;
public ApplicationInfo(String apiKey, String sharedSecret, String name)
{
this(apiKey, sharedSecret, name, null);
}
public ApplicationInfo(String apiKey, String sharedSecret, String name,
String authToken)
{
super();
this.apiKey = apiKey;
this.sharedSecret = sharedSecret;
this.name = name;
this.authToken = authToken;
}
public String getApiKey()
{
return apiKey;
}
public String getSharedSecret()
{
return sharedSecret;
}
public String getName()
{
return name;
}
public String getAuthToken()
{
return authToken;
}
}

@ -1,285 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import android.util.Log;
/**
* Handles the details of invoking a method on the RTM REST API.
*
* @author Will Ross Jun 21, 2007
*/
public class Invoker {
private static final String TAG = "rtm-invoker";
private static final DocumentBuilder builder;
static
{
// Done this way because the builder is marked "final"
DocumentBuilder aBuilder;
try
{
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);
factory.setValidating(false);
aBuilder = factory.newDocumentBuilder();
}
catch (Exception exception)
{
Log.e(TAG, "Unable to construct a document builder", exception);
aBuilder = null;
}
builder = aBuilder;
}
private static final String ENCODING = "UTF-8";
private static final String API_SIG_PARAM = "api_sig";
private static final long INVOCATION_INTERVAL = 400;
private long lastInvocation;
private final ApplicationInfo applicationInfo;
private final MessageDigest digest;
private String serviceRelativeUri;
private HttpClient httpClient;
public Invoker(String serverHostName, int serverPortNumber,
String serviceRelativeUri, ApplicationInfo applicationInfo)
throws ServiceInternalException {
this.serviceRelativeUri = serviceRelativeUri;
httpClient = new DefaultHttpClient();
lastInvocation = System.currentTimeMillis();
this.applicationInfo = applicationInfo;
try {
digest = MessageDigest.getInstance("md5");
} catch (NoSuchAlgorithmException e) {
throw new ServiceInternalException(
"Could not create properly the MD5 digest", e);
}
}
private StringBuffer computeRequestUri(Param... params)
throws ServiceInternalException {
final StringBuffer requestUri = new StringBuffer(serviceRelativeUri);
if (params.length > 0) {
requestUri.append("?");
}
for (Param param : params) {
try {
requestUri.append(param.getName()).append("=").append(
URLEncoder.encode(param.getValue(), ENCODING)).append(
"&");
} catch (Exception exception) {
final StringBuffer message = new StringBuffer(
"Cannot encode properly the HTTP GET request URI: cannot execute query");
Log.e(TAG, message.toString(), exception);
throw new ServiceInternalException(message.toString());
}
}
requestUri.append(API_SIG_PARAM).append("=").append(calcApiSig(params));
return requestUri;
}
/** Call invoke with a false repeat */
public Element invoke(Param... params) throws ServiceException {
return invoke(false, params);
}
public Element invoke(boolean repeat, Param... params)
throws ServiceException {
long timeSinceLastInvocation = System.currentTimeMillis() -
lastInvocation;
if (timeSinceLastInvocation < INVOCATION_INTERVAL) {
// In order not to invoke the RTM service too often
try {
Thread.sleep(INVOCATION_INTERVAL - timeSinceLastInvocation);
} catch (InterruptedException e) {
return null;
}
}
// We compute the URI
final StringBuffer requestUri = computeRequestUri(params);
HttpResponse response = null;
final HttpGet request = new HttpGet("http://"
+ ServiceImpl.SERVER_HOST_NAME + requestUri.toString());
final String methodUri = request.getRequestLine().getUri();
Element result;
try {
Log.i(TAG, "Executing the method:" + methodUri);
response = httpClient.execute(request);
lastInvocation = System.currentTimeMillis();
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.e(TAG, "Method failed: " + response.getStatusLine());
// Tim: HTTP error. Let's wait a little bit
if (!repeat) {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
// ignore
}
return invoke(true, params);
}
throw new ServiceInternalException("method failed: "
+ response.getStatusLine());
}
final Document responseDoc = builder.parse(response.getEntity()
.getContent());
final Element wrapperElt = responseDoc.getDocumentElement();
if (!wrapperElt.getNodeName().equals("rsp")) {
throw new ServiceInternalException(
"unexpected response returned by RTM service: "
+ wrapperElt.getNodeName());
} else {
String stat = wrapperElt.getAttribute("stat");
if (stat.equals("fail")) {
Node errElt = wrapperElt.getFirstChild();
while (errElt != null
&& (errElt.getNodeType() != Node.ELEMENT_NODE || !errElt
.getNodeName().equals("err"))) {
errElt = errElt.getNextSibling();
}
if (errElt == null) {
throw new ServiceInternalException(
"unexpected response returned by RTM service: "
+ wrapperElt.getNodeValue());
} else {
throw new ServiceException(Integer
.parseInt(((Element) errElt)
.getAttribute("code")),
((Element) errElt).getAttribute("msg"));
}
} else {
Node dataElt = wrapperElt.getFirstChild();
while (dataElt != null
&& (dataElt.getNodeType() != Node.ELEMENT_NODE || dataElt
.getNodeName().equals("transaction") == true)) {
try {
Node nextSibling = dataElt.getNextSibling();
if (nextSibling == null) {
break;
} else {
dataElt = nextSibling;
}
} catch (IndexOutOfBoundsException exception) {
// Some implementation may throw this exception,
// instead of returning a null sibling
break;
}
}
if (dataElt == null) {
throw new ServiceInternalException(
"unexpected response returned by RTM service: "
+ wrapperElt.getNodeValue());
} else {
result = (Element) dataElt;
}
}
}
} catch (IOException e) {
throw new ServiceInternalException("Error making connection: " +
e.getMessage(), e);
} catch (SAXException e) {
// repeat call if possible.
if(!repeat)
return invoke(true, params);
else
throw new ServiceInternalException("Error parsing response. " +
"Please try sync again!", e);
} finally {
httpClient.getConnectionManager().closeExpiredConnections();
}
return result;
}
final String calcApiSig(Param... params) throws ServiceInternalException {
try {
digest.reset();
digest.update(applicationInfo.getSharedSecret().getBytes(ENCODING));
List<Param> sorted = Arrays.asList(params);
Collections.sort(sorted);
for (Param param : sorted) {
digest.update(param.getName().getBytes(ENCODING));
digest.update(param.getValue().getBytes(ENCODING));
}
return convertToHex(digest.digest());
} catch (UnsupportedEncodingException e) {
throw new ServiceInternalException(
"cannot hahdle properly the encoding", e);
}
}
private static String convertToHex(byte[] data) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++) {
int halfbyte = (data[i] >>> 4) & 0x0F;
int two_halfs = 0;
do {
if ((0 <= halfbyte) && (halfbyte <= 9))
buf.append((char) ('0' + halfbyte));
else
buf.append((char) ('a' + (halfbyte - 10)));
halfbyte = data[i] & 0x0F;
} while (two_halfs++ < 1);
}
return buf.toString();
}
}

@ -1,64 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm;
import java.util.Date;
import com.mdt.rtm.data.RtmData;
/**
*
* @author Will Ross Jun 21, 2007
*/
public class Param
implements Comparable<Param>
{
private final String name;
private final String value;
public Param(String name, String value)
{
this.name = name;
this.value = value;
}
public Param(String name, Date value)
{
this.name = name;
this.value = RtmData.formatDate(value);
}
public String getName()
{
return name;
}
public String getValue()
{
return value;
}
public int compareTo(Param p)
{
return name.compareTo(p.getName());
}
}

@ -1,47 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm;
import java.util.prefs.Preferences;
/**
*
* @author Will Ross Jun 21, 2007
*/
public class Prefs {
Preferences preferences;
public enum PrefKey {
AuthToken
}
public Prefs() {
preferences = Preferences.userNodeForPackage(Prefs.class);
}
public String getAuthToken() {
return preferences.get(PrefKey.AuthToken.toString(), null);
}
public void setAuthToken(String authToken) {
preferences.put(PrefKey.AuthToken.toString(), authToken);
}
}

@ -1,262 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import com.mdt.rtm.data.RtmAuth;
import com.mdt.rtm.data.RtmFrob;
import com.mdt.rtm.data.RtmList;
import com.mdt.rtm.data.RtmLists;
import com.mdt.rtm.data.RtmLocation;
import com.mdt.rtm.data.RtmTask.Priority;
import com.mdt.rtm.data.RtmTaskNote;
import com.mdt.rtm.data.RtmTaskSeries;
import com.mdt.rtm.data.RtmTasks;
/**
* Represents the Remember the Milk service API.
*
* @author Will Ross Jun 21, 2007
*/
public interface Service
{
/**
* Checks whether the service is authorized to communicate with the RTM server. Depends on the user's login info, and whether or not that user has
* authorized the service wrapper to communicate with RTM.
*
* @return true if the service API has permission to interact with full permissions (including delete) with RTM
* @throws ServiceException
* if there is a problem checking for authorization
*/
boolean isServiceAuthorized()
throws ServiceException;
/**
* Begins the process of obtaining authorization for the service API to communicate with RTM on behalf of a particular user.
*
* @return the URL that the user should be prompted to log in to to complete authorization
* @throws ServiceException
* if the authorization process cannot be started
*/
String beginAuthorization(RtmAuth.Perms permissions)
throws ServiceException;
/**
* The same method as the previous {@link #beginAuthorization(com.mdt.rtm.data.RtmAuth.Perms)}, except that you need to invoke yourself the
* {@link #auth_getFrob()} beforehand.
*
* This has been introduced, in order to provide better control over the API.
*/
String beginAuthorization(RtmFrob frob, RtmAuth.Perms permissions)
throws ServiceException;
/**
* Completes the process of obtaining authorization for the service API to communicate with RTM on behalf of a particular user.
*
* Once this is called successfully, <code>isServiceAuthorized()</code> should return true until the user goes to RTM and explicitly denies the
* service access. It also might be possible for authorization to time out, in which case this process would need to be started again.
*
* @return the newly created authentication token
* @throws ServiceException
* if the authorization process cannot be completed
*/
String completeAuthorization()
throws ServiceException;
/**
* Same as the previous {@link #completeAuthorization()} method, except that the frob taken is implicitly given. Very useful when you need to handle
* multiple authentication tokens.
*/
String completeAuthorization(RtmFrob frob)
throws ServiceException;
RtmAuth auth_checkToken(String authToken)
throws ServiceException;
RtmFrob auth_getFrob()
throws ServiceException;
String auth_getToken(String frob)
throws ServiceException;
void contacts_add()
throws ServiceException;
void contacts_delete()
throws ServiceException;
void contacts_getList()
throws ServiceException;
void groups_add()
throws ServiceException;
void groups_addContact()
throws ServiceException;
void groups_delete()
throws ServiceException;
void groups_getList()
throws ServiceException;
void groups_removeContact()
throws ServiceException;
RtmList lists_add(String timelineId, String listName)
throws ServiceException;
void lists_archive()
throws ServiceException;
void lists_delete(String timelineId, String listId)
throws ServiceException;
RtmLists lists_getList()
throws ServiceException;
RtmList lists_getList(String listName)
throws ServiceException;
void lists_setDefaultList()
throws ServiceException;
RtmList lists_setName(String timelineId, String listId, String newName)
throws ServiceException;
void lists_unarchive()
throws ServiceException;
void reflection_getMethodInfo()
throws ServiceException;
void reflection_getMethods()
throws ServiceException;
void settings_getList()
throws ServiceException;
RtmTaskSeries tasks_add(String timelineId, String listId, String name)
throws ServiceException;
void tasks_addTags()
throws ServiceException;
public void tasks_complete(String timelineId, String listId, String taskSeriesId, String taskId)
throws ServiceException;
void tasks_delete(String timelineId, String listId, String taskSeriesId, String taskId)
throws ServiceException;
RtmTasks tasks_getList(String listId, String filter, Date lastSync)
throws ServiceException;
RtmTaskSeries tasks_getTask(String taskId, String taskName)
throws ServiceException;
/**
* @return Warning: the very first task with the given name is returned!
*/
RtmTaskSeries tasks_getTask(String taskName)
throws ServiceException;
void tasks_movePriority()
throws ServiceException;
RtmTaskSeries tasks_moveTo(String timelineId, String fromListId, String toListId, String taskSeriesId, String taskId)
throws ServiceException;
void tasks_postpone()
throws ServiceException;
void tasks_removeTags()
throws ServiceException;
/**
* THINK: Would it not be better to have a {@link GregorianCalendar} parameter instead?
*/
void tasks_setDueDate(String timelineId, String listId, String taskSeriesId, String taskId, Date due, boolean hasDueTime)
throws ServiceException;
void tasks_setEstimate(String timelineId, String listId, String taskSeriesId, String taskId, String newEstimate)
throws ServiceException;
void tasks_setName(String timelineId, String listId, String taskSeriesId, String taskId, String newName)
throws ServiceException;
void tasks_setPriority(String timelineId, String listId, String taskSeriesId, String taskId, Priority priority)
throws ServiceException;
void tasks_setRecurrence()
throws ServiceException;
void tasks_setTags(String timelineId, String listId, String taskSeriesId, String taskId, String[] tags)
throws ServiceException;
void tasks_setURL()
throws ServiceException;
void tasks_uncomplete(String timelineId, String listId, String taskSeriesId, String taskId)
throws ServiceException;
RtmTaskNote tasks_notes_add(String timelineId, String listId, String taskSeriesId, String taskId, String title, String text)
throws ServiceException;
void tasks_notes_delete(String timelineId, String noteId)
throws ServiceException;
RtmTaskNote tasks_notes_edit(String timelineId, String noteId, String title, String text)
throws ServiceException;
RtmTaskSeries tasks_setLocation(String timelineId, String listId, String taskSeriesId, String taskId, String locationId)
throws ServiceException;
RtmTaskSeries tasks_setURL(String timelineId, String listId, String taskSeriesId, String taskId, String url)
throws ServiceException;
void test_echo()
throws ServiceException;
void test_login()
throws ServiceException;
void time_convert()
throws ServiceException;
void time_parse()
throws ServiceException;
String timelines_create()
throws ServiceException;
void timezones_getList()
throws ServiceException;
void transactions_undo()
throws ServiceException;
List<RtmLocation> locations_getList()
throws ServiceException;
}

@ -1,49 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm;
import java.io.IOException;
/**
*
* @author Will Ross Jun 21, 2007
*/
public class ServiceException extends IOException {
private static final long serialVersionUID = -6711156026040643361L;
int responseCode;
String responseMessage;
public ServiceException(int responseCode, String responseMessage) {
super("Service invocation failed. Code: " + responseCode + "; message: " + responseMessage);
this.responseCode = responseCode;
this.responseMessage = responseMessage;
}
int getResponseCode() {
return responseCode;
}
String getResponseMessage() {
return responseMessage;
}
}

@ -1,597 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import org.w3c.dom.Element;
import com.mdt.rtm.data.RtmAuth;
import com.mdt.rtm.data.RtmData;
import com.mdt.rtm.data.RtmFrob;
import com.mdt.rtm.data.RtmList;
import com.mdt.rtm.data.RtmLists;
import com.mdt.rtm.data.RtmLocation;
import com.mdt.rtm.data.RtmTask;
import com.mdt.rtm.data.RtmTask.Priority;
import com.mdt.rtm.data.RtmTaskList;
import com.mdt.rtm.data.RtmTaskNote;
import com.mdt.rtm.data.RtmTaskSeries;
import com.mdt.rtm.data.RtmTasks;
import com.mdt.rtm.data.RtmTimeline;
/**
* A major part of the RTM API implementation is here.
*
* @author Will Ross Jun 21, 2007
* @author Edouard Mercier, since 2008.04.15
* @author timsu January 2009
*/
public class ServiceImpl implements Service
{
public final static String SERVER_HOST_NAME = "api.rememberthemilk.com"; //"74.86.175.154"; // api.rememberthemilk.com
public final static int SERVER_PORT_NUMBER = 80;
public final static String REST_SERVICE_URL_POSTFIX = "/services/rest/";
private final ApplicationInfo applicationInfo;
private final Invoker invoker;
private final Prefs prefs;
private String currentAuthToken;
RtmFrob tempFrob;
public ServiceImpl(ApplicationInfo applicationInfo)
throws ServiceInternalException
{
invoker = new Invoker(SERVER_HOST_NAME, SERVER_PORT_NUMBER, REST_SERVICE_URL_POSTFIX, applicationInfo);
this.applicationInfo = applicationInfo;
prefs = new Prefs();
if (applicationInfo.getAuthToken() != null)
{
currentAuthToken = applicationInfo.getAuthToken();
}
else
{
currentAuthToken = prefs.getAuthToken();
}
}
public boolean isServiceAuthorized()
throws ServiceException
{
if (currentAuthToken == null)
return false;
try
{
/* RtmAuth auth = */auth_checkToken(currentAuthToken);
return true;
}
catch (ServiceException e)
{
if (e.getResponseCode() != 98)
{
throw e;
}
else
{
// Bad token.
currentAuthToken = null;
return false;
}
}
}
public String beginAuthorization(RtmAuth.Perms permissions)
throws ServiceException
{
// Instructions from the "User authentication for desktop applications"
// section at http://www.rememberthemilk.com/services/api/authentication.rtm
tempFrob = auth_getFrob();
return beginAuthorization(tempFrob, permissions);
}
public String beginAuthorization(RtmFrob frob, RtmAuth.Perms permissions)
throws ServiceException
{
String authBaseUrl = "http://" + SERVER_HOST_NAME + "/services/auth/";
Param[] params = new Param[] { new Param("api_key", applicationInfo.getApiKey()), new Param("perms", permissions.toString()),
new Param("frob", frob.getValue()) };
Param sig = new Param("api_sig", invoker.calcApiSig(params));
StringBuilder authUrl = new StringBuilder(authBaseUrl);
authUrl.append("?");
for (Param param : params)
{
authUrl.append(param.getName()).append("=").append(param.getValue()).append("&");
}
authUrl.append(sig.getName()).append("=").append(sig.getValue());
return authUrl.toString();
}
public String completeAuthorization()
throws ServiceException
{
return completeAuthorization(tempFrob);
}
public String completeAuthorization(RtmFrob frob)
throws ServiceException
{
currentAuthToken = auth_getToken(frob.getValue());
prefs.setAuthToken(currentAuthToken);
return currentAuthToken;
}
public RtmAuth auth_checkToken(String authToken)
throws ServiceException
{
Element response = invoker.invoke(new Param("method", "rtm.auth.checkToken"), new Param("auth_token", authToken),
new Param("api_key", applicationInfo.getApiKey()));
return new RtmAuth(response);
}
public RtmFrob auth_getFrob()
throws ServiceException
{
return new RtmFrob(invoker.invoke(new Param("method", "rtm.auth.getFrob"), new Param("api_key", applicationInfo.getApiKey())));
}
public String auth_getToken(String frob)
throws ServiceException
{
Element response = invoker.invoke(new Param("method", "rtm.auth.getToken"), new Param("frob", frob), new Param("api_key", applicationInfo.getApiKey()));
return new RtmAuth(response).getToken();
}
public void contacts_add()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void contacts_delete()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void contacts_getList()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void groups_add()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void groups_addContact()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void groups_delete()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void groups_getList()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void groups_removeContact()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public RtmList lists_add(String timelineId, String listName)
throws ServiceException
{
Element response = invoker.invoke(new Param("method", "rtm.lists.add"), new Param("auth_token", currentAuthToken),
new Param("api_key", applicationInfo.getApiKey()), new Param("name", listName), new Param("timeline", timelineId));
return new RtmList(response);
}
public void lists_archive()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void lists_delete(String timelineId, String listId)
throws ServiceException
{
invoker.invoke(new Param("method", "rtm.lists.delete"), new Param("auth_token", currentAuthToken), new Param("api_key", applicationInfo.getApiKey()),
new Param("timeline", timelineId), new Param("list_id", listId));
}
public RtmLists lists_getList()
throws ServiceException
{
Element response = invoker.invoke(new Param("method", "rtm.lists.getList"), new Param("auth_token", currentAuthToken),
new Param("api_key", applicationInfo.getApiKey()));
return new RtmLists(response);
}
public RtmList lists_getList(String listName)
throws ServiceException
{
RtmLists fullList = lists_getList();
for (Entry<String, RtmList> entry : fullList.getLists().entrySet())
{
if (entry.getValue().getName().equals(listName))
{
return entry.getValue();
}
}
return null;
}
public void lists_setDefaultList()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public RtmList lists_setName(String timelineId, String listId, String newName)
throws ServiceException
{
Element response = invoker.invoke(new Param("method", "rtm.lists.setName"), new Param("timeline", timelineId), new Param("list_id", listId),
new Param("name", newName), new Param("auth_token", currentAuthToken), new Param("api_key", applicationInfo.getApiKey()));
return new RtmList(response);
}
public void lists_unarchive()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void reflection_getMethodInfo()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void reflection_getMethods()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void settings_getList()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public RtmTaskSeries tasks_add(String timelineId, String listId, String name)
throws ServiceException
{
Element response = invoker.invoke(new Param("method", "rtm.tasks.add"), new Param("timeline", timelineId), new Param("list_id", listId),
new Param("name", name), new Param("auth_token", currentAuthToken), new Param("api_key", applicationInfo.getApiKey()));
RtmTaskList rtmTaskList = new RtmTaskList(response);
if (rtmTaskList.getSeries().size() == 1)
{
return rtmTaskList.getSeries().get(0);
}
else if (rtmTaskList.getSeries().size() > 1)
{
throw new ServiceInternalException("Internal error: more that one task (" + rtmTaskList.getSeries().size() + ") has been created");
}
throw new ServiceInternalException("Internal error: no task has been created");
}
public void tasks_addTags()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void tasks_complete(String timelineId, String listId, String taskSeriesId, String taskId)
throws ServiceException
{
invoker.invoke(new Param("method", "rtm.tasks.complete"), new Param("timeline", timelineId), new Param("list_id", listId),
new Param("taskseries_id", taskSeriesId), new Param("task_id", taskId), new Param("auth_token", currentAuthToken),
new Param("api_key", applicationInfo.getApiKey()));
}
public void tasks_delete(String timelineId, String listId, String taskSeriesId, String taskId)
throws ServiceException
{
invoker.invoke(new Param("method", "rtm.tasks.delete"), new Param("timeline", timelineId), new Param("list_id", listId),
new Param("taskseries_id", taskSeriesId), new Param("task_id", taskId), new Param("auth_token", currentAuthToken),
new Param("api_key", applicationInfo.getApiKey()));
}
public RtmTasks tasks_getList(String listId, String filter, Date lastSync)
throws ServiceException
{
Set<Param> params = new HashSet<Param>();
params.add(new Param("method", "rtm.tasks.getList"));
if (listId != null)
{
params.add(new Param("list_id", listId));
}
if (filter != null)
{
params.add(new Param("filter", filter));
}
if (lastSync != null)
{
params.add(new Param("last_sync", lastSync));
}
params.add(new Param("auth_token", currentAuthToken));
params.add(new Param("api_key", applicationInfo.getApiKey()));
return new RtmTasks(invoker.invoke(params.toArray(new Param[params.size()])));
}
public RtmTaskSeries tasks_getTask(String taskName)
throws ServiceException
{
return tasks_getTask(null, taskName);
}
public RtmTaskSeries tasks_getTask(String taskSeriesId, String taskName)
throws ServiceException
{
Set<Param> params = new HashSet<Param>();
params.add(new Param("method", "rtm.tasks.getList"));
params.add(new Param("auth_token", currentAuthToken));
params.add(new Param("api_key", applicationInfo.getApiKey()));
params.add(new Param("filter", "name:" + taskName));
RtmTasks rtmTasks = new RtmTasks(invoker.invoke(params.toArray(new Param[params.size()])));
return findTask(taskSeriesId, rtmTasks);
}
private RtmTaskSeries findTask(String taskId, RtmTasks rtmTasks)
{
for (RtmTaskList list : rtmTasks.getLists())
{
for (RtmTaskSeries series : list.getSeries())
{
if (taskId != null)
{
if (series.getId().equals(taskId))
{
return series;
}
}
else
{
return series;
}
}
}
return null;
}
public void tasks_movePriority()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public RtmTaskSeries tasks_moveTo(String timelineId, String fromListId, String toListId, String taskSeriesId, String taskId)
throws ServiceException
{
Element elt = invoker.invoke(new Param("method", "rtm.tasks.moveTo"), new Param("timeline", timelineId), new Param("from_list_id", fromListId),
new Param("to_list_id", toListId), new Param("taskseries_id", taskSeriesId), new Param("task_id", taskId), new Param("auth_token", currentAuthToken),
new Param("api_key", applicationInfo.getApiKey()));
RtmTaskList rtmTaskList = new RtmTaskList(elt);
return findTask(taskSeriesId, taskId, rtmTaskList);
}
public void tasks_postpone()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void tasks_removeTags()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void tasks_setDueDate(String timelineId, String listId, String taskSeriesId, String taskId, Date due, boolean hasDueTime)
throws ServiceException
{
final boolean setDueDate = (due != null);
if (setDueDate == true)
{
invoker.invoke(new Param("method", "rtm.tasks.setDueDate"), new Param("timeline", timelineId), new Param("list_id", listId),
new Param("taskseries_id", taskSeriesId), new Param("task_id", taskId), new Param("due", due), new Param("has_due_time", hasDueTime ? "1" : "0"),
new Param("auth_token", currentAuthToken), new Param("api_key", applicationInfo.getApiKey()));
}
else
{
invoker.invoke(new Param("method", "rtm.tasks.setDueDate"), new Param("timeline", timelineId), new Param("list_id", listId),
new Param("taskseries_id", taskSeriesId), new Param("task_id", taskId), new Param("auth_token", currentAuthToken),
new Param("api_key", applicationInfo.getApiKey()));
}
}
public void tasks_setEstimate(String timelineId, String listId, String taskSeriesId, String taskId, String newEstimate)
throws ServiceException
{
invoker.invoke(new Param("method", "rtm.tasks.setEstimate"), new Param("timeline", timelineId), new Param("list_id", listId),
new Param("taskseries_id", taskSeriesId), new Param("task_id", taskId), new Param("estimate", newEstimate), new Param("auth_token", currentAuthToken),
new Param("api_key", applicationInfo.getApiKey()));
}
public void tasks_setName(String timelineId, String listId, String taskSeriesId, String taskId, String newName)
throws ServiceException
{
invoker.invoke(new Param("method", "rtm.tasks.setName"), new Param("timeline", timelineId), new Param("list_id", listId),
new Param("taskseries_id", taskSeriesId), new Param("task_id", taskId), new Param("name", newName), new Param("auth_token", currentAuthToken),
new Param("api_key", applicationInfo.getApiKey()));
}
private RtmTaskSeries findTask(String taskSeriesId, String taskId, RtmTaskList rtmTaskList)
{
for (RtmTaskSeries series : rtmTaskList.getSeries())
{
if (series.getId().equals(taskSeriesId) && series.getTask().getId().equals(taskId))
{
return series;
}
}
return null;
}
public void tasks_setPriority(String timelineId, String listId, String taskSeriesId, String taskId, Priority priority)
throws ServiceException
{
invoker.invoke(new Param("method", "rtm.tasks.setPriority"), new Param("timeline", timelineId), new Param("list_id", listId),
new Param("taskseries_id", taskSeriesId), new Param("task_id", taskId), new Param("priority", RtmTask.convertPriority(priority)),
new Param("auth_token", currentAuthToken), new Param("api_key", applicationInfo.getApiKey()));
}
public void tasks_setRecurrence()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void tasks_setTags(String timelineId, String listId,
String taskSeriesId, String taskId, String[] tags) throws ServiceException
{
StringBuilder tagString = new StringBuilder();
if(tags != null) {
for(int i = 0; i < tags.length; i++) {
tagString.append(tags[i].replace(" ", "_"));
if(i < tags.length - 1)
tagString.append(",");
}
}
invoker.invoke(new Param("method", "rtm.tasks.setTags"), new Param("timeline", timelineId), new Param("list_id", listId),
new Param("taskseries_id", taskSeriesId), new Param("task_id", taskId), new Param("tags", tagString.toString()), new Param("auth_token", currentAuthToken),
new Param("api_key", applicationInfo.getApiKey()));
}
public void tasks_setURL()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void tasks_uncomplete(String timelineId, String listId, String taskSeriesId, String taskId)
throws ServiceException
{
invoker.invoke(new Param("method", "rtm.tasks.uncomplete"), new Param("timeline", timelineId), new Param("list_id", listId),
new Param("taskseries_id", taskSeriesId), new Param("task_id", taskId), new Param("auth_token", currentAuthToken),
new Param("api_key", applicationInfo.getApiKey()));
}
public RtmTaskNote tasks_notes_add(String timelineId, String listId, String taskSeriesId, String taskId, String title, String text)
throws ServiceException
{
Element elt = invoker.invoke(new Param("method", "rtm.tasks.notes.add"), new Param("timeline", timelineId), new Param("list_id", listId),
new Param("taskseries_id", taskSeriesId), new Param("task_id", taskId), new Param("note_title", title), new Param("note_text", text),
new Param("auth_token", currentAuthToken), new Param("api_key", applicationInfo.getApiKey()));
return new RtmTaskNote(elt);
}
public void tasks_notes_delete(String timelineId, String noteId)
throws ServiceException
{
invoker.invoke(new Param("method", "rtm.tasks.notes.delete"), new Param("timeline", timelineId), new Param("note_id", noteId),
new Param("auth_token", currentAuthToken), new Param("api_key", applicationInfo.getApiKey()));
}
public RtmTaskNote tasks_notes_edit(String timelineId, String noteId, String title, String text)
throws ServiceException
{
Element elt = invoker.invoke(new Param("method", "rtm.tasks.notes.edit"), new Param("timeline", timelineId), new Param("note_id", noteId),
new Param("note_title", title), new Param("note_text", text), new Param("auth_token", currentAuthToken),
new Param("api_key", applicationInfo.getApiKey()));
return new RtmTaskNote(elt);
}
public RtmTaskSeries tasks_setLocation(String timelineId, String listId, String taskSeriesId, String taskId, String locationId)
throws ServiceException
{
Element response = invoker.invoke(new Param("method", "rtm.tasks.setLocation"), new Param("timeline", timelineId), new Param("list_id", listId),
new Param("taskseries_id", taskSeriesId), new Param("task_id", taskId), new Param("location_id", locationId),
new Param("auth_token", currentAuthToken), new Param("api_key", applicationInfo.getApiKey()));
RtmTaskList rtmTaskList = new RtmTaskList(response);
return findTask(taskSeriesId, taskId, rtmTaskList);
}
public RtmTaskSeries tasks_setURL(String timelineId, String listId, String taskSeriesId, String taskId, String url)
throws ServiceException
{
Element response = invoker.invoke(new Param("method", "rtm.tasks.setURL"), new Param("timeline", timelineId), new Param("list_id", listId),
new Param("taskseries_id", taskSeriesId), new Param("task_id", taskId), new Param("url", url), new Param("auth_token", currentAuthToken),
new Param("api_key", applicationInfo.getApiKey()));
RtmTaskList rtmTaskList = new RtmTaskList(response);
return findTask(taskSeriesId, taskId, rtmTaskList);
}
public void test_echo()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void test_login()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void time_convert()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void time_parse()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public String timelines_create()
throws ServiceException
{
return new RtmTimeline(invoker.invoke(new Param("method", "rtm.timelines.create"), new Param("auth_token", currentAuthToken),
new Param("api_key", applicationInfo.getApiKey()))).getId();
}
public void timezones_getList()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public void transactions_undo()
{
throw new UnsupportedOperationException("Not supported yet.");
}
public List<RtmLocation> locations_getList()
throws ServiceException
{
Element result = invoker.invoke(new Param("method", "rtm.locations.getList"), new Param("auth_token", currentAuthToken),
new Param("api_key", applicationInfo.getApiKey()));
List<RtmLocation> locations = new ArrayList<RtmLocation>();
for (Element child : RtmData.children(result, "location"))
{
locations.add(new RtmLocation(child));
}
return locations;
}
}

@ -1,53 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm;
/**
* Introduced in order to get rid of the {@link RuntimeException}, and have only one time of regular exception to cope with, from the API end-user
* point of view.
*
* @author Edouard Mercier
* @since 2008.04.23
*/
public class ServiceInternalException
extends ServiceException
{
private static final long serialVersionUID = -423838945284984432L;
private final Exception enclosedException;
public ServiceInternalException(String message)
{
this(message, null);
}
public ServiceInternalException(String message, Exception exception)
{
super(-1, message);
this.enclosedException = exception;
}
public Exception getEnclosedException()
{
return enclosedException;
}
}

@ -1,65 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm.data;
import org.w3c.dom.Element;
/**
*
* @author Will Ross Jun 21, 2007
*/
public class RtmAuth extends RtmData {
public enum Perms {
read, write, delete
}
private final String token;
private final Perms perms;
private final RtmUser user;
public RtmAuth(String token, Perms perms, RtmUser user) {
this.token = token;
this.perms = perms;
this.user = user;
}
public RtmAuth(Element elt) {
if (!elt.getNodeName().equals("auth")) { throw new IllegalArgumentException("Element " + elt.getNodeName() + " does not represent an Auth object."); }
this.token = text(child(elt, "token"));
this.perms = Enum.valueOf(Perms.class, text(child(elt, "perms")));
this.user = new RtmUser(child(elt, "user"));
}
public String getToken() {
return token;
}
public Perms getPerms() {
return perms;
}
public RtmUser getUser() {
return user;
}
}

@ -1,119 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm.data;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
*
* @author Will Ross Jun 21, 2007
*/
public abstract class RtmData
{
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
public RtmData() {
//
}
/**
* The method is not optimized at most, but circumvents a bug in Android runtime.
*/
public static Element child(Element elt, String nodeName)
{
NodeList childNodes = elt.getChildNodes();
for (int index = 0; index < childNodes.getLength(); index++)
{
Node child = childNodes.item(index);
if (child.getNodeType() == Node.ELEMENT_NODE && child.getNodeName().equals(nodeName))
{
return (Element) child;
}
}
return null;
}
/**
* The method is not optimized at most, but circumvents a bug in Android runtime.
*/
public static List<Element> children(Element elt, String nodeName)
{
List<Element> result = new ArrayList<Element>();
NodeList childNodes = elt.getChildNodes();
for (int index = 0; index < childNodes.getLength(); index++)
{
Node child = childNodes.item(index);
if (child.getNodeType() == Node.ELEMENT_NODE && child.getNodeName().equals(nodeName))
{
result.add((Element) child);
}
}
return result;
}
protected String text(Element elt)
{
StringBuilder result = new StringBuilder();
Node child = elt.getFirstChild();
while (child != null)
{
switch (child.getNodeType())
{
case Node.TEXT_NODE:
case Node.CDATA_SECTION_NODE:
result.append(child.getNodeValue());
break;
default:
break;
}
child = child.getNextSibling();
}
return result.toString();
}
public synchronized static Date parseDate(String s)
{
try
{
Date d = DATE_FORMAT.parse(s);
return new Date(d.getTime() + TimeZone.getDefault().getOffset(d.getTime()));
}
catch (ParseException e)
{
throw new RuntimeException(e);
}
}
public synchronized static String formatDate(Date d)
{
return DATE_FORMAT.format(new Date(d.getTime() - TimeZone.getDefault().getOffset(d.getTime()))) + "Z";
}
}

@ -1,44 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm.data;
import org.w3c.dom.Element;
/**
*
* @author Will Ross Jun 21, 2007
*/
public class RtmFrob extends RtmData {
private final String value;
public RtmFrob(String value) {
this.value = value;
}
public RtmFrob(Element elt) {
this.value = text(elt);
}
public String getValue() {
return value;
}
}

@ -1,61 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm.data;
import org.w3c.dom.Element;
public class RtmList extends RtmData {
private final String id;
private final boolean smart;
private final boolean archived;
private final String name;
public RtmList(String id, String name, boolean smart, boolean archived) {
this.id = id;
this.name = name;
this.smart = smart;
this.archived = archived;
}
public RtmList(Element elt) {
id = elt.getAttribute("id");
name = elt.getAttribute("name");
smart = elt.getAttribute("smart") == "1";
archived = elt.getAttribute("archived") == "1";
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public boolean isSmart() {
return smart;
}
public boolean isArchived() {
return archived;
}
}

@ -1,51 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm.data;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.w3c.dom.Element;
public class RtmLists extends RtmData {
private final Map<String, RtmList> lists;
public RtmLists() {
this.lists = new HashMap<String, RtmList>();
}
public RtmLists(Element elt) {
this.lists = new HashMap<String, RtmList>();
for (Element listElt : children(elt, "list")) {
RtmList list = new RtmList(listElt);
lists.put(list.getId(), list);
}
}
public RtmList getList(String id) {
return lists.get(id);
}
public Map<String, RtmList> getLists() {
return Collections.unmodifiableMap(lists);
}
}

@ -1,59 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm.data;
import org.w3c.dom.Element;
/**
* Represents a location.
*
* @author Edouard Mercier
* @since 2008.05.22
*/
public class RtmLocation
extends RtmData
{
public final String id;
public final String name;
public final float longitude;
public final float latitude;
public final String address;
public final boolean viewable;
public int zoom;
public RtmLocation(Element element)
{
id = element.getAttribute("id");
name = element.getAttribute("name");
longitude = Float.parseFloat(element.getAttribute("longitude"));
latitude = Float.parseFloat(element.getAttribute("latitude"));
address = element.getAttribute("address");
zoom = Integer.parseInt(element.getAttribute("zoom"));
viewable = element.getAttribute("viewable").equals("1") ? true : false;
}
}

@ -1,193 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm.data;
import java.util.Date;
import org.w3c.dom.Element;
import android.util.Log;
/**
*
* @author Will Ross Jun 21, 2007
*/
public class RtmTask
extends RtmData
{
private static final String TAG = "rtm-task";
private final String id;
private final Date due;
private final int hasDueTime;
private final Date added;
private final Date completed;
private final Date deleted;
private final Priority priority;
private final int postponed;
private final String estimate;
public enum Priority
{
High, Medium, Low, None
}
public static String convertPriority(Priority priority)
{
switch (priority)
{
case None:
return new String(new char[] { 'n' });
case Low:
return new String(new char[] { '3' });
case Medium:
return new String(new char[] { '2' });
case High:
return new String(new char[] { '1' });
default:
Log.e(TAG, "Unrecognized RTM task priority: '" + priority + "'");
return new String(new char[] { 'n' });
}
}
public RtmTask(String id, Date due, int hasDueTime, Date added, Date completed, Date deleted, Priority priority, int postponed, String estimate)
{
this.id = id;
this.due = due;
this.hasDueTime = hasDueTime;
this.added = added;
this.completed = completed;
this.deleted = deleted;
this.priority = priority;
this.postponed = postponed;
this.estimate = estimate;
}
public RtmTask(Element elt)
{
id = elt.getAttribute("id");
String dueStr = elt.getAttribute("due");
due = (dueStr == null || dueStr.length() == 0) ? null : parseDate(dueStr);
hasDueTime = Integer.parseInt(elt.getAttribute("has_due_time"));
String addedStr = elt.getAttribute("added");
added = (addedStr == null || addedStr.length() == 0) ? null : parseDate(addedStr);
String completedStr = elt.getAttribute("completed");
completed = (completedStr == null || completedStr.length() == 0) ? null : parseDate(completedStr);
String deletedStr = elt.getAttribute("deleted");
deleted = (deletedStr == null || deletedStr.length() == 0) ? null : parseDate(deletedStr);
String priorityStr = elt.getAttribute("priority");
if (priorityStr.length() > 0)
{
switch (priorityStr.charAt(0))
{
case 'N':
case 'n':
priority = Priority.None;
break;
case '3':
priority = Priority.Low;
break;
case '2':
priority = Priority.Medium;
break;
case '1':
priority = Priority.High;
break;
default:
System.err.println("Unrecognized RTM task priority: '" + priorityStr + "'");
priority = Priority.Medium;
}
}
else
{
priority = Priority.None;
}
if (elt.hasAttribute("postponed") == true && elt.getAttribute("postponed").length() > 0)
{
postponed = Integer.parseInt(elt.getAttribute("postponed"));
}
else
{
postponed = 0;
}
estimate = elt.getAttribute("estimate");
}
public String getId()
{
return id;
}
public Date getDue()
{
return due;
}
public int getHasDueTime()
{
return hasDueTime;
}
public Date getAdded()
{
return added;
}
public Date getCompleted()
{
return completed;
}
public Date getDeleted()
{
return deleted;
}
public Priority getPriority()
{
return priority;
}
public int getPostponed()
{
return postponed;
}
public String getEstimate()
{
return estimate;
}
@Override
public String toString()
{
return "Task<" + id + ">";
}
}

@ -1,60 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm.data;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.w3c.dom.Element;
/**
*
* @author Will Ross Jun 22, 2007
*/
public class RtmTaskList extends RtmData {
private final String id;
private final List<RtmTaskSeries> series;
public RtmTaskList(String id) {
this.id = id;
this.series = new ArrayList<RtmTaskSeries>();
}
public RtmTaskList(Element elt) {
id = elt.getAttribute("id");
series = new ArrayList<RtmTaskSeries>();
for (Element seriesElt : children(elt, "taskseries")) {
series.add(new RtmTaskSeries(seriesElt));
}
if (id == null || id.length() == 0) { throw new RuntimeException("No id found in task list."); }
}
public String getId() {
return id;
}
public List<RtmTaskSeries> getSeries() {
return Collections.unmodifiableList(series);
}
}

@ -1,100 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm.data;
import java.util.Date;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import android.util.Log;
/**
* Represents a single task note.
*
* @author Edouard Mercier
* @since 2008.04.22
*/
public class RtmTaskNote
extends RtmData
{
private String id;
private Date created;
private Date modified;
private String title;
private String text;
public RtmTaskNote(Element element)
{
id = element.getAttribute("id");
created = parseDate(element.getAttribute("created"));
modified = parseDate(element.getAttribute("modified"));
title = element.getAttribute("title");
// The note text itself might be split across multiple children of the
// note element, so get all of the children.
for (int i=0; i < element.getChildNodes().getLength(); i++) {
Object innerNote = element.getChildNodes().item(i);
if(!(innerNote instanceof Text)) {
Log.w("rtm-note", "Expected text type, got " + innerNote.getClass());
continue;
}
Text innerText = (Text) innerNote;
if (text == null)
text = innerText.getData();
else
text = text.concat(innerText.getData());
}
}
public String getId()
{
return id;
}
public Date getCreated()
{
return created;
}
public Date getModified()
{
return modified;
}
public String getTitle()
{
return title;
}
public String getText()
{
return text;
}
}

@ -1,53 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm.data;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Element;
/**
* Represents the notes of a task.
*
* @author Edouard Mercier
* @since 2008.04.22
*/
public class RtmTaskNotes
extends RtmData
{
private List<RtmTaskNote> notes;
public RtmTaskNotes(Element element)
{
notes = new ArrayList<RtmTaskNote>();
for (Element child : children(element, "note"))
{
notes.add(new RtmTaskNote(child));
}
}
public List<RtmTaskNote> getNotes()
{
return notes;
}
}

@ -1,161 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm.data;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.w3c.dom.Element;
/**
*
* @author Will Ross Jun 22, 2007
*/
public class RtmTaskSeries extends RtmData {
private final String id;
private final Date created;
private final Date modified;
private final String name;
private final String source;
private final RtmTask task;
private final LinkedList<String> tags;
private final RtmTaskNotes notes;
private final String locationId;
private final String url;
private final boolean hasRecurrence;
public RtmTaskSeries(String id, Date created, Date modified, String name,
String source, RtmTask task) {
this.id = id;
this.created = created;
this.modified = modified;
this.name = name;
this.source = source;
this.task = task;
this.locationId = null;
notes = null;
url = null;
tags = null;
hasRecurrence = false;
}
public RtmTaskSeries(Element elt) {
id = elt.getAttribute("id");
created = parseDate(elt.getAttribute("created"));
modified = parseDate(elt.getAttribute("modified"));
name = elt.getAttribute("name");
source = elt.getAttribute("source");
List<Element> children = children(elt, "task");
if (children.size() > 1) {
// assume it's a repeating task - pick the child with nearest
// but not expired due date
RtmTask selectedTask = new RtmTask(children.get(0));
for(Element element : children) {
RtmTask childTask = new RtmTask(element);
if(childTask.getCompleted() == null) {
selectedTask = childTask;
break;
}
}
task = selectedTask;
} else {
task = new RtmTask(child(elt, "task"));
}
notes = new RtmTaskNotes(child(elt, "notes"));
locationId = elt.getAttribute("location_id");
url = elt.getAttribute("url");
hasRecurrence = children(elt, "rrule").size() > 0;
Element elementTags = child(elt, "tags");
if (elementTags.getChildNodes().getLength() > 0) {
List<Element> elementTagList = children(elementTags, "tag");
tags = new LinkedList<String>();
for (Element elementTag : elementTagList) {
String tag = text(elementTag);
if (tag != null)
tags.add(tag);
}
} else {
tags = null;
}
}
public String getId() {
return id;
}
public Date getCreated() {
return created;
}
public Date getModified() {
return modified;
}
public String getName() {
return name;
}
public String getSource() {
return source;
}
public RtmTask getTask() {
return task;
}
public LinkedList<String> getTags() {
return tags;
}
public RtmTaskNotes getNotes() {
return notes;
}
public String getLocationId() {
return locationId;
}
@Override
public String toString() {
return "TaskSeries<" + id + "," + name + ">";
}
public String getURL() {
return url;
}
public boolean hasRecurrence() {
return hasRecurrence;
}
}

@ -1,50 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm.data;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.w3c.dom.Element;
/**
*
* @author Will Ross Jun 21, 2007
*/
public class RtmTasks extends RtmData {
private final List<RtmTaskList> lists;
public RtmTasks() {
this.lists = new ArrayList<RtmTaskList>();
}
public RtmTasks(Element elt) {
this.lists = new ArrayList<RtmTaskList>();
for (Element listElt : children(elt, "list")) {
lists.add(new RtmTaskList(listElt));
}
}
public List<RtmTaskList> getLists() {
return Collections.unmodifiableList(lists);
}
}

@ -1,39 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm.data;
import org.w3c.dom.Element;
public class RtmTimeline extends RtmData {
private final String id;
public RtmTimeline(String id) {
this.id = id;
}
public RtmTimeline(Element elt) {
id = text(elt);
}
public String getId() {
return id;
}
}

@ -1,62 +0,0 @@
/*
* Copyright 2007, MetaDimensional Technologies Inc.
*
*
* This file is part of the RememberTheMilk Java API.
*
* The RememberTheMilk Java API is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* The RememberTheMilk Java API is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mdt.rtm.data;
import org.w3c.dom.Element;
/**
*
* @author Will Ross Jun 21, 2007
*/
public class RtmUser extends RtmData {
private final String id;
private final String username;
private final String fullname;
public RtmUser(String id, String username, String fullname) {
this.id = id;
this.username = username;
this.fullname = fullname;
}
public RtmUser(Element elt) {
if (!elt.getNodeName().equals("user")) { throw new IllegalArgumentException("Element " + elt.getNodeName() + " does not represent a User object."); }
this.id = elt.getAttribute("id");
this.username = elt.getAttribute("username");
this.fullname = elt.getAttribute("fullname");
}
public String getId() {
return id;
}
public String getUsername() {
return username;
}
public String getFullname() {
return fullname;
}
}
Loading…
Cancel
Save