Skip to content

Commit 7b4a3ec

Browse files
author
hideki
committed
Merge commit 'd6c2960788624d6570c539b556ce68e78cd540e1'
* commit 'd6c2960788624d6570c539b556ce68e78cd540e1': Applied feedbacks from @pasin Fixed #11 Implement ReplicationFilter Compiler for JavaScript Experimental ReplicationFilter and ReplicationFilterCompiler with JavaScript update submodule update submodule update submodule update submodule update submodule update submodule update submodule
2 parents 933cc94 + d6c2960 commit 7b4a3ec

File tree

10 files changed

+317
-4
lines changed

10 files changed

+317
-4
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* Copyright (c) 2015 Couchbase, Inc All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11+
* either express or implied. See the License for the specific language governing permissions
12+
* and limitations under the License.
13+
*/
14+
15+
package com.couchbase.lite.javascript;
16+
17+
import com.couchbase.lite.ReplicationFilter;
18+
import com.couchbase.lite.ReplicationFilterCompiler;
19+
20+
/**
21+
* Created by hideki on 10/28/15.
22+
*/
23+
public class JavaScriptReplicationFilterCompiler implements ReplicationFilterCompiler {
24+
@Override
25+
public ReplicationFilter compileFilterFunction(String source, String language) {
26+
if (language != null && language.equalsIgnoreCase("javascript")) {
27+
return new ReplicationFilterBlockRhino(source);
28+
}
29+
throw new IllegalArgumentException(language + " is not supported");
30+
}
31+
}

src/main/java/com/couchbase/lite/javascript/JavaScriptViewCompiler.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/**
2+
* Copyright (c) 2015 Couchbase, Inc All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11+
* either express or implied. See the License for the specific language governing permissions
12+
* and limitations under the License.
13+
*/
114
package com.couchbase.lite.javascript;
215

316
import com.couchbase.lite.Mapper;
@@ -7,15 +20,15 @@
720
public class JavaScriptViewCompiler implements ViewCompiler {
821
@Override
922
public Mapper compileMap(String source, String language) {
10-
if (language.equals("javascript")) {
23+
if (language != null && language.equalsIgnoreCase("javascript")) {
1124
return new ViewMapBlockRhino(source);
1225
}
1326
throw new IllegalArgumentException(language + " is not supported");
1427
}
1528

1629
@Override
1730
public Reducer compileReduce(String source, String language) {
18-
if (language.equals("javascript")) {
31+
if (language != null && language.equalsIgnoreCase("javascript")) {
1932
return new ViewReduceBlockRhino(source);
2033
}
2134
throw new IllegalArgumentException(language + " is not supported");
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
* Copyright (c) 2015 Couchbase, Inc All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11+
* either express or implied. See the License for the specific language governing permissions
12+
* and limitations under the License.
13+
*/
14+
15+
package com.couchbase.lite.javascript;
16+
17+
import com.couchbase.lite.ReplicationFilter;
18+
import com.couchbase.lite.SavedRevision;
19+
import com.couchbase.lite.javascript.scopes.GlobalScope;
20+
import com.couchbase.lite.javascript.wrapper.CustomWrapFactory;
21+
import com.couchbase.lite.util.Log;
22+
23+
import org.mozilla.javascript.Function;
24+
import org.mozilla.javascript.Scriptable;
25+
import org.mozilla.javascript.WrapFactory;
26+
27+
import java.util.Map;
28+
29+
/**
30+
* Created by hideki on 10/28/15.
31+
*/
32+
public class ReplicationFilterBlockRhino implements ReplicationFilter {
33+
public static String TAG = "ReplicationFilterBlockRhino";
34+
35+
private static WrapFactory wrapFactory = new CustomWrapFactory();
36+
private Scriptable scope;
37+
private GlobalScope globalScope;
38+
private Function filterFunction;
39+
40+
public ReplicationFilterBlockRhino(String src){
41+
org.mozilla.javascript.Context ctx = org.mozilla.javascript.Context.enter();
42+
try {
43+
ctx.setOptimizationLevel(-1);
44+
ctx.setWrapFactory(wrapFactory);
45+
globalScope = new GlobalScope();
46+
scope = ctx.initStandardObjects(globalScope, true);
47+
filterFunction = ctx.compileFunction(scope, src, "filter", 0, null);
48+
} finally {
49+
org.mozilla.javascript.Context.exit();
50+
}
51+
}
52+
53+
@Override
54+
public boolean filter(SavedRevision revision, Map<String, Object> params) {
55+
org.mozilla.javascript.Context ctx = org.mozilla.javascript.Context.enter();
56+
try {
57+
ctx.setOptimizationLevel(-1);
58+
ctx.setWrapFactory(wrapFactory);
59+
60+
Scriptable localScope = ctx.newObject(scope);
61+
localScope.setPrototype(scope);
62+
localScope.setParentScope(null);
63+
64+
Object jsDocument = org.mozilla.javascript.Context.javaToJS(revision.getProperties(), localScope);
65+
Object jsParams = org.mozilla.javascript.Context.javaToJS(params, localScope);
66+
67+
try {
68+
Object result = filterFunction.call(ctx, localScope, null, new Object[]{jsDocument, jsParams});
69+
return ((Boolean)result).booleanValue();
70+
} catch (org.mozilla.javascript.RhinoException e) {
71+
// Error in the JavaScript view - CouchDB swallows the error and tries the next document
72+
Log.e(TAG, "Error in filterFunction.call()", e);
73+
return false;
74+
}
75+
} finally {
76+
org.mozilla.javascript.Context.exit();
77+
}
78+
}
79+
}

src/main/java/com/couchbase/lite/javascript/ViewMapBlockRhino.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/**
2+
* Copyright (c) 2015 Couchbase, Inc All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11+
* either express or implied. See the License for the specific language governing permissions
12+
* and limitations under the License.
13+
*/
114
package com.couchbase.lite.javascript;
215

316
import com.couchbase.lite.Emitter;

src/main/java/com/couchbase/lite/javascript/ViewReduceBlockRhino.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/**
2+
* Copyright (c) 2015 Couchbase, Inc All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11+
* either express or implied. See the License for the specific language governing permissions
12+
* and limitations under the License.
13+
*/
114
package com.couchbase.lite.javascript;
215

316
import com.couchbase.lite.Reducer;

src/main/java/com/couchbase/lite/javascript/scopes/GlobalScope.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,23 @@
1+
/**
2+
* Copyright (c) 2015 Couchbase, Inc All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11+
* either express or implied. See the License for the specific language governing permissions
12+
* and limitations under the License.
13+
*/
114
package com.couchbase.lite.javascript.scopes;
215

316
import com.couchbase.lite.util.Log;
417

518
import org.mozilla.javascript.ScriptableObject;
619

7-
class GlobalScope extends ScriptableObject {
20+
public class GlobalScope extends ScriptableObject {
821
public GlobalScope() {
922
super();
1023
String[] names = {"log"};

src/main/java/com/couchbase/lite/javascript/scopes/MapGlobalScope.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/**
2+
* Copyright (c) 2015 Couchbase, Inc All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11+
* either express or implied. See the License for the specific language governing permissions
12+
* and limitations under the License.
13+
*/
114
package com.couchbase.lite.javascript.scopes;
215

316
import com.couchbase.lite.Emitter;

src/main/java/com/couchbase/lite/javascript/scopes/ReduceGlobalScope.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/**
2+
* Copyright (c) 2015 Couchbase, Inc All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11+
* either express or implied. See the License for the specific language governing permissions
12+
* and limitations under the License.
13+
*/
114
package com.couchbase.lite.javascript.scopes;
215

316
import com.couchbase.lite.CouchbaseLiteException;

src/main/java/com/couchbase/lite/javascript/wrapper/CustomWrapFactory.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/**
2+
* Copyright (c) 2015 Couchbase, Inc All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11+
* either express or implied. See the License for the specific language governing permissions
12+
* and limitations under the License.
13+
*/
114
package com.couchbase.lite.javascript.wrapper;
215

316
import org.mozilla.javascript.Context;
@@ -14,7 +27,6 @@ public class CustomWrapFactory extends WrapFactory {
1427

1528
public CustomWrapFactory() {
1629
setJavaPrimitiveWrap(false);
17-
1830
}
1931

2032
@Override
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/**
2+
* Copyright (c) 2015 Couchbase, Inc All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11+
* either express or implied. See the License for the specific language governing permissions
12+
* and limitations under the License.
13+
*/
14+
15+
package com.couchbase.lite;
16+
17+
import com.couchbase.lite.internal.RevisionInternal;
18+
import com.couchbase.lite.javascript.JavaScriptReplicationFilterCompiler;
19+
20+
import junit.framework.TestCase;
21+
22+
import java.util.HashMap;
23+
import java.util.Map;
24+
25+
/**
26+
* Created by hideki on 11/9/15.
27+
*/
28+
public class ReplicationFilterTestCase extends TestCase {
29+
private JavaScriptReplicationFilterCompiler replicationFilterCompiler;
30+
31+
@Override
32+
public void setUp() throws Exception {
33+
super.setUp();
34+
replicationFilterCompiler = new JavaScriptReplicationFilterCompiler();
35+
}
36+
37+
public void testSimpleFilterTrue() {
38+
Map<String, Object> props = new HashMap<String, Object>();
39+
props.put("_id", "foo");
40+
props.put("_rev", "1-1111");
41+
props.put("_deleted", false);
42+
props.put("type", "order");
43+
props.put("SeatNumber", 10);
44+
RevisionInternal revisionInternal = new RevisionInternal(props);
45+
SavedRevision savedRevision = new SavedRevision((Document)null, revisionInternal);
46+
ReplicationFilter replicationFilter = replicationFilterCompiler.compileFilterFunction("function(doc, req) {if(doc.type && doc.type == 'order') {return true;}else{return false}}", "javascript");
47+
assertTrue(replicationFilter.filter(savedRevision, null));
48+
}
49+
50+
public void testSimpleFilterFalse() {
51+
Map<String, Object> props = new HashMap<String, Object>();
52+
props.put("_id", "foo");
53+
props.put("_rev", "1-1111");
54+
props.put("_deleted", false);
55+
props.put("type", "user");
56+
props.put("Name", "tom");
57+
RevisionInternal revisionInternal = new RevisionInternal(props);
58+
SavedRevision savedRevision = new SavedRevision((Document)null, revisionInternal);
59+
ReplicationFilter replicationFilter = replicationFilterCompiler.compileFilterFunction("function(doc, req) {if(doc.type && doc.type == 'order') {return true;}else{return false}}", "javascript");
60+
assertFalse(replicationFilter.filter(savedRevision, null));
61+
}
62+
63+
64+
public void testSimpleFilterWithReqTrue() {
65+
Map<String, Object> props = new HashMap<String, Object>();
66+
props.put("_id", "foo");
67+
props.put("_rev", "1-1111");
68+
props.put("_deleted", false);
69+
props.put("type", "order");
70+
props.put("SeatNumber", 10);
71+
RevisionInternal revisionInternal = new RevisionInternal(props);
72+
SavedRevision savedRevision = new SavedRevision((Document)null, revisionInternal);
73+
ReplicationFilter replicationFilter = replicationFilterCompiler.compileFilterFunction("function(doc, req) {if(doc.type && doc.type == 'order' && req.abc == 1) {return true;}else{return false}}", "javascript");
74+
Map req = new HashMap();
75+
req.put("abc", 1);
76+
assertTrue(replicationFilter.filter(savedRevision, req));
77+
}
78+
79+
public void testSimpleFilterWithReqFalse() {
80+
Map<String, Object> props = new HashMap<String, Object>();
81+
props.put("_id", "foo");
82+
props.put("_rev", "1-1111");
83+
props.put("_deleted", false);
84+
props.put("type", "user");
85+
props.put("Name", "tom");
86+
RevisionInternal revisionInternal = new RevisionInternal(props);
87+
SavedRevision savedRevision = new SavedRevision((Document)null, revisionInternal);
88+
ReplicationFilter replicationFilter = replicationFilterCompiler.compileFilterFunction("function(doc, req) {if(doc.type && doc.type == 'order' && req.abc == 1) {return true;}else{return false}}", "javascript");
89+
Map req = new HashMap();
90+
req.put("abc", 2);
91+
assertFalse(replicationFilter.filter(savedRevision, req));
92+
}
93+
public void testSimpleFilterWithReqFalse2() {
94+
Map<String, Object> props = new HashMap<String, Object>();
95+
props.put("_id", "foo");
96+
props.put("_rev", "1-1111");
97+
props.put("_deleted", false);
98+
props.put("type", "user");
99+
props.put("Name", "tom");
100+
RevisionInternal revisionInternal = new RevisionInternal(props);
101+
SavedRevision savedRevision = new SavedRevision((Document)null, revisionInternal);
102+
ReplicationFilter replicationFilter = replicationFilterCompiler.compileFilterFunction("function(doc, req) {if(doc.type && doc.type == 'order' && req.abc == 1) {return true;}else{return false}}", "javascript");
103+
assertFalse(replicationFilter.filter(savedRevision, null));
104+
}
105+
public void testInvalidLanguage() {
106+
try {
107+
ReplicationFilter replicationFilter = replicationFilterCompiler.compileFilterFunction("function(doc, req) {if(doc.type && doc.type == 'order' && req.abc == 1) {return true;}else{return false}}", "C++");
108+
fail("IllegalArgumentException should be thrown");
109+
}
110+
catch (IllegalArgumentException e){
111+
}
112+
}
113+
}

0 commit comments

Comments
 (0)