I have finally been dynamically update my UI using phonegap. I had to
update couchbase-lite-java library REST API to implement the feed=continous
and feed=longpoll parameters:
Here are the changes I made to the Router.java file to make it work:
public Status do_GET_Document_active_tasks(Database _db, String _docID,
String _attachmentName) {
return do_GET_active_tasks(_db, _docID, _attachmentName);
}
private boolean longpollReplication = false;
public Status do_GET_active_tasks(Database _db, String _docID, String
_attachmentName) {
// http://wiki.apache.org/couchdb/HttpGetActiveTasks
String feed = getQuery("feed");
longpollReplication = "longpoll".equals(feed);
boolean continuous = !longpollReplication && "continuous".equals(
feed);
String session_id = getQuery("session_id");
ChangeListener listener = new ChangeListener() {
ChangeListener self = this;
@Override
public void changed(ChangeEvent event) {
Map<String,Object> activity = getActivity( event.getSource()
);
if (event.getTransition() != null ) {
activity.put("transition_source", event.getTransition().
getSource());
activity.put("transition_destination", event.
getTransition().getDestination());
activity.put("trigger", event.getTransition().getTrigger
() );
Log.d(Log.TAG_ROUTER, "do_GET_active_tasks Transition ["
+ event.getTransition().getTrigger() + "] Source:" + event.getTransition().
getSource() + ", Destination:" + event.getTransition().getDestination() );
}
if(longpollReplication) {
Log.w(Log.TAG_ROUTER, "Router: Sending longpoll
replication response");
sendResponse();
if(callbackBlock != null) {
byte[] data = null;
try {
data = Manager.getObjectMapper().
writeValueAsBytes(activity);
} catch (Exception e) {
Log.w(Log.TAG_ROUTER, "Error serializing JSON",
e);
}
OutputStream os = connection.getResponseOutputStream
();
try {
os.write(data);
os.close();
} catch (IOException e) {
Log.e(Log.TAG_ROUTER, "IOException writing to
internal streams", e);
}
}
//remove this change listener because a new one will be
added when this responds
event.getSource().removeChangeListener(self);
} else {
Log.w(Log.TAG_ROUTER, "Router: Sending continous
replication change chunk");
sendContinuousReplicationChanges(activity);
}
}
};
List<Map<String,Object>> activities = new ArrayList<Map<String,
Object>>();
for (Database db : manager.allOpenDatabases()) {
List<Replication> allReplicators = db.getAllReplications();
if(allReplicators != null) {
for (Replication replicator : allReplicators) {
Map<String,Object> activity = getActivity( replicator );
activities.add(activity);
if (continuous || longpollReplication) {
if (session_id != null) {
if (replicator.getSessionID().equals(session_id
)){
replicator.addChangeListener(listener);
}
} else {
replicator.addChangeListener(listener);
}
}
}
}
}
if (continuous || longpollReplication) {
connection.setChunked(true);
connection.setResponseCode(Status.OK);
sendResponse();
if (continuous && !activities.isEmpty()) {
for (Map<String,Object> activity : activities) {
sendContinuousReplicationChanges(activity);
}
}
// Don't close connection; more data to come
return new Status(0);
} else {
connection.setResponseBody(new Body(activities));
return new Status(Status.OK);
}
}
private Map<String,Object> getActivity(Replication replicator) {
Map<String,Object> activity = new HashMap<String,Object>();
String source = replicator.getRemoteUrl().toExternalForm();
String target = replicator.getLocalDatabase().getName();
if(!replicator.isPull()) {
String tmp = source;
source = target;
target = tmp;
}
int processed = replicator.getCompletedChangesCount();
int total = replicator.getChangesCount();
String status = String.format("Processed %d / %d changes", processed
, total);
if (! replicator.getStatus().name().equals( ReplicationStatus.
REPLICATION_ACTIVE.name() ) ) {
status = replicator.getStatus().name();
}
int progress = (total > 0) ? Math.round(100 * processed / (float)
total) : 0;
activity.put("type", "Replication");
activity.put("task", replicator.getSessionID());
activity.put("source", source);
activity.put("target", target);
if (replicator.getLastError() != null) {
String msg = String.format("Replicator error: %s. Repl: %s.
Source: %s, Target: %s",
replicator.getLastError(), replicator, source, target);
Log.e(Log.TAG_ROUTER, msg);
Throwable error = replicator.getLastError();
int statusCode = 400;
if (error instanceof HttpResponseException) {
statusCode = ((HttpResponseException)error).getStatusCode();
}
Object[] errorObjects = new Object[]{ statusCode, replicator.
getLastError().toString() };
activity.put("error", errorObjects);
activity.put("status", Replication.ReplicationStatus.
REPLICATION_STOPPED);
activity.put("progress", null);
activity.put("change_count", null);
activity.put("completed_change_count", null);
} else {
activity.put("status", status);
activity.put("progress", progress);
activity.put("change_count", total);
activity.put("completed_change_count", processed);
}
return activity;
}
public void sendContinuousReplicationChanges(Map<String,Object> activity
) {
try {
String jsonString = Manager.getObjectMapper().writeValueAsString
(activity);
if(callbackBlock != null) {
byte[] json = (jsonString + "\n").getBytes();
OutputStream os = connection.getResponseOutputStream();
try {
os.write(json);
os.flush();
} catch (Exception e) {
Log.e(Log.TAG_ROUTER, "IOException writing to internal
streams", e);
}
}
} catch (Exception e) {
Log.w("Unable to serialize change to JSON", e);
}
}
If you would like to see how I implemented it in my phonegap app. you can
check out my source code here.
https://github.com/deefactorial/openmoney-mobile/
I was not able to get feed=continuous to work in my phonegap app because it
does not work for the changes API, But longpoll works quite nicely.
On Wednesday, 12 November 2014 14:46:28 UTC-8, Dominique Legault wrote:
>
> sorry string compare in java is different.
>
> String status = String.format("Processed %d / %d changes", processed,
> total);
> if (! replicator.getStatus().name().equals(
> ReplicationStatus.REPLICATION_ACTIVE
> ) ) {
> status = replicator.getStatus().name();
> }
>
>
>
> On Wednesday, 12 November 2014 14:40:39 UTC-8, Dominique Legault wrote:
>>
>> What about adding:
>>
>> String status = String.format("Processed %d / %d changes", processed,
>> total);
>> if (replicator.getStatus().name() != ReplicationStatus.REPLICATION_ACTIVE
>> ) {
>> status = replicator.getStatus().name();
>> }
>>
>> to this line
>>
>> https://github.com/couchbase/couchbase-lite-java-core/blob/master/src/main/java/com/couchbase/lite/router/Router.java#L698
>>
>> At least I would be able to get the current status of the replication,
>> and I could assume if it was Processed... that it was Active.
>>
>>
>> On Wednesday, 12 November 2014 12:10:06 UTC-8, Dominique Legault wrote:
>>>
>>> See my responses inline:
>>>
>>> On Tuesday, 11 November 2014 14:08:25 UTC-8, Traun Leyden wrote:
>>>>
>>>> See inline responses below:
>>>>
>>>>
>>>>> How can it go back to 2 / 2 changes once it has hit 2 / 3 changes ?
>>>>>
>>>>>
>>>> That's definitely a bug. Can you file a github issue here
>>>> <https://github.com/couchbase/couchbase-lite-java-core> and mention:
>>>>
>>>
>>>> * Is it a pull or push replication?
>>>>
>>> * Which version of Couchbase Lite are you using? (or a link to where
>>>> you downloaded it and I can probably figure out from there)
>>>> * Is this sync'ing with a CouchDB database or a Sync Gateway?
>>>> * Is it possible to put the database or an equivalent database on a
>>>> public URL so that we can test against it and try to reproduce the issue?
>>>>
>>>
>>> I'll try and reproduce the issue to see if it comes up. It may have been
>>> that push replication surpassed the pull replication at that time, I'll get
>>> the logs this time.
>>> Most recent version by doing this four days ago.
>>> phonegap plugin remove com.couchbase.lite.phonegap
>>> phonegap local plugin add https://
>>> github.com/couchbaselabs/Couchbase-Lite-PhoneGap-Plugin.git
>>> I am doing a sync to a sync_gateway
>>> The DB is on a public url, here is the source code:
>>> https://github.com/deefactorial/openmoney-mobile/
>>>
>>> Let me do some preliminary testing to see if I can reproduce the error
>>> and I'll create a bug report with the logcat.
>>>
>>>
>>>
>>>>
>>>>> The changes feed for documents only sends data when it changes, the
>>>>> active_tasks is different in that it sends data continuously.
>>>>> When I turn off access to the internet the stream of continuous
>>>>> responses stops.
>>>>>
>>>>
>>>> I'm not sure I understand this, can you describe it in more details?
>>>> Are you saying that the HTTP response never finishes?
>>>>
>>>>
>>>>
>>> When I get the active_tasks with feed=continuous I get a stream of
>>> responses, often the data hasn't changed. It will be the same response
>>> every time, until a document is changed in my local db, Why does it send
>>> continuous responses when the response data has not changed.
>>> Here is an example log:
>>>
>>> 11-12 11:58:44.569: I/Web Console(3378): task{"progress":100,"target":"
>>> https://deefactorial%2B8%40gmail.com:123456@
>>> cloud.openmoney.cc:4984/openmoney_shadow/","source":"openmoney","type":"Replication","status":"Processed
>>>
>>> 168 / 168 changes","task":"repl001"} at
>>> file:///android_asset/www/js/index.js:5861
>>> 11-12 11:58:44.569: I/Web Console(3378): push sync connected handler
>>> called at file:///android_asset/www/js/index.js:5861
>>> 11-12 11:58:44.620: I/Web Console(3378):
>>> task{"progress":100,"target":"openmoney","source":"https://deefactorial
>>> %2B8%40gmail.com:[email protected]:4984/openmoney_shadow/","type":"Replication","status":"Processed
>>>
>>> 6 / 6 changes","task":"repl002"} at
>>> file:///android_asset/www/js/index.js:5861
>>> 11-12 11:58:44.620: I/Web Console(3378): pull sync connected handler
>>> called at file:///android_asset/www/js/index.js:5861
>>> 11-12 11:58:44.846: I/Web Console(3378): task{"progress":100,"target":"
>>> https://deefactorial%2B8%40gmail.com:123456@
>>> cloud.openmoney.cc:4984/openmoney_shadow/","source":"openmoney","type":"Replication","status":"Processed
>>>
>>> 168 / 168 changes","task":"repl001"} at
>>> file:///android_asset/www/js/index.js:5861
>>> 11-12 11:58:44.846: I/Web Console(3378): push sync connected handler
>>> called at file:///android_asset/www/js/index.js:5861
>>> 11-12 11:58:44.858: I/Web Console(3378):
>>> task{"progress":100,"target":"openmoney","source":"https://deefactorial
>>> %2B8%40gmail.com:[email protected]:4984/openmoney_shadow/","type":"Replication","status":"Processed
>>>
>>> 6 / 6 changes","task":"repl002"} at
>>> file:///android_asset/www/js/index.js:5861
>>> 11-12 11:58:44.858: I/Web Console(3378): pull sync connected handler
>>> called at file:///android_asset/www/js/index.js:5861
>>> 11-12 11:58:45.124: I/Web Console(3378): task{"progress":100,"target":"
>>> https://deefactorial%2B8%40gmail.com:123456@
>>> cloud.openmoney.cc:4984/openmoney_shadow/","source":"openmoney","type":"Replication","status":"Processed
>>>
>>> 168 / 168 changes","task":"repl001"} at
>>> file:///android_asset/www/js/index.js:5861
>>> 11-12 11:58:45.128: I/Web Console(3378): push sync connected handler
>>> called at file:///android_asset/www/js/index.js:5861
>>>
>>> Notice how all those responses happened within 1 second, and there isn't
>>> anything new in each of the responses.
>>>
>>> I have not seen any responses where the status has been anything but
>>> "Processed [number] / [number] changes" in the Android version.
>>> When the replication stops (wifi connection disabled) the stream of
>>> responses stops, there is no response that indicates it has stopped other
>>> than the stream of responses has stopped.
>>>
>>>
>>>>> How do I detect the various different states that the replication is
>>>>> in with the active_tasks API ?
>>>>> Idle when there isn't a change ?
>>>>> Active when changes are not equal ?
>>>>> and Stopped when the stream stops ?
>>>>>
>>>>> How do I know if a change has completed ?
>>>>> do I track the number of changes I have made and compare that to the
>>>>> number of changes completed ?
>>>>>
>>>>> On Monday, 10 November 2014 11:12:03 UTC-8, Jens Alfke wrote:
>>>>>>
>>>>>>
>>>>>> > On Nov 10, 2014, at 10:56 AM, Dominique <[email protected]>
>>>>>> wrote:
>>>>>> >
>>>>>> > What I would like to see is access to the Replication Change
>>>>>> Listener through the REST API, similar to the Document Change Listener.
>>>>>>
>>>>>> If you add "?feed=continuous" to _active_tasks it'll send push
>>>>>> updates just like the _changes feed.
>>>>>>
>>>>>> —Jens
>>>>>>
>>>>>> --
>>>>> You received this message because you are subscribed to the Google
>>>>> Groups "Couchbase Mobile" group.
>>>>> To unsubscribe from this group and stop receiving emails from it, send
>>>>> an email to [email protected].
>>>>> To view this discussion on the web visit
>>>>> https://groups.google.com/d/msgid/mobile-couchbase/24bf3b32-bb3a-4df4-ac5e-78481382345d%40googlegroups.com
>>>>>
>>>>> <https://groups.google.com/d/msgid/mobile-couchbase/24bf3b32-bb3a-4df4-ac5e-78481382345d%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>> .
>>>>>
>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>
>>>>
>>>>
--
You received this message because you are subscribed to the Google Groups
"Couchbase Mobile" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/mobile-couchbase/688b3a30-f3e8-47d0-911d-5fc4e2be27da%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.