#ignite-1170: add scan query support for rest commands.
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/d301d938 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/d301d938 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/d301d938 Branch: refs/heads/ignite-1170 Commit: d301d938a9287bc4c3663dc134f3897b2d2756f6 Parents: 2008ee3 Author: ivasilinets <ivasilin...@gridgain.com> Authored: Wed Jul 29 16:40:09 2015 +0300 Committer: ivasilinets <ivasilin...@gridgain.com> Committed: Wed Jul 29 16:40:09 2015 +0300 ---------------------------------------------------------------------- .../JettyRestProcessorAbstractSelfTest.java | 57 ++++++ .../processors/rest/GridRestProcessor.java | 2 +- .../handlers/query/QueryCommandHandler.java | 99 +++++++++-- .../rest/request/RestQueryRequest.java | 173 +++++++++++++++++++ .../rest/request/RestSqlQueryRequest.java | 125 -------------- .../http/jetty/GridJettyRestHandler.java | 33 +++- 6 files changed, 341 insertions(+), 148 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d301d938/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java index 5f3d15e..d659df2 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java @@ -27,6 +27,7 @@ import org.apache.ignite.configuration.*; import org.apache.ignite.internal.processors.json.*; import org.apache.ignite.internal.processors.rest.handlers.*; import org.apache.ignite.internal.util.typedef.*; +import org.apache.ignite.lang.*; import org.apache.ignite.testframework.*; import java.io.*; @@ -1319,6 +1320,52 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro /** * @throws Exception If failed. */ + public void testQueryScan() throws Exception { + Map<String, String> params = new HashMap<>(); + params.put("cmd", GridRestCommand.EXECUTE_SCAN_QUERY.key()); + params.put("psz", "10"); + params.put("cacheName", "person"); + params.put("classname", ScanFilter.class.getName()); + + String ret = content(params); + + assertNotNull(ret); + assertTrue(!ret.isEmpty()); + + JSONObject json = JSONObject.fromObject(ret); + + List items = (List)((Map)json.get("response")).get("items"); + + assertEquals(2, items.size()); + + assertFalse(queryCursorFound()); + } + + /** + * @throws Exception If failed. + */ + public void testIncorrectQueryScan() throws Exception { + Map<String, String> params = new HashMap<>(); + params.put("cmd", GridRestCommand.EXECUTE_SCAN_QUERY.key()); + params.put("psz", "10"); + params.put("cacheName", "person"); + params.put("classname", ScanFilter.class.getName() + 1); + + String ret = content(params); + + assertNotNull(ret); + assertTrue(!ret.isEmpty()); + + JSONObject json = JSONObject.fromObject(ret); + + String err = (String)json.get("error"); + + assertTrue(err.contains("Failed to find target class")); + } + + /** + * @throws Exception If failed. + */ public void testQuery() throws Exception { grid(0).cache(null).put("1", "1"); grid(0).cache(null).put("2", "2"); @@ -1761,4 +1808,14 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro return id; } } + + /** + * Test filter for scan query. + */ + public static class ScanFilter implements IgniteBiPredicate<Integer, Person> { + /** {@inheritDoc} */ + @Override public boolean apply(Integer integer, Person person) { + return person.salary > 1000; + } + } } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d301d938/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java index 7b502dd..8871d1a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java @@ -544,7 +544,7 @@ public class GridRestProcessor extends GridProcessorAdapter { case CLOSE_SQL_QUERY: case FETCH_SQL_QUERY: perm = SecurityPermission.CACHE_READ; - name = ((RestSqlQueryRequest)req).cacheName(); + name = ((RestQueryRequest)req).cacheName(); break; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d301d938/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/query/QueryCommandHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/query/QueryCommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/query/QueryCommandHandler.java index 3e9cb18..eafa1d2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/query/QueryCommandHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/query/QueryCommandHandler.java @@ -29,6 +29,7 @@ import org.apache.ignite.internal.util.future.*; import org.apache.ignite.internal.util.typedef.internal.*; import org.apache.ignite.lang.*; +import java.lang.reflect.*; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; @@ -69,23 +70,24 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { assert req != null; assert SUPPORTED_COMMANDS.contains(req.command()); - assert req instanceof RestSqlQueryRequest : "Invalid type of query request."; + assert req instanceof RestQueryRequest : "Invalid type of query request."; switch (req.command()) { case EXECUTE_SQL_QUERY: - case EXECUTE_SQL_FIELDS_QUERY: { + case EXECUTE_SQL_FIELDS_QUERY: + case EXECUTE_SCAN_QUERY: { return ctx.closure().callLocalSafe( - new ExecuteQueryCallable(ctx, (RestSqlQueryRequest)req, qryCurs), false); + new ExecuteQueryCallable(ctx, (RestQueryRequest)req, qryCurs), false); } case FETCH_SQL_QUERY: { return ctx.closure().callLocalSafe( - new FetchQueryCallable(ctx, (RestSqlQueryRequest)req, qryCurs), false); + new FetchQueryCallable(ctx, (RestQueryRequest)req, qryCurs), false); } case CLOSE_SQL_QUERY: { return ctx.closure().callLocalSafe( - new CloseQueryCallable((RestSqlQueryRequest)req, qryCurs), false); + new CloseQueryCallable((RestQueryRequest)req, qryCurs), false); } } @@ -100,7 +102,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { private GridKernalContext ctx; /** Execute query request. */ - private RestSqlQueryRequest req; + private RestQueryRequest req; /** Queries cursors. */ private ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs; @@ -110,7 +112,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { * @param req Execute query request. * @param qryCurs Queries cursors. */ - public ExecuteQueryCallable(GridKernalContext ctx, RestSqlQueryRequest req, + public ExecuteQueryCallable(GridKernalContext ctx, RestQueryRequest req, ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs) { this.ctx = ctx; this.req = req; @@ -124,15 +126,33 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { try { Query qry; - if (req.typeName() != null) { - qry = new SqlQuery(req.typeName(), req.sqlQuery()); + switch (req.queryType()) { + case SQL: + qry = new SqlQuery(req.typeName(), req.sqlQuery()); - ((SqlQuery)qry).setArgs(req.arguments()); - } - else { - qry = new SqlFieldsQuery(req.sqlQuery()); + ((SqlQuery) qry).setArgs(req.arguments()); + + break; + + case SQL_FIELDS: + qry = new SqlFieldsQuery(req.sqlQuery()); + + ((SqlFieldsQuery) qry).setArgs(req.arguments()); + + break; + + case SCAN: + IgniteBiPredicate pred = null; - ((SqlFieldsQuery)qry).setArgs(req.arguments()); + if (req.className() != null) + pred = instance(IgniteBiPredicate.class, req.className()); + + qry = new ScanQuery(pred); + + break; + + default: + throw new IgniteException("Incorrect query type."); } IgniteCache<Object, Object> cache = ctx.grid().cache(req.cacheName()); @@ -183,7 +203,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { */ private static class CloseQueryCallable implements Callable<GridRestResponse> { /** Execute query request. */ - private RestSqlQueryRequest req; + private RestQueryRequest req; /** Queries cursors. */ private final ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs; @@ -192,7 +212,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { * @param req Execute query request. * @param qryCurs Queries cursors. */ - public CloseQueryCallable(RestSqlQueryRequest req, + public CloseQueryCallable(RestQueryRequest req, ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs) { this.req = req; this.qryCurs = qryCurs; @@ -226,7 +246,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { */ private static class FetchQueryCallable implements Callable<GridRestResponse> { /** Execute query request. */ - private RestSqlQueryRequest req; + private RestQueryRequest req; /** Queries cursors. */ private final ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs; @@ -239,7 +259,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { * @param req Execute query request. * @param qryCurs Queries cursors. */ - public FetchQueryCallable(GridKernalContext ctx, RestSqlQueryRequest req, + public FetchQueryCallable(GridKernalContext ctx, RestQueryRequest req, ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs) { this.ctx = ctx; this.req = req; @@ -277,7 +297,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { */ private static CacheQueryResult createQueryResult( ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs, - Iterator cur, RestSqlQueryRequest req, Long qryId, GridKernalContext ctx) { + Iterator cur, RestQueryRequest req, Long qryId, GridKernalContext ctx) { CacheQueryResult res = new CacheQueryResult(); List<Object> items = new ArrayList<>(); @@ -296,4 +316,45 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { return res; } + + /** + * Creates class instance. + * + * @param cls Target class. + * @param clsName Implementing class name. + * @return Class instance. + * @throws IgniteException If failed. + */ + private static <T> T instance(Class<? extends T> cls, String clsName) throws IgniteException { + try { + Class<?> implCls = Class.forName(clsName); + + if (!cls.isAssignableFrom(implCls)) + throw new IgniteException("Failed to create instance (target class does not extend or implement " + + "required class or interface) [cls=" + cls.getName() + ", clsName=" + clsName + ']'); + + Constructor<?> ctor = implCls.getConstructor(); + + return (T)ctor.newInstance(); + } + catch (ClassNotFoundException e) { + throw new IgniteException("Failed to find target class: " + clsName, e); + } + catch (NoSuchMethodException e) { + throw new IgniteException("Failed to find constructor for provided arguments " + + "[clsName=" + clsName + ']', e); + } + catch (InstantiationException e) { + throw new IgniteException("Failed to instantiate target class " + + "[clsName=" + clsName + ']', e); + } + catch (IllegalAccessException e) { + throw new IgniteException("Failed to instantiate class (constructor is not available) " + + "[clsName=" + clsName + ']', e); + } + catch (InvocationTargetException e) { + throw new IgniteException("Failed to instantiate class (constructor threw an exception) " + + "[clsName=" + clsName + ']', e.getCause()); + } + } } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d301d938/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestQueryRequest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestQueryRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestQueryRequest.java new file mode 100644 index 0000000..029b573 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestQueryRequest.java @@ -0,0 +1,173 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.processors.rest.request; + +/** + * Sql query request. + */ +public class RestQueryRequest extends GridRestRequest { + /** Sql query. */ + private String sqlQry; + + /** Sql query arguments. */ + private Object[] args; + + /** Page size. */ + private Integer pageSize; + + /** Cache name. */ + private String cacheName; + + /** Query id. */ + private Long qryId; + + /** Query type name. */ + private String typeName; + + /** Predicate class name for scan query. */ + private String className; + + /** Query type. */ + private QueryType type; + + /** + * @param sqlQry Sql query. + */ + public void sqlQuery(String sqlQry) { + this.sqlQry = sqlQry; + } + + /** + * @return Sql query. + */ + public String sqlQuery() { + return sqlQry; + } + + /** + * @param args Sql query arguments. + */ + public void arguments(Object[] args) { + this.args = args; + } + + /** + * @return Sql query arguments. + */ + public Object[] arguments() { + return args; + } + + /** + * @param pageSize Page size. + */ + public void pageSize(Integer pageSize) { + this.pageSize = pageSize; + } + + /** + * @return Page size. + */ + public int pageSize() { + return pageSize; + } + + /** + * @param cacheName Cache name. + */ + public void cacheName(String cacheName) { + this.cacheName = cacheName; + } + + /** + * @return Cache name. + */ + public String cacheName() { + return cacheName; + } + + /** + * @param id Query id. + */ + public void queryId(Long id) { + this.qryId = id; + } + + /** + * @return Query id. + */ + public Long queryId() { + return qryId; + } + + /** + * @param typeName Query type name. + */ + public void typeName(String typeName) { + this.typeName = typeName; + } + + /** + * @return Query type name. + */ + public String typeName() { + return typeName; + } + + /** + * @return Predicate class name for scan query. + */ + public String className() { + return className; + } + + /** + * @param className Predicate class name for scan query. + */ + public void className(String className) { + this.className = className; + } + + /** + * @param type Query type. + */ + public void queryType(QueryType type) { + this.type = type; + } + + /** + * @return Query type. + */ + public QueryType queryType() { + return type; + } + + /** + * Supported query types. + */ + public enum QueryType { + /** Sql query. */ + SQL, + + /** Sql fields query. */ + SQL_FIELDS, + + /** Scan query. */ + SCAN + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d301d938/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestSqlQueryRequest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestSqlQueryRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestSqlQueryRequest.java deleted file mode 100644 index 5ba3a50..0000000 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestSqlQueryRequest.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.ignite.internal.processors.rest.request; - -/** - * Sql query request. - */ -public class RestSqlQueryRequest extends GridRestRequest { - /** Sql query. */ - private String sqlQry; - - /** Sql query arguments. */ - private Object[] args; - - /** Page size. */ - private Integer pageSize; - - /** Cache name. */ - private String cacheName; - - /** Query id. */ - private Long qryId; - - /** Query type name. */ - private String typeName; - - /** - * @param sqlQry Sql query. - */ - public void sqlQuery(String sqlQry) { - this.sqlQry = sqlQry; - } - - /** - * @return Sql query. - */ - public String sqlQuery() { - return sqlQry; - } - - /** - * @param args Sql query arguments. - */ - public void arguments(Object[] args) { - this.args = args; - } - - /** - * @return Sql query arguments. - */ - public Object[] arguments() { - return args; - } - - /** - * @param pageSize Page size. - */ - public void pageSize(Integer pageSize) { - this.pageSize = pageSize; - } - - /** - * @return Page size. - */ - public int pageSize() { - return pageSize; - } - - /** - * @param cacheName Cache name. - */ - public void cacheName(String cacheName) { - this.cacheName = cacheName; - } - - /** - * @return Cache name. - */ - public String cacheName() { - return cacheName; - } - - /** - * @param id Query id. - */ - public void queryId(Long id) { - this.qryId = id; - } - - /** - * @return Query id. - */ - public Long queryId() { - return qryId; - } - - /** - * @param typeName Query type name. - */ - public void typeName(String typeName) { - this.typeName = typeName; - } - - /** - * @return Query type name. - */ - public String typeName() { - return typeName; - } -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d301d938/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java ---------------------------------------------------------------------- diff --git a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java b/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java index 2cf9988..6181f5e 100644 --- a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java +++ b/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java @@ -24,6 +24,7 @@ import org.apache.ignite.internal.*; import org.apache.ignite.internal.processors.rest.*; import org.apache.ignite.internal.processors.rest.client.message.*; import org.apache.ignite.internal.processors.rest.request.*; +import org.apache.ignite.internal.processors.rest.request.RestQueryRequest.*; import org.apache.ignite.internal.util.typedef.*; import org.apache.ignite.internal.util.typedef.internal.*; import org.apache.ignite.lang.*; @@ -639,7 +640,7 @@ public class GridJettyRestHandler extends AbstractHandler { case EXECUTE_SQL_QUERY: case EXECUTE_SQL_FIELDS_QUERY: { - RestSqlQueryRequest restReq0 = new RestSqlQueryRequest(); + RestQueryRequest restReq0 = new RestQueryRequest(); restReq0.sqlQuery((String) params.get("qry")); @@ -660,13 +661,39 @@ public class GridJettyRestHandler extends AbstractHandler { restReq0.cacheName((String)params.get("cacheName")); + if (cmd.equals(EXECUTE_SQL_QUERY)) + restReq0.queryType(QueryType.SQL); + else + restReq0.queryType(QueryType.SQL_FIELDS); + + restReq = restReq0; + + break; + } + + case EXECUTE_SCAN_QUERY: { + RestQueryRequest restReq0 = new RestQueryRequest(); + + restReq0.sqlQuery((String) params.get("qry")); + + String psz = (String) params.get("psz"); + + if (psz != null) + restReq0.pageSize(Integer.parseInt(psz)); + + restReq0.cacheName((String)params.get("cacheName")); + + restReq0.className((String)params.get("classname")); + + restReq0.queryType(QueryType.SCAN); + restReq = restReq0; break; } case FETCH_SQL_QUERY: { - RestSqlQueryRequest restReq0 = new RestSqlQueryRequest(); + RestQueryRequest restReq0 = new RestQueryRequest(); String qryId = (String) params.get("qryId"); @@ -686,7 +713,7 @@ public class GridJettyRestHandler extends AbstractHandler { } case CLOSE_SQL_QUERY: { - RestSqlQueryRequest restReq0 = new RestSqlQueryRequest(); + RestQueryRequest restReq0 = new RestQueryRequest(); String qryId = (String) params.get("qryId");