From 8411af2d502fa1528f8df9ff8060b5c299a05474 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 12 Oct 2015 10:50:04 +0700 Subject: [PATCH] # ignite-1168 --- .../rest/JettyRestProcessorAbstractSelfTest.java | 225 +++++++++++++++++++++ .../managers/discovery/GridDiscoveryManager.java | 36 +++- .../processors/cache/GridCacheProcessor.java | 8 +- .../cache/query/GridCacheQueryManager.java | 27 ++- .../cache/query/GridCacheSqlIndexMetadata.java | 7 +- .../cache/query/GridCacheSqlMetadata.java | 22 +- .../internal/processors/rest/GridRestCommand.java | 8 +- .../processors/rest/GridRestProcessor.java | 6 +- .../handlers/cache/GridCacheCommandHandler.java | 49 ++++- .../rest/handlers/query/QueryCommandHandler.java | 134 +++++++++--- .../handlers/top/GridTopologyCommandHandler.java | 31 +-- .../processors/rest/request/RestQueryRequest.java | 173 ++++++++++++++++ .../rest/request/RestSqlQueryRequest.java | 125 ------------ .../protocols/http/jetty/GridJettyJsonConfig.java | 158 ++++++++++++++- .../protocols/http/jetty/GridJettyRestHandler.java | 42 +++- 15 files changed, 857 insertions(+), 194 deletions(-) create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestQueryRequest.java delete mode 100644 modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestSqlQueryRequest.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 ac0edff..bb6e67e 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 @@ -24,6 +24,7 @@ import java.io.Serializable; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; +import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -31,14 +32,24 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; +import net.sf.json.JSONNull; import net.sf.json.JSONObject; import org.apache.ignite.IgniteCache; import org.apache.ignite.cache.CachePeekMode; import org.apache.ignite.cache.query.SqlQuery; import org.apache.ignite.cache.query.annotations.QuerySqlField; +import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.internal.processors.cache.GridCacheProcessor; +import org.apache.ignite.internal.processors.cache.IgniteCacheProxy; +import org.apache.ignite.internal.processors.cache.IgniteInternalCache; +import org.apache.ignite.internal.processors.cache.query.GridCacheSqlIndexMetadata; +import org.apache.ignite.internal.processors.cache.query.GridCacheSqlMetadata; import org.apache.ignite.internal.processors.rest.handlers.GridRestCommandHandler; import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.internal.CU; +import org.apache.ignite.lang.IgniteBiPredicate; +import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.testframework.GridTestUtils; import static org.apache.ignite.IgniteSystemProperties.IGNITE_JETTY_PORT; @@ -907,6 +918,106 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro } /** + * @param meta Metadata for Ignite cache. + * @throws Exception If failed. + */ + private void testMetadata(GridCacheSqlMetadata meta) throws Exception { + Map params = F.asMap("cmd", GridRestCommand.CACHE_METADATA.key()); + + if (meta.cacheName() != null) + params.put("cacheName", meta.cacheName()); + + String ret = content(params); + + assertNotNull(ret); + assertTrue(!ret.isEmpty()); + + info("Cache metadata result: " + ret); + + jsonEquals(ret, pattern("\\{.+\\}", true)); + + Map res = (Map)JSONObject.fromObject(ret).get("response"); + + Collection types = (Collection)res.get("types"); + + assertNotNull(types); + assertEqualsCollections(meta.types(), types); + + Map keyClasses = (Map)res.get("keyClasses"); + + assertNotNull(keyClasses); + assertTrue(meta.keyClasses().equals(keyClasses)); + + Map valClasses = (Map)res.get("valClasses"); + + assertNotNull(valClasses); + assertTrue(meta.valClasses().equals(valClasses)); + + Map fields = (Map)res.get("fields"); + + assertNotNull(fields); + assertTrue(meta.fields().equals(fields)); + + Map indexesByType = (Map)res.get("indexes"); + + assertNotNull(indexesByType); + assertEquals(meta.indexes().size(), indexesByType.size()); + + for (Map.Entry> metaIndexes : meta.indexes().entrySet()) { + Collection indexes = (Collection)indexesByType.get(metaIndexes.getKey()); + + assertNotNull(indexes); + assertEquals(metaIndexes.getValue().size(), indexes.size()); + + for (final GridCacheSqlIndexMetadata metaIdx : metaIndexes.getValue()) { + Map idx = F.find(indexes, null, new IgnitePredicate() { + @Override public boolean apply(Map map) { + return metaIdx.name().equals(map.get("name")); + } + }); + + assertNotNull(idx); + + assertEqualsCollections(metaIdx.fields(), (Collection)idx.get("fields")); + assertEqualsCollections(metaIdx.descendings(), (Collection)idx.get("descendings")); + assertEquals(metaIdx.unique(), idx.get("unique")); + } + } + } + + /** + * @throws Exception If failed. + */ + public void testMetadataLocal() throws Exception { + GridCacheProcessor cacheProc = grid(0).context().cache(); + + for (IgniteInternalCache cache : cacheProc.caches()) { + if (CU.isSystemCache(cache.name())) + continue; + + GridCacheSqlMetadata meta = F.first(cache.context().queries().sqlMetadata()); + + testMetadata(meta); + } + } + + /** + * @throws Exception If failed. + */ + public void testMetadataRemote() throws Exception { + CacheConfiguration partialCacheCfg = new CacheConfiguration<>("partial"); + + partialCacheCfg.setIndexedTypes(Integer.class, String.class); + partialCacheCfg.setNodeFilter(new NodeIdFilter(grid(1).localNode().id())); + + IgniteCacheProxy c = (IgniteCacheProxy)grid(1).createCache(partialCacheCfg); + + GridCacheSqlMetadata meta = F.first(c.context().queries().sqlMetadata()); + + testMetadata(meta); + } + + /** * @throws Exception If failed. */ public void testTopology() throws Exception { @@ -918,6 +1029,23 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro info("Topology command result: " + ret); jsonEquals(ret, pattern("\\[\\{.+\\}\\]", true)); + + JSONObject json = JSONObject.fromObject(ret); + + Collection nodes = (Collection)json.get("response"); + + assertEquals(GRID_CNT, nodes.size()); + + for (Map node : nodes) { + assertEquals(JSONNull.getInstance(), node.get("attributes")); + assertEquals(JSONNull.getInstance(), node.get("metrics")); + + assertEquals("PARTITIONED", node.get("defaultCacheMode")); + + Map caches = (Map)node.get("caches"); + + assertEquals(F.asMap("person", "PARTITIONED"), caches); + } } /** @@ -1056,6 +1184,75 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro /** * @throws Exception If failed. */ + public void testQueryScan() throws Exception { + Map params = new HashMap<>(); + params.put("cmd", GridRestCommand.EXECUTE_SCAN_QUERY.key()); + params.put("pageSize", "10"); + params.put("cacheName", "person"); + + String ret = content(params); + + assertNotNull(ret); + assertTrue(!ret.isEmpty()); + + JSONObject json = JSONObject.fromObject(ret); + + List items = (List)((Map)json.get("response")).get("items"); + + assertEquals(4, items.size()); + + assertFalse(queryCursorFound()); + } + + /** + * @throws Exception If failed. + */ + public void testFilterQueryScan() throws Exception { + Map params = new HashMap<>(); + params.put("cmd", GridRestCommand.EXECUTE_SCAN_QUERY.key()); + params.put("pageSize", "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 testIncorrectFilterQueryScan() throws Exception { + Map params = new HashMap<>(); + params.put("cmd", GridRestCommand.EXECUTE_SCAN_QUERY.key()); + params.put("pageSize", "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"); @@ -1323,4 +1520,32 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro return id; } } + + /** + * Test filter for scan query. + */ + public static class ScanFilter implements IgniteBiPredicate { + /** {@inheritDoc} */ + @Override public boolean apply(Integer integer, Person person) { + return person.salary > 1000; + } + } + + /** Filter by node ID. */ + private static class NodeIdFilter implements IgnitePredicate { + /** */ + private final UUID nid; + + /** + * @param nid Node ID where cache should be started. + */ + NodeIdFilter(UUID nid) { + this.nid = nid; + } + + /** {@inheritDoc} */ + @Override public boolean apply(ClusterNode n) { + return n.id().equals(nid); + } + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java index 2ed4520..6aba211 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java @@ -56,6 +56,7 @@ import org.apache.ignite.IgniteClientDisconnectedException; import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteInterruptedException; import org.apache.ignite.cache.CacheMetrics; +import org.apache.ignite.cache.CacheMode; import org.apache.ignite.cluster.ClusterMetrics; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.events.DiscoveryEvent; @@ -299,16 +300,16 @@ public class GridDiscoveryManager extends GridManagerAdapter { * @param cacheName Cache name. * @param filter Cache filter. * @param nearEnabled Near enabled flag. - * @param loc {@code True} if cache is local. + * @param cacheMode Cache mode. */ public void setCacheFilter( String cacheName, IgnitePredicate filter, boolean nearEnabled, - boolean loc + CacheMode cacheMode ) { if (!registeredCaches.containsKey(cacheName)) - registeredCaches.put(cacheName, new CachePredicate(filter, nearEnabled, loc)); + registeredCaches.put(cacheName, new CachePredicate(filter, nearEnabled, cacheMode)); } /** @@ -1592,6 +1593,25 @@ public class GridDiscoveryManager extends GridManagerAdapter { } /** + * @param node Node to check. + * @return Cache names accessible on the given node. + */ + public Map nodeCaches(ClusterNode node) { + Map caches = U.newHashMap(registeredCaches.size()); + + for (Map.Entry entry : registeredCaches.entrySet()) { + String cacheName = entry.getKey(); + + CachePredicate pred = entry.getValue(); + + if (pred != null && pred.cacheNode(node)) + caches.put(cacheName, pred.cacheMode); + } + + return caches; + } + + /** * Checks if cache with given name has at least one node with near cache enabled. * * @param cacheName Cache name. @@ -2832,8 +2852,8 @@ public class GridDiscoveryManager extends GridManagerAdapter { /** If near cache is enabled on data nodes. */ private final boolean nearEnabled; - /** Flag indicating if cache is local. */ - private final boolean loc; + /** Cache mode. */ + private final CacheMode cacheMode; /** Collection of client near nodes. */ private final ConcurrentHashMap clientNodes; @@ -2841,14 +2861,14 @@ public class GridDiscoveryManager extends GridManagerAdapter { /** * @param cacheFilter Cache filter. * @param nearEnabled Near enabled flag. - * @param loc {@code True} if cache is local. + * @param cacheMode Cache mode. */ - private CachePredicate(IgnitePredicate cacheFilter, boolean nearEnabled, boolean loc) { + private CachePredicate(IgnitePredicate cacheFilter, boolean nearEnabled, CacheMode cacheMode) { assert cacheFilter != null; this.cacheFilter = cacheFilter; this.nearEnabled = nearEnabled; - this.loc = loc; + this.cacheMode = cacheMode; clientNodes = new ConcurrentHashMap<>(); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java index daa4475..8c96c0c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java @@ -689,7 +689,7 @@ public class GridCacheProcessor extends GridProcessorAdapter { cfg.getName(), cfg.getNodeFilter(), cfg.getNearConfiguration() != null && cfg.getCacheMode() == PARTITIONED, - cfg.getCacheMode() == LOCAL); + cfg.getCacheMode()); ctx.discovery().addClientNode(cfg.getName(), ctx.localNodeId(), @@ -1941,7 +1941,7 @@ public class GridCacheProcessor extends GridProcessorAdapter { req.cacheName(), ccfg.getNodeFilter(), ccfg.getNearConfiguration() != null, - ccfg.getCacheMode() == LOCAL); + ccfg.getCacheMode()); } } else { @@ -1968,7 +1968,7 @@ public class GridCacheProcessor extends GridProcessorAdapter { req.cacheName(), ccfg.getNodeFilter(), ccfg.getNearConfiguration() != null, - ccfg.getCacheMode() == LOCAL); + ccfg.getCacheMode()); } } } @@ -2468,7 +2468,7 @@ public class GridCacheProcessor extends GridProcessorAdapter { ccfg.getName(), ccfg.getNodeFilter(), ccfg.getNearConfiguration() != null, - ccfg.getCacheMode() == LOCAL); + ccfg.getCacheMode()); ctx.discovery().addClientNode(req.cacheName(), req.initiatingNodeId(), diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java index 25ace1b..f907d5b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java @@ -2229,6 +2229,26 @@ public abstract class GridCacheQueryManager extends GridCacheManagerAdapte } /** {@inheritDoc} */ + @Override public Map keyClasses() { + return keyClasses; + } + + /** {@inheritDoc} */ + @Override public Map valClasses() { + return valClasses; + } + + /** {@inheritDoc} */ + @Override public Map> fields() { + return fields; + } + + /** {@inheritDoc} */ + @Override public Map> indexes() { + return indexes; + } + + /** {@inheritDoc} */ @Override public Collection indexes(String type) { return indexes.get(type); } @@ -2319,6 +2339,11 @@ public abstract class GridCacheQueryManager extends GridCacheManagerAdapte } /** {@inheritDoc} */ + @Override public Collection descendings() { + return descendings; + } + + /** {@inheritDoc} */ @Override public boolean unique() { return unique; } @@ -3078,4 +3103,4 @@ public abstract class GridCacheQueryManager extends GridCacheManagerAdapte false, keepPortable); } -} \ No newline at end of file +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlIndexMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlIndexMetadata.java index 6b3ed68..539a156 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlIndexMetadata.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlIndexMetadata.java @@ -51,9 +51,14 @@ public interface GridCacheSqlIndexMetadata extends Externalizable { public boolean descending(String field); /** + * @return Descendings. + */ + public Collection descendings(); + + /** * Gets whether this is a unique index. * * @return {@code True} if index is unique, {@code false} otherwise. */ public boolean unique(); -} \ No newline at end of file +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlMetadata.java index dae034c..724962e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlMetadata.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlMetadata.java @@ -78,6 +78,26 @@ public interface GridCacheSqlMetadata extends Externalizable { @Nullable public Map fields(String type); /** + * @return Key classes. + */ + public Map keyClasses(); + + /** + * @return Value classes. + */ + public Map valClasses(); + + /** + * @return Fields. + */ + public Map> fields(); + + /** + * @return Indexes. + */ + public Map> indexes(); + + /** * Gets descriptors of indexes created for provided type. * See {@link GridCacheSqlIndexMetadata} javadoc for more information. * @@ -86,4 +106,4 @@ public interface GridCacheSqlMetadata extends Externalizable { * @see GridCacheSqlIndexMetadata */ public Collection indexes(String type); -} \ No newline at end of file +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestCommand.java index 4f9b3ae..8282d3a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestCommand.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestCommand.java @@ -96,6 +96,9 @@ public enum GridRestCommand { /** Cache size. */ CACHE_SIZE("size"), + /** Cache metadata. */ + CACHE_METADATA("metadata"), + /** Increment. */ ATOMIC_INCREMENT("incr"), @@ -141,6 +144,9 @@ public enum GridRestCommand { /** Execute sql fields query. */ EXECUTE_SQL_FIELDS_QUERY("qryfldexe"), + /** Execute scan query. */ + EXECUTE_SCAN_QUERY("qryscanexe"), + /** Fetch query results. */ FETCH_SQL_QUERY("qryfetch"), @@ -193,4 +199,4 @@ public enum GridRestCommand { public String key() { return key; } -} \ No newline at end of file +} 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 d54c8bb..27b3e6f 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 @@ -51,7 +51,7 @@ import org.apache.ignite.internal.processors.rest.protocols.tcp.GridTcpRestProto import org.apache.ignite.internal.processors.rest.request.GridRestCacheRequest; import org.apache.ignite.internal.processors.rest.request.GridRestRequest; import org.apache.ignite.internal.processors.rest.request.GridRestTaskRequest; -import org.apache.ignite.internal.processors.rest.request.RestSqlQueryRequest; +import org.apache.ignite.internal.processors.rest.request.RestQueryRequest; import org.apache.ignite.internal.processors.security.SecurityContext; import org.apache.ignite.internal.util.GridSpinReadWriteLock; import org.apache.ignite.internal.util.future.GridFinishedFuture; @@ -715,10 +715,11 @@ public class GridRestProcessor extends GridProcessorAdapter { case EXECUTE_SQL_QUERY: case EXECUTE_SQL_FIELDS_QUERY: + case EXECUTE_SCAN_QUERY: case CLOSE_SQL_QUERY: case FETCH_SQL_QUERY: perm = SecurityPermission.CACHE_READ; - name = ((RestSqlQueryRequest)req).cacheName(); + name = ((RestQueryRequest)req).cacheName(); break; @@ -764,6 +765,7 @@ public class GridRestProcessor extends GridProcessorAdapter { case CACHE_METRICS: case CACHE_SIZE: + case CACHE_METADATA: case TOPOLOGY: case NODE: case VERSION: diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java index 9d32c17..1c6d18d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java @@ -40,6 +40,7 @@ import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.IgniteKernal; import org.apache.ignite.internal.processors.cache.GridCacheAdapter; import org.apache.ignite.internal.processors.cache.IgniteInternalCache; +import org.apache.ignite.internal.processors.cache.query.GridCacheSqlMetadata; import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; import org.apache.ignite.internal.processors.rest.GridRestCommand; import org.apache.ignite.internal.processors.rest.GridRestResponse; @@ -73,6 +74,7 @@ import static org.apache.ignite.internal.processors.rest.GridRestCommand.CACHE_G import static org.apache.ignite.internal.processors.rest.GridRestCommand.CACHE_GET_AND_PUT_IF_ABSENT; import static org.apache.ignite.internal.processors.rest.GridRestCommand.CACHE_GET_AND_REMOVE; import static org.apache.ignite.internal.processors.rest.GridRestCommand.CACHE_GET_AND_REPLACE; +import static org.apache.ignite.internal.processors.rest.GridRestCommand.CACHE_METADATA; import static org.apache.ignite.internal.processors.rest.GridRestCommand.CACHE_METRICS; import static org.apache.ignite.internal.processors.rest.GridRestCommand.CACHE_PREPEND; import static org.apache.ignite.internal.processors.rest.GridRestCommand.CACHE_PUT; @@ -119,7 +121,8 @@ public class GridCacheCommandHandler extends GridRestCommandHandlerAdapter { CACHE_APPEND, CACHE_PREPEND, CACHE_METRICS, - CACHE_SIZE + CACHE_SIZE, + CACHE_METADATA ); /** Requests with required parameter {@code key}. */ @@ -224,6 +227,25 @@ public class GridCacheCommandHandler extends GridRestCommandHandlerAdapter { break; } + case CACHE_METADATA: { + IgniteInternalCache cache = ctx.cache().cache(cacheName); + + if (cache != null) { + GridCacheSqlMetadata res = F.first(cache.context().queries().sqlMetadata()); + + fut = new GridFinishedFuture<>(new GridRestResponse(res)); + } + else { + ClusterGroup prj = ctx.grid().cluster().forDataNodes(cacheName); + + ctx.task().setThreadContext(TC_NO_FAILOVER, true); + + fut = ctx.closure().callAsync(BALANCE, new MetadataCommand(cacheName), prj.nodes()); + } + + break; + } + case CACHE_CONTAINS_KEYS: { fut = executeCommand(req.destinationId(), req.clientId(), cacheName, skipStore, key, new ContainsKeysCommand(getKeys(req0))); @@ -892,6 +914,31 @@ public class GridCacheCommandHandler extends GridRestCommandHandlerAdapter { } /** */ + private static class MetadataCommand implements Callable, Serializable { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final String cacheName; + + /** */ + @IgniteInstanceResource + private Ignite g; + + /** + * @param cacheName Cache name. + */ + private MetadataCommand(String cacheName) { + this.cacheName = cacheName; + } + + /** {@inheritDoc} */ + @Override public GridRestResponse call() throws Exception { + return new GridRestResponse(F.first(cache(g, cacheName).context().queries().sqlMetadata())); + } + } + + /** */ private static class ContainsKeysCommand extends CacheProjectionCommand { /** */ private static final long serialVersionUID = 0L; 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 64c7673..3822737 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 @@ -17,6 +17,8 @@ package org.apache.ignite.internal.processors.rest.handlers.query; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -25,8 +27,10 @@ import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import org.apache.ignite.IgniteCache; +import org.apache.ignite.IgniteException; import org.apache.ignite.cache.query.Query; import org.apache.ignite.cache.query.QueryCursor; +import org.apache.ignite.cache.query.ScanQuery; import org.apache.ignite.cache.query.SqlFieldsQuery; import org.apache.ignite.cache.query.SqlQuery; import org.apache.ignite.internal.GridKernalContext; @@ -37,12 +41,14 @@ import org.apache.ignite.internal.processors.rest.GridRestCommand; import org.apache.ignite.internal.processors.rest.GridRestResponse; import org.apache.ignite.internal.processors.rest.handlers.GridRestCommandHandlerAdapter; import org.apache.ignite.internal.processors.rest.request.GridRestRequest; -import org.apache.ignite.internal.processors.rest.request.RestSqlQueryRequest; +import org.apache.ignite.internal.processors.rest.request.RestQueryRequest; import org.apache.ignite.internal.util.future.GridFinishedFuture; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteBiPredicate; import org.apache.ignite.lang.IgniteBiTuple; import static org.apache.ignite.internal.processors.rest.GridRestCommand.CLOSE_SQL_QUERY; +import static org.apache.ignite.internal.processors.rest.GridRestCommand.EXECUTE_SCAN_QUERY; import static org.apache.ignite.internal.processors.rest.GridRestCommand.EXECUTE_SQL_FIELDS_QUERY; import static org.apache.ignite.internal.processors.rest.GridRestCommand.EXECUTE_SQL_QUERY; import static org.apache.ignite.internal.processors.rest.GridRestCommand.FETCH_SQL_QUERY; @@ -54,6 +60,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { /** Supported commands. */ private static final Collection SUPPORTED_COMMANDS = U.sealList(EXECUTE_SQL_QUERY, EXECUTE_SQL_FIELDS_QUERY, + EXECUTE_SCAN_QUERY, FETCH_SQL_QUERY, CLOSE_SQL_QUERY); @@ -80,23 +87,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((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); } } @@ -111,7 +119,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { private GridKernalContext ctx; /** Execute query request. */ - private RestSqlQueryRequest req; + private RestQueryRequest req; /** Queries cursors. */ private ConcurrentHashMap> qryCurs; @@ -121,7 +129,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> qryCurs) { this.ctx = ctx; this.req = req; @@ -135,15 +143,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; + + if (req.className() != null) + pred = instance(IgniteBiPredicate.class, req.className()); + + qry = new ScanQuery(pred); - ((SqlFieldsQuery)qry).setArgs(req.arguments()); + break; + + default: + throw new IgniteException("Incorrect query type [type=" + req.queryType() + "]"); } IgniteCache cache = ctx.grid().cache(req.cacheName()); @@ -160,9 +186,25 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { CacheQueryResult res = createQueryResult(qryCurs, cur, req, qryId); - List fieldsMeta = ((QueryCursorImpl) qryCur).fieldsMeta(); + switch (req.queryType()) { + case SQL: + case SQL_FIELDS: + List fieldsMeta = ((QueryCursorImpl) qryCur).fieldsMeta(); + + res.setFieldsMetadata(convertMetadata(fieldsMeta)); + + break; + case SCAN: + CacheQueryFieldsMetaResult keyField = new CacheQueryFieldsMetaResult(); + keyField.setFieldName("key"); + + CacheQueryFieldsMetaResult valField = new CacheQueryFieldsMetaResult(); + valField.setFieldName("value"); - res.setFieldsMetadata(convertMetadata(fieldsMeta)); + res.setFieldsMetadata(U.sealList(keyField, valField)); + + break; + } return new GridRestResponse(res); } @@ -194,7 +236,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { */ private static class CloseQueryCallable implements Callable { /** Execute query request. */ - private RestSqlQueryRequest req; + private RestQueryRequest req; /** Queries cursors. */ private final ConcurrentHashMap> qryCurs; @@ -203,7 +245,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { * @param req Execute query request. * @param qryCurs Queries cursors. */ - public CloseQueryCallable(RestSqlQueryRequest req, + public CloseQueryCallable(RestQueryRequest req, ConcurrentHashMap> qryCurs) { this.req = req; this.qryCurs = qryCurs; @@ -237,17 +279,22 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { */ private static class FetchQueryCallable implements Callable { /** Execute query request. */ - private RestSqlQueryRequest req; + private RestQueryRequest req; /** Queries cursors. */ private final ConcurrentHashMap> qryCurs; + /** Grid kernal context. */ + private final GridKernalContext ctx; + /** + * @param ctx Grid kernal context. * @param req Execute query request. * @param qryCurs Queries cursors. */ - public FetchQueryCallable(RestSqlQueryRequest req, + public FetchQueryCallable(GridKernalContext ctx, RestQueryRequest req, ConcurrentHashMap> qryCurs) { + this.ctx = ctx; this.req = req; this.qryCurs = qryCurs; } @@ -282,7 +329,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { */ private static CacheQueryResult createQueryResult( ConcurrentHashMap> qryCurs, - Iterator cur, RestSqlQueryRequest req, Long qryId) { + Iterator cur, RestQueryRequest req, Long qryId) { CacheQueryResult res = new CacheQueryResult(); List items = new ArrayList<>(); @@ -301,4 +348,45 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { return res; } -} \ No newline at end of file + + /** + * Creates class instance. + * + * @param cls Target class. + * @param clsName Implementing class name. + * @return Class instance. + * @throws IgniteException If failed. + */ + private static T instance(Class 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()); + } + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/top/GridTopologyCommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/top/GridTopologyCommandHandler.java index aee8a1f..eea29d2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/top/GridTopologyCommandHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/top/GridTopologyCommandHandler.java @@ -27,11 +27,11 @@ import java.util.Iterator; import java.util.Map; import java.util.UUID; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.cache.CacheMode; import org.apache.ignite.cluster.ClusterMetrics; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.IgniteInternalFuture; -import org.apache.ignite.internal.processors.cache.GridCacheAttributes; import org.apache.ignite.internal.processors.port.GridPortRecord; import org.apache.ignite.internal.processors.rest.GridRestCommand; import org.apache.ignite.internal.processors.rest.GridRestProtocol; @@ -44,6 +44,7 @@ import org.apache.ignite.internal.processors.rest.request.GridRestTopologyReques import org.apache.ignite.internal.util.future.GridFinishedFuture; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.P1; +import org.apache.ignite.internal.util.typedef.internal.CU; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.spi.IgnitePortProtocol; @@ -194,24 +195,26 @@ public class GridTopologyCommandHandler extends GridRestCommandHandlerAdapter { nodeBean.setTcpAddresses(nonEmptyList(node.>attribute(ATTR_REST_TCP_ADDRS))); nodeBean.setTcpHostNames(nonEmptyList(node.>attribute(ATTR_REST_TCP_HOST_NAMES))); - GridCacheAttributes[] caches = node.attribute(ATTR_CACHE); + Map nodeCaches = ctx.discovery().nodeCaches(node); - if (!F.isEmpty(caches)) { - Map cacheMap = new HashMap<>(); + Map cacheMap = U.newHashMap(nodeCaches.size()); - for (GridCacheAttributes cacheAttr : caches) { - if (ctx.cache().systemCache(cacheAttr.cacheName())) - continue; + for (Map.Entry cache : nodeCaches.entrySet()) { + String cacheName = cache.getKey(); - if (cacheAttr.cacheName() != null) - cacheMap.put(cacheAttr.cacheName(), cacheAttr.cacheMode().toString()); - else - nodeBean.setDefaultCacheMode(cacheAttr.cacheMode().toString()); - } + if (CU.isSystemCache(cacheName) || CU.isIgfsCache(ctx.config(), cacheName)) + continue; - nodeBean.setCaches(cacheMap); + String mode = cache.getValue().toString(); + + if (cacheName != null) + cacheMap.put(cacheName, mode); + else + nodeBean.setDefaultCacheMode(mode); } + nodeBean.setCaches(cacheMap); + if (mtr) { ClusterMetrics metrics = node.metrics(); @@ -345,4 +348,4 @@ public class GridTopologyCommandHandler extends GridRestCommandHandlerAdapter { @Override public String toString() { return S.toString(GridTopologyCommandHandler.class, this); } -} \ No newline at end of file +} 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 + } +} 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 b6ab339..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; - } -} \ No newline at end of file diff --git a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyJsonConfig.java b/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyJsonConfig.java index 60b44ee..0adbc14 100644 --- a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyJsonConfig.java +++ b/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyJsonConfig.java @@ -17,10 +17,19 @@ package org.apache.ignite.internal.processors.rest.protocols.http.jetty; +import java.text.DateFormat; import java.util.UUID; +import net.sf.json.JSONObject; import net.sf.json.JsonConfig; +import net.sf.json.processors.JsonBeanProcessor; +import net.sf.json.processors.JsonBeanProcessorMatcher; import net.sf.json.processors.JsonValueProcessor; +import java.util.*; +import net.sf.json.processors.JsonValueProcessorMatcher; +import org.apache.ignite.internal.processors.cache.query.GridCacheSqlIndexMetadata; +import org.apache.ignite.internal.processors.cache.query.GridCacheSqlMetadata; + /** * Jetty protocol json configuration. */ @@ -29,21 +38,158 @@ public class GridJettyJsonConfig extends JsonConfig { * Constructs default jetty json config. */ public GridJettyJsonConfig() { - registerJsonValueProcessor(UUID.class, new ToStringJsonProcessor()); + registerJsonValueProcessor(UUID.class, new UUIDToStringJsonProcessor()); + registerJsonValueProcessor(Date.class, new DateToStringJsonProcessor()); + registerJsonValueProcessor(java.sql.Date.class, new DateToStringJsonProcessor()); + + registerJsonBeanProcessor(GridCacheSqlMetadata.class, new GridCacheSqlMetadataBeanProcessor()); + registerJsonValueProcessor(GridCacheSqlIndexMetadata.class, new GridCacheSqlIndexMetadataToJson()); + + setJsonBeanProcessorMatcher(new GridJettyJsonBeanProcessorMatcher()); + setJsonValueProcessorMatcher(new GridJettyJsonValueProcessorMatcher()); } /** - * Helper class for simple to-string conversion for the beans. + * Helper class for simple to-string conversion for {@link UUID}. */ - private static class ToStringJsonProcessor implements JsonValueProcessor { + private static class UUIDToStringJsonProcessor implements JsonValueProcessor { /** {@inheritDoc} */ @Override public Object processArrayValue(Object val, JsonConfig jsonCfg) { - throw new UnsupportedOperationException("Serialize array to string is not supported: " + val); + if (val == null) + return new JSONObject(true); + + if (val instanceof UUID) + return val.toString(); + + throw new UnsupportedOperationException("Serialize value to json is not supported: " + val); } /** {@inheritDoc} */ @Override public Object processObjectValue(String key, Object val, JsonConfig jsonCfg) { - return val == null ? null : val.toString(); + return processArrayValue(val, jsonCfg); + } + } + + /** + * Helper class for simple to-string conversion for {@link Date}. + */ + private static class DateToStringJsonProcessor implements JsonValueProcessor { + private final DateFormat enUsFormat + = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US); + + /** {@inheritDoc} */ + @Override public synchronized Object processArrayValue(Object val, JsonConfig jsonCfg) { + if (val == null) + return new JSONObject(true); + + if (val instanceof Date) + return enUsFormat.format(val); + + throw new UnsupportedOperationException("Serialize value to json is not supported: " + val); + } + + /** {@inheritDoc} */ + @Override public synchronized Object processObjectValue(String key, Object val, JsonConfig jsonCfg) { + return processArrayValue(val, jsonCfg); + } + } + + /** + * Helper class for simple to-json conversion for {@link GridCacheSqlMetadata}. + */ + private static class GridCacheSqlMetadataBeanProcessor implements JsonBeanProcessor { + /** {@inheritDoc} */ + @Override public JSONObject processBean(Object bean, JsonConfig jsonCfg) { + if (bean == null) + return new JSONObject(true); + + if (bean instanceof GridCacheSqlMetadata) { + GridCacheSqlMetadata r = (GridCacheSqlMetadata) bean; + + return new JSONObject() + .element("cacheName", r.cacheName(), jsonCfg) + .element("types", r.types(), jsonCfg) + .element("keyClasses", r.keyClasses(), jsonCfg) + .element("valClasses", r.valClasses(), jsonCfg) + .element("fields", r.fields(), jsonCfg) + .element("indexes", r.indexes(), jsonCfg); + } + + throw new UnsupportedOperationException("Serialize bean to json is not supported: " + bean); + } + } + + /** + * Helper class for simple to-json conversion for {@link GridCacheSqlIndexMetadata}. + */ + private static class GridCacheSqlIndexMetadataToJson implements JsonValueProcessor { + /** {@inheritDoc} */ + @Override public Object processArrayValue(Object val, JsonConfig jsonCfg) { + if (val == null) + return new JSONObject(true); + + if (val instanceof GridCacheSqlIndexMetadata) { + GridCacheSqlIndexMetadata r = (GridCacheSqlIndexMetadata) val; + + return new JSONObject() + .element("name", r.name()) + .element("fields", r.fields()) + .element("descendings", r.descendings()) + .element("unique", r.unique()); + } + + throw new UnsupportedOperationException("Serialize array to string is not supported: " + val); + } + + /** {@inheritDoc} */ + @Override public Object processObjectValue(String key, Object value, JsonConfig jsonCfg) { + return processArrayValue(value, jsonCfg); + } + } + + /** + * Class for finding a matching JsonBeanProcessor. Matches the target class with instanceOf. + */ + private static final class GridJettyJsonBeanProcessorMatcher extends JsonBeanProcessorMatcher { + /** {@inheritDoc} */ + @Override public Object getMatch(Class target, Set keys) { + if (target == null || keys == null) + return null; + + if (keys.contains(target)) + return target; + + for (Object key : keys) { + Class clazz = (Class) key; + + if (clazz.isAssignableFrom(target)) + return key; + } + + return null; + } + } + + /** + * Class for finding a matching JsonValueProcessor. Matches the target class with instanceOf. + */ + private static final class GridJettyJsonValueProcessorMatcher extends JsonValueProcessorMatcher { + /** {@inheritDoc} */ + @Override public Object getMatch(Class target, Set keys) { + if (target == null || keys == null) + return null; + + if (keys.contains(target)) + return target; + + for (Object key : keys) { + Class clazz = (Class) key; + + if (clazz.isAssignableFrom(target)) + return key; + } + + return null; } } -} \ No newline at end of file +} 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 9b82098..55bd842 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 @@ -51,7 +51,7 @@ import org.apache.ignite.internal.processors.rest.request.GridRestLogRequest; import org.apache.ignite.internal.processors.rest.request.GridRestRequest; import org.apache.ignite.internal.processors.rest.request.GridRestTaskRequest; import org.apache.ignite.internal.processors.rest.request.GridRestTopologyRequest; -import org.apache.ignite.internal.processors.rest.request.RestSqlQueryRequest; +import org.apache.ignite.internal.processors.rest.request.RestQueryRequest; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteClosure; @@ -64,6 +64,7 @@ import static org.apache.ignite.internal.processors.rest.GridRestCommand.CACHE_C import static org.apache.ignite.internal.processors.rest.GridRestCommand.CACHE_GET_ALL; import static org.apache.ignite.internal.processors.rest.GridRestCommand.CACHE_PUT_ALL; import static org.apache.ignite.internal.processors.rest.GridRestCommand.CACHE_REMOVE_ALL; +import static org.apache.ignite.internal.processors.rest.GridRestCommand.EXECUTE_SQL_QUERY; import static org.apache.ignite.internal.processors.rest.GridRestResponse.STATUS_FAILED; /** @@ -396,6 +397,7 @@ public class GridJettyRestHandler extends AbstractHandler { case CACHE_CAS: case CACHE_METRICS: case CACHE_SIZE: + case CACHE_METADATA: case CACHE_REPLACE: case CACHE_APPEND: case CACHE_PREPEND: { @@ -497,9 +499,9 @@ 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")); + restReq0.sqlQuery((String)params.get("qry")); restReq0.arguments(values("arg", params).toArray()); @@ -512,20 +514,46 @@ public class GridJettyRestHandler extends AbstractHandler { restReq0.cacheName((String)params.get("cacheName")); + if (cmd == EXECUTE_SQL_QUERY) + restReq0.queryType(RestQueryRequest.QueryType.SQL); + else + restReq0.queryType(RestQueryRequest.QueryType.SQL_FIELDS); + + restReq = restReq0; + + break; + } + + case EXECUTE_SCAN_QUERY: { + RestQueryRequest restReq0 = new RestQueryRequest(); + + restReq0.sqlQuery((String)params.get("qry")); + + String pageSize = (String)params.get("pageSize"); + + if (pageSize != null) + restReq0.pageSize(Integer.parseInt(pageSize)); + + restReq0.cacheName((String)params.get("cacheName")); + + restReq0.className((String)params.get("classname")); + + restReq0.queryType(RestQueryRequest.QueryType.SCAN); + restReq = restReq0; break; } case FETCH_SQL_QUERY: { - RestSqlQueryRequest restReq0 = new RestSqlQueryRequest(); + RestQueryRequest restReq0 = new RestQueryRequest(); String qryId = (String) params.get("qryId"); if (qryId != null) restReq0.queryId(Long.parseLong(qryId)); - String pageSize = (String) params.get("pageSize"); + String pageSize = (String)params.get("pageSize"); if (pageSize != null) restReq0.pageSize(Integer.parseInt(pageSize)); @@ -538,7 +566,7 @@ public class GridJettyRestHandler extends AbstractHandler { } case CLOSE_SQL_QUERY: { - RestSqlQueryRequest restReq0 = new RestSqlQueryRequest(); + RestQueryRequest restReq0 = new RestQueryRequest(); String qryId = (String) params.get("qryId"); @@ -736,4 +764,4 @@ public class GridJettyRestHandler extends AbstractHandler { return null; } -} \ No newline at end of file +} -- 2.6.1