This is an automated email from the ASF dual-hosted git repository.
nizhikov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new ce12249e28f IGNITE-22549 CacheScanTask json output format (#11402)
ce12249e28f is described below
commit ce12249e28f019dab620aad48d2659df5f9e4b66
Author: Nikolay <[email protected]>
AuthorDate: Thu Jun 27 14:32:46 2024 +0300
IGNITE-22549 CacheScanTask json output format (#11402)
---
modules/bom/pom.xml | 5 +
.../common/AbstractEventSecurityContextTest.java | 4 +-
.../rest/JettyRestProcessorCommonSelfTest.java | 4 +-
modules/control-utility/pom.xml | 6 +
.../util/GridCommandHandlerClusterByClassTest.java | 199 ++++++++++++++++++-
.../java/org/apache/ignite/dump/DumpReader.java | 6 +-
.../cache/scan/DefaultCacheScanTaskFormat.java | 46 ++++-
.../cache/persistence/snapshot/dump/Dump.java | 5 +
.../dump/DumpConsumerKernalContextAware.java | 33 ++++
.../snapshot/dump/AbstractCacheDumpTest.java | 215 ++++++++++++---------
.../snapshot/dump/IgniteCacheDumpSelfTest.java | 33 ++--
modules/json/README.txt | 4 +
modules/{rest-http => json}/pom.xml | 77 +-------
.../org/apache/ignite/dump/JsonDumpConsumer.java | 151 +++++++++++++++
.../IgniteBinaryObjectJsonDeserializer.java | 2 +-
.../internal/jackson/IgniteObjectMapper.java} | 16 +-
.../cache/scan/JsonCacheScanTaskFormat.java | 57 ++++++
...ernal.management.cache.scan.CacheScanTaskFormat | 1 +
.../org/apache/ignite/dump/IgniteJsonSuite.java | 31 +++
.../apache/ignite/dump/JsonDumpConsumerTest.java | 194 +++++++++++++++++++
modules/rest-http/pom.xml | 23 +--
.../protocols/http/jetty/GridJettyRestHandler.java | 4 +-
pom.xml | 1 +
23 files changed, 905 insertions(+), 212 deletions(-)
diff --git a/modules/bom/pom.xml b/modules/bom/pom.xml
index 40ea220bdd2..32d6659279a 100644
--- a/modules/bom/pom.xml
+++ b/modules/bom/pom.xml
@@ -116,6 +116,11 @@
<artifactId>ignite-opencensus</artifactId>
<version>${revision}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ignite-json</artifactId>
+ <version>${revision}</version>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>ignite-rest-http</artifactId>
diff --git
a/modules/clients/src/test/java/org/apache/ignite/common/AbstractEventSecurityContextTest.java
b/modules/clients/src/test/java/org/apache/ignite/common/AbstractEventSecurityContextTest.java
index de0b11b7ead..81b17713c2c 100644
---
a/modules/clients/src/test/java/org/apache/ignite/common/AbstractEventSecurityContextTest.java
+++
b/modules/clients/src/test/java/org/apache/ignite/common/AbstractEventSecurityContextTest.java
@@ -42,8 +42,8 @@ import org.apache.ignite.events.Event;
import org.apache.ignite.events.JobEvent;
import org.apache.ignite.events.TaskEvent;
import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.jackson.IgniteObjectMapper;
import org.apache.ignite.internal.processors.rest.GridRestCommand;
-import
org.apache.ignite.internal.processors.rest.protocols.http.jetty.GridJettyObjectMapper;
import org.apache.ignite.internal.processors.security.AbstractSecurityTest;
import org.apache.ignite.internal.processors.security.impl.TestSecurityData;
import
org.apache.ignite.internal.processors.security.impl.TestSecurityPluginProvider;
@@ -64,7 +64,7 @@ public abstract class AbstractEventSecurityContextTest
extends AbstractSecurityT
protected static final Map<ClusterNode, Collection<Event>> LISTENED_EVTS =
new ConcurrentHashMap<>();
/** Custom object mapper for HTTP REST API. */
- private static final ObjectMapper OBJECT_MAPPER = new
GridJettyObjectMapper();
+ private static final ObjectMapper OBJECT_MAPPER = new IgniteObjectMapper();
/** Port for REST client connection. */
private static final String DFLT_REST_PORT = "11080";
diff --git
a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorCommonSelfTest.java
b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorCommonSelfTest.java
index 9976c1c52ca..e38386d8bdc 100644
---
a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorCommonSelfTest.java
+++
b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorCommonSelfTest.java
@@ -29,7 +29,7 @@ import java.util.LinkedHashMap;
import java.util.Map;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
-import
org.apache.ignite.internal.processors.rest.protocols.http.jetty.GridJettyObjectMapper;
+import org.apache.ignite.internal.jackson.IgniteObjectMapper;
import org.apache.ignite.internal.util.typedef.internal.SB;
import static org.apache.ignite.IgniteSystemProperties.IGNITE_JETTY_PORT;
@@ -48,7 +48,7 @@ public abstract class JettyRestProcessorCommonSelfTest
extends AbstractRestProce
private static final int DFLT_REST_PORT = 8091;
/** JSON to java mapper. */
- protected static final ObjectMapper JSON_MAPPER = new
GridJettyObjectMapper();
+ protected static final ObjectMapper JSON_MAPPER = new IgniteObjectMapper();
/** {@inheritDoc} */
@Override protected void beforeTestsStarted() throws Exception {
diff --git a/modules/control-utility/pom.xml b/modules/control-utility/pom.xml
index 56964c5a55a..6dd782bf2a2 100644
--- a/modules/control-utility/pom.xml
+++ b/modules/control-utility/pom.xml
@@ -85,6 +85,12 @@
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ignite-json</artifactId>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
diff --git
a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerClusterByClassTest.java
b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerClusterByClassTest.java
index 13d380ddc6c..99a2b156432 100644
---
a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerClusterByClassTest.java
+++
b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerClusterByClassTest.java
@@ -32,6 +32,8 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.Scanner;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
@@ -51,6 +53,8 @@ import java.util.logging.StreamHandler;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.difflib.text.DiffRow;
import com.github.difflib.text.DiffRowGenerator;
import org.apache.ignite.Ignite;
@@ -75,6 +79,7 @@ import org.apache.ignite.internal.client.thin.TcpIgniteClient;
import org.apache.ignite.internal.commandline.ArgumentParser;
import org.apache.ignite.internal.commandline.CommandHandler;
import org.apache.ignite.internal.dto.IgniteDataTransferObject;
+import org.apache.ignite.internal.jackson.IgniteObjectMapper;
import org.apache.ignite.internal.management.IgniteCommandRegistry;
import org.apache.ignite.internal.management.api.HelpCommand;
import org.apache.ignite.internal.management.api.Positional;
@@ -83,6 +88,7 @@ import
org.apache.ignite.internal.management.cache.CacheCommand;
import org.apache.ignite.internal.management.cache.CacheDestroyCommand;
import org.apache.ignite.internal.management.cache.IdleVerifyDumpTask;
import
org.apache.ignite.internal.management.cache.scan.DefaultCacheScanTaskFormat;
+import
org.apache.ignite.internal.management.cache.scan.JsonCacheScanTaskFormat;
import
org.apache.ignite.internal.management.cache.scan.TableCacheScanTaskFormat;
import org.apache.ignite.internal.management.tx.TxTaskResult;
import org.apache.ignite.internal.processors.cache.CacheGroupContext;
@@ -1693,7 +1699,13 @@ public class GridCommandHandlerClusterByClassTest
extends GridCommandHandlerClus
c3.put(1, new TestClass2(
1,
+ new boolean[]{true, false},
+ new char[] {'t', 'e', 's', 't'},
+ new short[] {1, 2, 3},
new int[]{2, 3},
+ new long[] {4, 5},
+ new float[]{},
+ new double[]{42.0},
Collections.singletonMap("some_key", "some_value"),
new String[] {"s1", "s2", "s3"},
DATE,
@@ -1703,7 +1715,13 @@ public class GridCommandHandlerClusterByClassTest
extends GridCommandHandlerClus
c3.put(2, new TestClass2(
2,
- new int[]{3, 4},
+ new boolean[]{true, false},
+ new char[] {'t', 'e', 's', 't'},
+ new short[] {1, 2, 3},
+ new int[]{2, 3},
+ new long[] {4, 5},
+ new float[]{123.0f},
+ new double[] {0},
Collections.singletonMap("1", "2"),
new String[] {"s4", "s5", "s6"},
DATE,
@@ -1713,7 +1731,13 @@ public class GridCommandHandlerClusterByClassTest
extends GridCommandHandlerClus
c3.put(3, new TestClass2(
3,
- new int[]{4, 5},
+ new boolean[]{true, false},
+ new char[] {'t', 'e', 's', 't'},
+ new short[] {1, 2, 3},
+ new int[]{2, 3},
+ new long[] {4, 5},
+ new float[]{123.0f},
+ new double[] {1},
Collections.singletonMap("xxx", "yyy"),
new String[] {"s7", "s8", "s9"},
DATE,
@@ -1753,9 +1777,140 @@ public class GridCommandHandlerClusterByClassTest
extends GridCommandHandlerClus
assertContains(log, testOut.toString(), "some_key=some_value");
assertContains(log, testOut.toString(), "xxx=yyy");
+ assertContains(log, testOut.toString(), "[s1, s2, s3]");
assertContains(log, testOut.toString(), DATE.toString());
}
+ /** */
+ @Test
+ public void testCacheScanJsonFormat() throws Exception {
+ injectTestSystemOut();
+
+ autoConfirmation = false;
+
+ dataForScanTest();
+
+ assertEquals(EXIT_CODE_OK, execute("--cache", SCAN, "--output-format",
JsonCacheScanTaskFormat.NAME, "cache1"));
+
+ Scanner sc = new Scanner(testOut.toString());
+
+ while (sc.hasNextLine() && !Objects.equals(sc.nextLine().trim(),
"data")) ;
+
+ TypeReference<HashMap<String, Object>> typeRef = new
TypeReference<HashMap<String, Object>>() {
+ // No-op.
+ };
+
+ ObjectMapper mapper = new ObjectMapper();
+
+ Set<Integer> keys = new HashSet<>();
+
+ for (int i = 0; i < 3; i++) {
+ assertTrue(sc.hasNextLine());
+
+ Map<String, Object> entryFromJson =
mapper.readValue(sc.nextLine(), typeRef);
+
+ int key = (int)((Map<String,
Object>)entryFromJson.get("key")).get("id");
+
+ keys.add(key);
+
+ Map<String, Object> val = (Map<String,
Object>)entryFromJson.get("value");
+
+ if (key == 1)
+ assertEquals(JOHN, val.get("fio"));
+ else if (key == 2)
+ assertEquals(SARAH, val.get("fio"));
+ else
+ assertEquals(KYLE, val.get("fio"));
+
+ assertEquals(key + 1, val.get("salary"));
+ }
+
+ assertTrue(keys.containsAll(Arrays.asList(1, 2, 3)));
+
+ keys.clear();
+
+ assertEquals(EXIT_CODE_OK, execute("--cache", SCAN, "--output-format",
JsonCacheScanTaskFormat.NAME, "cache2"));
+
+ sc = new Scanner(testOut.toString());
+
+ while (sc.hasNextLine() && !Objects.equals(sc.nextLine().trim(),
"data")) ;
+
+ for (int i = 0; i < 3; i++) {
+ assertTrue(sc.hasNextLine());
+
+ Map<String, Object> entryFromJson =
mapper.readValue(sc.nextLine(), typeRef);
+
+ int key = (int)entryFromJson.get("key");
+
+ keys.add(key);
+
+ String val = (String)entryFromJson.get("value");
+
+ if (key == 1)
+ assertEquals(JOHN, val);
+ else if (key == 2)
+ assertEquals(SARAH, val);
+ else
+ assertEquals(KYLE, val);
+ }
+
+ assertTrue(keys.containsAll(Arrays.asList(1, 2, 3)));
+
+ keys.clear();
+
+ assertEquals(EXIT_CODE_OK, execute("--cache", SCAN, "--output-format",
JsonCacheScanTaskFormat.NAME, "cache3"));
+
+ sc = new Scanner(testOut.toString());
+
+ while (sc.hasNextLine() && !Objects.equals(sc.nextLine().trim(),
"data")) ;
+
+ for (int i = 0; i < 3; i++) {
+ assertTrue(sc.hasNextLine());
+
+ Map<String, Object> entryFromJson =
mapper.readValue(sc.nextLine(), typeRef);
+
+ int key = (int)entryFromJson.get("key");
+
+ keys.add(key);
+
+ Map<String, Object> val = (Map<String,
Object>)entryFromJson.get("value");
+
+ assertEquals(key, val.get("i"));
+ assertEquals(Arrays.asList(true, false), val.get("booleans"));
+ assertEquals("test", val.get("chars"));
+ assertEquals(Arrays.asList(1, 2, 3), val.get("shorts"));
+ assertEquals(Arrays.asList(2, 3), val.get("ints"));
+ assertEquals(Arrays.asList(4, 5), val.get("longs"));
+ assertEquals(Arrays.asList(1, 2, 3), val.get("list"));
+ assertEquals(IgniteObjectMapper.DATE_FORMAT.format(DATE),
val.get("date"));
+
+ int firstIdx = i * 3 + 1;
+
+ assertEquals(Arrays.asList("s" + firstIdx, "s" + (firstIdx + 1),
"s" + (firstIdx + 2)), val.get("strArr"));
+
+ if (key == 1) {
+ assertTrue(((List<?>)val.get("floats")).isEmpty());
+ assertEquals(Arrays.asList(42.0d), val.get("doubles"));
+ assertEquals(Collections.singletonMap("some_key",
"some_value"), val.get("map"));
+ assertEquals(AccessLevel.USER.toString(), val.get("enm"));
+ }
+ else if (key == 2) {
+ assertEquals(Arrays.asList(123d), val.get("floats"));
+ assertEquals(Arrays.asList(0d), val.get("doubles"));
+ assertEquals(Collections.singletonMap("1", "2"),
val.get("map"));
+ assertEquals(AccessLevel.USER.toString(), val.get("enm"));
+ }
+ else {
+ assertEquals(Arrays.asList(123d), val.get("floats"));
+ assertEquals(Arrays.asList(1d), val.get("doubles"));
+ assertEquals(Collections.singletonMap("xxx", "yyy"),
val.get("map"));
+ assertEquals(AccessLevel.SUPER.toString(), val.get("enm"));
+ }
+ }
+
+ assertTrue(keys.containsAll(Arrays.asList(1, 2, 3)));
+ }
+
/** */
@Test
public void testCacheScanLimit() {
@@ -2378,9 +2533,27 @@ public class GridCommandHandlerClusterByClassTest
extends GridCommandHandlerClus
/** */
private final int i;
+ /** */
+ private final boolean[] booleans;
+
+ /** */
+ private final char[] chars;
+
+ /** */
+ private final short[] shorts;
+
/** */
private final int[] ints;
+ /** */
+ private final long[] longs;
+
+ /** */
+ private final float[] floats;
+
+ /** */
+ private final double[] doubles;
+
/** */
private final Map<?, ?> map;
@@ -2397,9 +2570,29 @@ public class GridCommandHandlerClusterByClassTest
extends GridCommandHandlerClus
private final AccessLevel enm;
/** */
- public TestClass2(int i, int[] ints, Map<?, ?> map, String[] strArr,
Date date, List<?> list, AccessLevel enm) {
+ public TestClass2(
+ int i,
+ boolean[] booleans,
+ char[] chars,
+ short[] shorts,
+ int[] ints,
+ long[] longs,
+ float[] floats,
+ double[] doubles,
+ Map<?, ?> map,
+ String[] strArr,
+ Date date,
+ List<?> list,
+ AccessLevel enm
+ ) {
this.i = i;
+ this.booleans = booleans;
+ this.chars = chars;
+ this.shorts = shorts;
this.ints = ints;
+ this.longs = longs;
+ this.floats = floats;
+ this.doubles = doubles;
this.map = map;
this.strArr = strArr;
this.date = date;
diff --git a/modules/core/src/main/java/org/apache/ignite/dump/DumpReader.java
b/modules/core/src/main/java/org/apache/ignite/dump/DumpReader.java
index 125d9c959fe..b290b319bb1 100644
--- a/modules/core/src/main/java/org/apache/ignite/dump/DumpReader.java
+++ b/modules/core/src/main/java/org/apache/ignite/dump/DumpReader.java
@@ -37,6 +37,7 @@ import org.apache.ignite.internal.cdc.CdcMain;
import
org.apache.ignite.internal.processors.cache.persistence.snapshot.SnapshotMetadata;
import
org.apache.ignite.internal.processors.cache.persistence.snapshot.dump.Dump;
import
org.apache.ignite.internal.processors.cache.persistence.snapshot.dump.Dump.DumpedPartitionIterator;
+import
org.apache.ignite.internal.processors.cache.persistence.snapshot.dump.DumpConsumerKernalContextAware;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.internal.U;
@@ -80,7 +81,10 @@ public class DumpReader implements Runnable {
try (Dump dump = new Dump(cfg.dumpRoot(), null, cfg.keepBinary(),
cfg.keepRaw(), encryptionSpi(), log)) {
DumpConsumer cnsmr = cfg.consumer();
- cnsmr.start();
+ if (cnsmr instanceof DumpConsumerKernalContextAware)
+ ((DumpConsumerKernalContextAware)cnsmr).start(dump.context());
+ else
+ cnsmr.start();
try {
File[] files = new File(cfg.dumpRoot(),
DFLT_MARSHALLER_PATH).listFiles(BinaryUtils::notTmpFile);
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/scan/DefaultCacheScanTaskFormat.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/scan/DefaultCacheScanTaskFormat.java
index f6aa82b0fa8..d683cfbf6c9 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/scan/DefaultCacheScanTaskFormat.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/scan/DefaultCacheScanTaskFormat.java
@@ -79,15 +79,42 @@ public class DefaultCacheScanTaskFormat implements
CacheScanTaskFormat {
if (o == null)
return "null";
- if (o instanceof byte[])
+ if (o instanceof byte[]) {
return "size=" + ((byte[])o).length;
-
- if (o instanceof Byte[])
+ }
+ else if (o instanceof Byte[]) {
return "size=" + ((Byte[])o).length;
-
- if (o instanceof Object[]) {
- return "size=" + ((Object[])o).length +
- ", values=[" + S.joinToString(Arrays.asList((Object[])o), ",
", "...", 120, 0) + "]";
+ }
+ else if (o instanceof boolean[]) {
+ boolean[] arr = (boolean[])o;
+ return arrayValue(arr.length, Arrays.toString(arr));
+ }
+ else if (o instanceof char[]) {
+ char[] arr = (char[])o;
+ return arrayValue(arr.length, Arrays.toString(arr));
+ }
+ else if (o instanceof short[]) {
+ short[] arr = (short[])o;
+ return arrayValue(arr.length, Arrays.toString(arr));
+ }
+ else if (o instanceof int[]) {
+ int[] arr = (int[])o;
+ return arrayValue(arr.length, Arrays.toString(arr));
+ }
+ else if (o instanceof long[]) {
+ long[] arr = (long[])o;
+ return arrayValue(arr.length, Arrays.toString(arr));
+ }
+ else if (o instanceof float[]) {
+ float[] arr = (float[])o;
+ return arrayValue(arr.length, Arrays.toString(arr));
+ }
+ else if (o instanceof double[]) {
+ double[] arr = (double[])o;
+ return arrayValue(arr.length, Arrays.toString(arr));
+ }
+ else if (o instanceof Object[]) {
+ return arrayValue(((Object[])o).length, "[" +
S.joinToString(Arrays.asList((Object[])o), ", ", "...", 120, 0)) + "]";
}
if (o instanceof BinaryObject)
@@ -96,6 +123,11 @@ public class DefaultCacheScanTaskFormat implements
CacheScanTaskFormat {
return o.toString();
}
+ /** */
+ static String arrayValue(int length, String values) {
+ return "size=" + length + ", values=" + values;
+ }
+
/**
* Convert Binary object to string.
*
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/Dump.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/Dump.java
index c26c56f88b1..7cefa552380 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/Dump.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/Dump.java
@@ -386,6 +386,11 @@ public class Dump implements AutoCloseable {
return grpDirs[0];
}
+ /** @return Kernal context. */
+ public GridKernalContext context() {
+ return cctx;
+ }
+
/** {@inheritDoc} */
@Override public void close() throws Exception {
closeAllComponents(cctx);
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/DumpConsumerKernalContextAware.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/DumpConsumerKernalContextAware.java
new file mode 100644
index 00000000000..ec24a4921f8
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/DumpConsumerKernalContextAware.java
@@ -0,0 +1,33 @@
+/*
+ * 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.cache.persistence.snapshot.dump;
+
+import org.apache.ignite.dump.DumpConsumer;
+import org.apache.ignite.internal.GridKernalContext;
+
+/**
+ * Dump consumer that needs to use {@link GridKernalContext} must implement
this interface.
+ */
+public interface DumpConsumerKernalContextAware extends DumpConsumer {
+ /**
+ * Starts the consumer with the kernal context provided.
+ *
+ * @param ctx Kernal context.
+ */
+ void start(GridKernalContext ctx);
+}
diff --git
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/AbstractCacheDumpTest.java
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/AbstractCacheDumpTest.java
index 38bf7dfb2c0..b518de85c09 100644
---
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/AbstractCacheDumpTest.java
+++
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/AbstractCacheDumpTest.java
@@ -56,7 +56,6 @@ import
org.apache.ignite.internal.processors.cache.CacheGroupContext;
import org.apache.ignite.internal.processors.cache.GridCacheContext;
import org.apache.ignite.internal.processors.cache.StoredCacheData;
import
org.apache.ignite.internal.processors.cache.persistence.snapshot.SnapshotMetadata;
-import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.T2;
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.internal.U;
@@ -228,7 +227,9 @@ public abstract class AbstractCacheDumpTest extends
GridCommonAbstractTest {
}
/** */
- protected T2<CountDownLatch, IgniteInternalFuture<?>>
runDumpAsyncAndStopBeforeStart() throws IgniteInterruptedCheckedException {
+ protected T2<CountDownLatch, IgniteInternalFuture<?>>
runDumpAsyncAndStopBeforeStart(
+ IgniteEx srv
+ ) throws IgniteInterruptedCheckedException {
CountDownLatch latch = new CountDownLatch(1);
List<Ignite> ignites = Ignition.allGrids();
@@ -244,7 +245,7 @@ public abstract class AbstractCacheDumpTest extends
GridCommonAbstractTest {
});
}
- IgniteInternalFuture<Object> dumpFut = runAsync(() ->
createDump((IgniteEx)F.first(ignites)));
+ IgniteInternalFuture<Object> dumpFut = runAsync(() -> createDump(srv));
// Waiting while dump will be setup: task planned after change
listener set.
assertTrue(waitForCondition(() -> {
@@ -344,82 +345,7 @@ public abstract class AbstractCacheDumpTest extends
GridCommonAbstractTest {
assertEquals(nodes, nodesDirs.size());
- TestDumpConsumer cnsmr = new TestDumpConsumer() {
- final Set<Integer> keys = new HashSet<>();
-
- final Set<Long> grpParts = new HashSet<>();
-
- int dfltDumpSz;
-
- int grpDumpSz;
-
- @Override public void onCacheConfigs(Iterator<StoredCacheData>
caches) {
- super.onCacheConfigs(caches);
-
- Set<String> cachesFound = new HashSet<>();
-
- caches.forEachRemaining(data -> {
- String cacheName = data.config().getName();
-
- assertTrue(cachesFound.add(cacheName));
-
- assertEquals(cacheName, data.configuration().getName());
-
- assertFalse(data.sql());
-
- assertTrue(data.queryEntities().isEmpty());
-
- if (cacheName.startsWith("cache-"))
- assertEquals(GRP, data.configuration().getGroupName());
- else if (!cacheName.equals(DEFAULT_CACHE_NAME))
- throw new IgniteException("Unknown cache");
- });
-
- assertEquals(expectedFoundCaches, cachesFound);
- }
-
- @Override public void onPartition(int grp, int part,
Iterator<DumpEntry> iter) {
- if (onlyPrimary)
- assertTrue(grpParts.add(toLong(grp, part)));
-
- if (grp == CU.cacheId(DEFAULT_CACHE_NAME)) {
- while (iter.hasNext()) {
- DumpEntry e = iter.next();
-
- checkDefaultCacheEntry(e);
-
- keys.add((Integer)e.key());
-
- dfltDumpSz++;
- }
- }
- else {
- while (iter.hasNext()) {
- DumpEntry e = iter.next();
-
- assertNotNull(e);
- assertNotNull(e.version());
- assertNull(e.version().otherClusterVersion());
-
- if (e.cacheId() == CU.cacheId(CACHE_0))
- assertEquals(USER_FACTORY.apply((Integer)e.key()),
e.value());
- else
- assertEquals(((Key)e.key()).getId() + "",
((Value)e.value()).getVal());
-
- grpDumpSz++;
- }
- }
- }
-
- @Override public void check() {
- super.check();
-
- assertEquals(expectedDfltDumpSz, dfltDumpSz);
- assertEquals(expectedGrpDumpSz, grpDumpSz);
-
- IntStream.range(0, expectedCnt).forEach(key ->
assertTrue(keys.contains(key)));
- }
- };
+ TestDumpConsumer cnsmr = dumpConsumer(expectedFoundCaches,
expectedDfltDumpSz, expectedGrpDumpSz, expectedCnt);
new DumpReader(
new DumpReaderConfiguration(
@@ -440,14 +366,13 @@ public abstract class AbstractCacheDumpTest extends
GridCommonAbstractTest {
}
/** */
- protected void checkDefaultCacheEntry(DumpEntry e) {
- assertNotNull(e);
-
- Integer key = (Integer)e.key();
-
- assertEquals(key, e.value());
- assertNotNull(e.version());
- assertNull(e.version().otherClusterVersion());
+ protected TestDumpConsumer dumpConsumer(
+ Set<String> expectedFoundCaches,
+ int expectedDfltDumpSz,
+ int expectedGrpDumpSz,
+ int expectedCnt
+ ) {
+ return new TestDumpConsumerImpl(expectedFoundCaches,
expectedDfltDumpSz, expectedGrpDumpSz, expectedCnt);
}
/** */
@@ -577,6 +502,122 @@ public abstract class AbstractCacheDumpTest extends
GridCommonAbstractTest {
return encSpi;
}
+ /** */
+ public class TestDumpConsumerImpl extends TestDumpConsumer {
+ /** */
+ private final Set<String> expectedFoundCaches;
+
+ /** */
+ private final int expectedDfltDumpSz;
+
+ /** */
+ private final int expectedGrpDumpSz;
+
+ /** */
+ private final int expectedCnt;
+
+ /** */
+ final Set<Integer> keys = new HashSet<>();
+
+ /** */
+ final Set<Long> grpParts = new HashSet<>();
+
+ /** */
+ int dfltDumpSz;
+
+ /** */
+ int grpDumpSz;
+
+ /** */
+ protected TestDumpConsumerImpl(Set<String> expectedFoundCaches, int
expectedDfltDumpSz, int expectedGrpDumpSz, int expectedCnt) {
+ this.expectedFoundCaches = expectedFoundCaches;
+ this.expectedDfltDumpSz = expectedDfltDumpSz;
+ this.expectedGrpDumpSz = expectedGrpDumpSz;
+ this.expectedCnt = expectedCnt;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onCacheConfigs(Iterator<StoredCacheData> caches)
{
+ super.onCacheConfigs(caches);
+
+ Set<String> cachesFound = new HashSet<>();
+
+ caches.forEachRemaining(data -> {
+ String cacheName = data.config().getName();
+
+ assertTrue(cachesFound.add(cacheName));
+
+ assertEquals(cacheName, data.configuration().getName());
+
+ assertFalse(data.sql());
+
+ assertTrue(data.queryEntities().isEmpty());
+
+ if (cacheName.startsWith("cache-"))
+ assertEquals(GRP, data.configuration().getGroupName());
+ else if (!cacheName.equals(DEFAULT_CACHE_NAME))
+ throw new IgniteException("Unknown cache");
+ });
+
+ assertEquals(expectedFoundCaches, cachesFound);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onPartition(int grp, int part,
Iterator<DumpEntry> iter) {
+ if (onlyPrimary)
+ assertTrue(grpParts.add(toLong(grp, part)));
+
+ if (grp == CU.cacheId(DEFAULT_CACHE_NAME)) {
+ while (iter.hasNext()) {
+ DumpEntry e = iter.next();
+
+ checkDefaultCacheEntry(e);
+
+ keys.add((Integer)e.key());
+
+ dfltDumpSz++;
+ }
+ }
+ else {
+ while (iter.hasNext()) {
+ DumpEntry e = iter.next();
+
+ assertNotNull(e);
+ assertNotNull(e.version());
+ assertNull(e.version().otherClusterVersion());
+
+ if (e.cacheId() == CU.cacheId(CACHE_0))
+ assertEquals(USER_FACTORY.apply((Integer)e.key()),
e.value());
+ else
+ assertEquals(((Key)e.key()).getId() + "",
((Value)e.value()).getVal());
+
+ grpDumpSz++;
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public void check() {
+ super.check();
+
+ assertEquals(expectedDfltDumpSz, dfltDumpSz);
+ assertEquals(expectedGrpDumpSz, grpDumpSz);
+
+ IntStream.range(0, expectedCnt).forEach(key ->
assertTrue(keys.contains(key)));
+ }
+
+ /** */
+ protected void checkDefaultCacheEntry(DumpEntry e) {
+ assertNotNull(e);
+
+ Integer key = (Integer)e.key();
+
+ assertEquals(key, e.value());
+ assertNotNull(e.version());
+ assertNull(e.version().otherClusterVersion());
+ }
+ }
+
/** */
public abstract static class TestDumpConsumer implements DumpConsumer {
/** */
diff --git
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/IgniteCacheDumpSelfTest.java
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/IgniteCacheDumpSelfTest.java
index 0a44519c776..665b993d92e 100644
---
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/IgniteCacheDumpSelfTest.java
+++
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/IgniteCacheDumpSelfTest.java
@@ -25,6 +25,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -618,7 +619,7 @@ public class IgniteCacheDumpSelfTest extends
AbstractCacheDumpTest {
}
});
- T2<CountDownLatch, IgniteInternalFuture<?>> latchAndFut =
runDumpAsyncAndStopBeforeStart();
+ T2<CountDownLatch, IgniteInternalFuture<?>> latchAndFut =
runDumpAsyncAndStopBeforeStart(ign);
cache.put(keyToFail, "test string");
@@ -647,7 +648,7 @@ public class IgniteCacheDumpSelfTest extends
AbstractCacheDumpTest {
private void doTestDumpWithExpiry() throws Exception {
IgniteEx ign = startGridAndFillCaches();
- T2<CountDownLatch, IgniteInternalFuture<?>> latchAndFut =
runDumpAsyncAndStopBeforeStart();
+ T2<CountDownLatch, IgniteInternalFuture<?>> latchAndFut =
runDumpAsyncAndStopBeforeStart(ign);
Thread.sleep(TTL);
@@ -677,7 +678,7 @@ public class IgniteCacheDumpSelfTest extends
AbstractCacheDumpTest {
private void doTestConcurrentOperations(Consumer<IgniteEx> op) throws
Exception {
IgniteEx ign = startGridAndFillCaches();
- T2<CountDownLatch, IgniteInternalFuture<?>> latchAndFut =
runDumpAsyncAndStopBeforeStart();
+ T2<CountDownLatch, IgniteInternalFuture<?>> latchAndFut =
runDumpAsyncAndStopBeforeStart(ign);
// This operations will be catched by change listeners. Old value must
be stored in dump.
op.accept(ign);
@@ -707,14 +708,24 @@ public class IgniteCacheDumpSelfTest extends
AbstractCacheDumpTest {
}
/** {@inheritDoc} */
- @Override protected void checkDefaultCacheEntry(DumpEntry e) {
- super.checkDefaultCacheEntry(e);
-
- if (explicitTtl != null) {
- assertTrue("Expire time must be set", e.expireTime() != 0);
- assertTrue("Expire time must be in past",
System.currentTimeMillis() >= e.expireTime());
- assertTrue("Expire time must be set during test run",
System.currentTimeMillis() - getTestTimeout() < e.expireTime());
- }
+ @Override protected TestDumpConsumer dumpConsumer(
+ Set<String> expectedFoundCaches,
+ int expectedDfltDumpSz,
+ int expectedGrpDumpSz,
+ int expectedCnt
+ ) {
+ return new TestDumpConsumerImpl(expectedFoundCaches,
expectedDfltDumpSz, expectedGrpDumpSz, expectedCnt) {
+ /** {@inheritDoc} */
+ @Override protected void checkDefaultCacheEntry(DumpEntry e) {
+ super.checkDefaultCacheEntry(e);
+
+ if (explicitTtl != null) {
+ assertTrue("Expire time must be set", e.expireTime() != 0);
+ assertTrue("Expire time must be in past",
System.currentTimeMillis() >= e.expireTime());
+ assertTrue("Expire time must be set during test run",
System.currentTimeMillis() - getTestTimeout() < e.expireTime());
+ }
+ }
+ };
}
/** */
diff --git a/modules/json/README.txt b/modules/json/README.txt
new file mode 100644
index 00000000000..5eae369e8b3
--- /dev/null
+++ b/modules/json/README.txt
@@ -0,0 +1,4 @@
+Apache Ignite Json Module
+------------------------
+
+Apache Ignite json module provides classes and configurations for integration
with external tools via json format.
\ No newline at end of file
diff --git a/modules/rest-http/pom.xml b/modules/json/pom.xml
similarity index 58%
copy from modules/rest-http/pom.xml
copy to modules/json/pom.xml
index f326f428621..4cf92c4b842 100644
--- a/modules/rest-http/pom.xml
+++ b/modules/json/pom.xml
@@ -30,17 +30,10 @@
<relativePath>../../parent-internal/pom.xml</relativePath>
</parent>
- <artifactId>ignite-rest-http</artifactId>
+ <artifactId>ignite-json</artifactId>
<url>http://ignite.apache.org</url>
- <properties>
- <osgi.export.package>
- org.apache.ignite.internal.processors.rest.protocols.http.jetty,
- {local-packages}
- </osgi.export.package>
- </properties>
-
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
@@ -48,51 +41,9 @@
</dependency>
<dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <version>${commons.lang.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-continuation</artifactId>
- <version>${jetty.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-http</artifactId>
- <version>${jetty.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-io</artifactId>
- <version>${jetty.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-server</artifactId>
- <version>${jetty.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-util</artifactId>
- <version>${jetty.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-xml</artifactId>
- <version>${jetty.version}</version>
- </dependency>
-
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>javax.servlet-api</artifactId>
- <version>3.1.0</version>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ignite-spring</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
@@ -131,26 +82,6 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
-
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>ignite-tools</artifactId>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-beans</artifactId>
- <version>${spring.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context</artifactId>
- <version>${spring.version}</version>
- <scope>test</scope>
- </dependency>
</dependencies>
<build>
diff --git
a/modules/json/src/main/java/org/apache/ignite/dump/JsonDumpConsumer.java
b/modules/json/src/main/java/org/apache/ignite/dump/JsonDumpConsumer.java
new file mode 100644
index 00000000000..0bf4fe28906
--- /dev/null
+++ b/modules/json/src/main/java/org/apache/ignite/dump/JsonDumpConsumer.java
@@ -0,0 +1,151 @@
+/*
+ * 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.dump;
+
+import java.io.IOException;
+import java.util.Iterator;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.binary.BinaryType;
+import org.apache.ignite.cache.CacheEntryVersion;
+import org.apache.ignite.cdc.TypeMapping;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.jackson.IgniteObjectMapper;
+import org.apache.ignite.internal.processors.cache.StoredCacheData;
+import
org.apache.ignite.internal.processors.cache.persistence.snapshot.dump.DumpConsumerKernalContextAware;
+
+/**
+ * Dump consumer that outputs entries in json format.
+ */
+public class JsonDumpConsumer implements DumpConsumerKernalContextAware {
+ /** Ignite specific object mapper. */
+ private IgniteObjectMapper mapper;
+
+ /** {@inheritDoc} */
+ @Override public void start(GridKernalContext ctx) {
+ mapper = new IgniteObjectMapper(ctx);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onMappings(Iterator<TypeMapping> mappings) {
+ // No-op.
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onTypes(Iterator<BinaryType> types) {
+ // No-op.
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onCacheConfigs(Iterator<StoredCacheData> caches) {
+ // No-op.
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onPartition(int grp, int part, Iterator<DumpEntry>
data) {
+ data.forEachRemaining(entry -> {
+ try {
+ System.out.println(mapper.writeValueAsString(new
PrintableDumpEntry(entry)));
+ }
+ catch (IOException e) {
+ throw new IgniteException(e);
+ }
+ });
+ }
+
+ /** {@inheritDoc} */
+ @Override public void stop() {
+ // No-op.
+ }
+
+ /** {@inheritDoc} */
+ @Override public void start() {
+ // No-op.
+ }
+
+ /** */
+ private static class PrintableDumpEntry {
+ /** */
+ private final DumpEntry e;
+
+ /** */
+ public PrintableDumpEntry(DumpEntry e) {
+ this.e = e;
+ }
+
+ /** @see DumpEntry#cacheId() */
+ public int getCacheId() {
+ return e.cacheId();
+ }
+
+ /** @see DumpEntry#expireTime() */
+ public long getExpireTime() {
+ return e.expireTime();
+ }
+
+ /** @see DumpEntry#version() */
+ public PrintableCacheEntryVersion getVersion() {
+ return new PrintableCacheEntryVersion(e.version());
+ }
+
+ /** @see DumpEntry#key() */
+ public Object getKey() {
+ return e.key();
+ }
+
+ /** @see DumpEntry#value() */
+ public Object getValue() {
+ return e.value();
+ }
+ }
+
+ /** */
+ private static class PrintableCacheEntryVersion {
+ /** */
+ private final CacheEntryVersion v;
+
+ /** */
+ public PrintableCacheEntryVersion(CacheEntryVersion v) {
+ this.v = v;
+ }
+
+ /** @see CacheEntryVersion#order() */
+ public long getOrder() {
+ return v.order();
+ }
+
+ /** @see CacheEntryVersion#nodeOrder() */
+ public int getNodeOrder() {
+ return v.nodeOrder();
+ }
+
+ /** @see CacheEntryVersion#clusterId() */
+ public byte getClusterId() {
+ return v.clusterId();
+ }
+
+ /** @see CacheEntryVersion#topologyVersion() */
+ public int getTopologyVersion() {
+ return v.topologyVersion();
+ }
+
+ /** @see CacheEntryVersion#otherClusterVersion() */
+ public PrintableCacheEntryVersion otherClusterVersion() {
+ return new PrintableCacheEntryVersion(v.otherClusterVersion());
+ }
+ }
+}
diff --git
a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/IgniteBinaryObjectJsonDeserializer.java
b/modules/json/src/main/java/org/apache/ignite/internal/jackson/IgniteBinaryObjectJsonDeserializer.java
similarity index 98%
rename from
modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/IgniteBinaryObjectJsonDeserializer.java
rename to
modules/json/src/main/java/org/apache/ignite/internal/jackson/IgniteBinaryObjectJsonDeserializer.java
index a6d0d6fbe09..08723facfa7 100644
---
a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/IgniteBinaryObjectJsonDeserializer.java
+++
b/modules/json/src/main/java/org/apache/ignite/internal/jackson/IgniteBinaryObjectJsonDeserializer.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.processors.rest.protocols.http.jetty;
+package org.apache.ignite.internal.jackson;
import java.io.IOException;
import java.util.Collections;
diff --git
a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyObjectMapper.java
b/modules/json/src/main/java/org/apache/ignite/internal/jackson/IgniteObjectMapper.java
similarity index 96%
rename from
modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyObjectMapper.java
rename to
modules/json/src/main/java/org/apache/ignite/internal/jackson/IgniteObjectMapper.java
index fc3966a8548..804f5159532 100644
---
a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyObjectMapper.java
+++
b/modules/json/src/main/java/org/apache/ignite/internal/jackson/IgniteObjectMapper.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.processors.rest.protocols.http.jetty;
+package org.apache.ignite.internal.jackson;
import java.io.IOException;
import java.sql.Date;
@@ -59,21 +59,24 @@ import org.apache.ignite.lang.IgniteUuid;
/**
* Custom object mapper for HTTP REST API.
*/
-public class GridJettyObjectMapper extends ObjectMapper {
+public class IgniteObjectMapper extends ObjectMapper {
+ /** Date format. */
+ public static final DateFormat DATE_FORMAT =
DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT,
Locale.US);
+
/**
* Default constructor.
*/
- public GridJettyObjectMapper() {
+ public IgniteObjectMapper() {
this(null);
}
/**
* @param ctx Defines a kernal context to enable deserialization into the
Ignite binary object.
*/
- GridJettyObjectMapper(GridKernalContext ctx) {
+ public IgniteObjectMapper(GridKernalContext ctx) {
super(null, new CustomSerializerProvider(), null);
- setDateFormat(DateFormat.getDateTimeInstance(DateFormat.DEFAULT,
DateFormat.DEFAULT, Locale.US));
+ setDateFormat(DATE_FORMAT);
SimpleModule module = new SimpleModule();
@@ -98,7 +101,8 @@ public class GridJettyObjectMapper extends ObjectMapper {
IgnitePredicate<String> clsFilter =
ctx.marshallerContext().classNameFilter();
- setDefaultTyping(new
RestrictedTypeResolverBuilder(clsFilter).init(JsonTypeInfo.Id.CLASS, null));
+ if (clsFilter != null)
+ setDefaultTyping(new
RestrictedTypeResolverBuilder(clsFilter).init(JsonTypeInfo.Id.CLASS, null));
}
configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
diff --git
a/modules/json/src/main/java/org/apache/ignite/internal/management/cache/scan/JsonCacheScanTaskFormat.java
b/modules/json/src/main/java/org/apache/ignite/internal/management/cache/scan/JsonCacheScanTaskFormat.java
new file mode 100644
index 00000000000..34443987f74
--- /dev/null
+++
b/modules/json/src/main/java/org/apache/ignite/internal/management/cache/scan/JsonCacheScanTaskFormat.java
@@ -0,0 +1,57 @@
+/*
+ * 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.management.cache.scan;
+
+import java.util.Collections;
+import java.util.List;
+import javax.cache.Cache;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.jackson.IgniteObjectMapper;
+
+/**
+ * This format prints cache objects in json format.
+ */
+public class JsonCacheScanTaskFormat implements CacheScanTaskFormat {
+ /** */
+ public static final String NAME = "json";
+
+ /** */
+ private final ObjectMapper mapper = new IgniteObjectMapper();
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return NAME;
+ }
+
+ /** {@inheritDoc} */
+ @Override public List<String> titles(Cache.Entry<Object, Object> first) {
+ return Collections.singletonList("data");
+ }
+
+ /** {@inheritDoc} */
+ @Override public List<?> row(Cache.Entry<Object, Object> e) {
+ try {
+ return Collections.singletonList(mapper.writeValueAsString(e));
+ }
+ catch (JsonProcessingException ex) {
+ throw new IgniteException(ex);
+ }
+ }
+}
diff --git
a/modules/json/src/main/resources/META-INF/services/org.apache.ignite.internal.management.cache.scan.CacheScanTaskFormat
b/modules/json/src/main/resources/META-INF/services/org.apache.ignite.internal.management.cache.scan.CacheScanTaskFormat
new file mode 100644
index 00000000000..cfbbc776498
--- /dev/null
+++
b/modules/json/src/main/resources/META-INF/services/org.apache.ignite.internal.management.cache.scan.CacheScanTaskFormat
@@ -0,0 +1 @@
+org.apache.ignite.internal.management.cache.scan.JsonCacheScanTaskFormat
\ No newline at end of file
diff --git
a/modules/json/src/test/java/org/apache/ignite/dump/IgniteJsonSuite.java
b/modules/json/src/test/java/org/apache/ignite/dump/IgniteJsonSuite.java
new file mode 100644
index 00000000000..b82cbe8ef2b
--- /dev/null
+++ b/modules/json/src/test/java/org/apache/ignite/dump/IgniteJsonSuite.java
@@ -0,0 +1,31 @@
+/*
+ * 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.dump;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+/**
+ * Json test suite.
+ */
+@RunWith(Suite.class)
[email protected]({
+ JsonDumpConsumerTest.class
+})
+public class IgniteJsonSuite {
+}
diff --git
a/modules/json/src/test/java/org/apache/ignite/dump/JsonDumpConsumerTest.java
b/modules/json/src/test/java/org/apache/ignite/dump/JsonDumpConsumerTest.java
new file mode 100644
index 00000000000..06aff788042
--- /dev/null
+++
b/modules/json/src/test/java/org/apache/ignite/dump/JsonDumpConsumerTest.java
@@ -0,0 +1,194 @@
+/*
+ * 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.dump;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.Set;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.ignite.cache.CacheEntryVersion;
+import org.apache.ignite.internal.GridKernalContext;
+import
org.apache.ignite.internal.processors.cache.persistence.snapshot.dump.DumpConsumerKernalContextAware;
+import
org.apache.ignite.internal.processors.cache.persistence.snapshot.dump.IgniteCacheDumpSelfTest;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.platform.model.ACL;
+import org.apache.ignite.platform.model.AccessLevel;
+import org.apache.ignite.platform.model.Key;
+import org.apache.ignite.platform.model.Role;
+import org.apache.ignite.platform.model.User;
+import org.apache.ignite.platform.model.Value;
+import org.jetbrains.annotations.NotNull;
+
+/** */
+public class JsonDumpConsumerTest extends IgniteCacheDumpSelfTest {
+ /** {@inheritDoc} */
+ @Override protected TestDumpConsumer dumpConsumer(
+ Set<String> expectedFoundCaches,
+ int expectedDfltDumpSz,
+ int expectedGrpDumpSz,
+ int expectedCnt
+ ) {
+ return new TestJsonDumpConsumer(expectedFoundCaches,
expectedDfltDumpSz, expectedGrpDumpSz, expectedCnt);
+ }
+
+ /** */
+ public class TestJsonDumpConsumer extends TestDumpConsumerImpl implements
DumpConsumerKernalContextAware {
+ /** */
+ private final JsonDumpConsumer jsonDumpConsumer = new
JsonDumpConsumer();
+
+ /** */
+ protected TestJsonDumpConsumer(Set<String> expectedFoundCaches, int
expectedDfltDumpSz, int expectedGrpDumpSz, int expectedCnt) {
+ super(expectedFoundCaches, expectedDfltDumpSz, expectedGrpDumpSz,
expectedCnt);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void start(GridKernalContext ctx) {
+ jsonDumpConsumer.start(ctx);
+ start();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onPartition(int grp, int part,
Iterator<DumpEntry> data) {
+ ByteArrayOutputStream testOut = new ByteArrayOutputStream((int)(16
* U.MB));
+
+ PrintStream out = System.out;
+
+ System.setOut(new PrintStream(testOut));
+
+ // Parse entries from System.out.
+ Scanner sc;
+
+ try {
+ // Print out all entries to System.out.
+ jsonDumpConsumer.onPartition(grp, part, data);
+
+ sc = new Scanner(testOut.toString());
+ }
+ finally {
+ System.setOut(out);
+ }
+
+ TypeReference<HashMap<String, Object>> typeRef = new
TypeReference<HashMap<String, Object>>() {
+ // No-op.
+ };
+
+ ObjectMapper mapper = new ObjectMapper();
+
+ super.onPartition(grp, part, new Iterator<DumpEntry>() {
+ @Override public boolean hasNext() {
+ return sc.hasNextLine();
+ }
+
+ @Override public DumpEntry next() {
+ try {
+ Map<String, Object> entryFromJson =
mapper.readValue(sc.nextLine(), typeRef);
+
+ return new DumpEntry() {
+ @Override public int cacheId() {
+ return
Integer.parseInt(entryFromJson.get("cacheId").toString());
+ }
+
+ @Override public long expireTime() {
+ return
Long.parseLong(entryFromJson.get("expireTime").toString());
+ }
+
+ @Override public CacheEntryVersion version() {
+ return
JsonDumpConsumerTest.version((Map<String, Object>)entryFromJson.get("version"));
+ }
+
+ @Override public Object key() {
+ if (cacheId() ==
CU.cacheId(DEFAULT_CACHE_NAME) || cacheId() == CU.cacheId(CACHE_0))
+ return
Integer.parseInt(entryFromJson.get("key").toString());
+
+ Map<String, Object> key = (Map<String,
Object>)entryFromJson.get("key");
+
+ return new
Key(Long.parseLong(key.get("id").toString()));
+ }
+
+ @Override public Object value() {
+ if (cacheId() ==
CU.cacheId(DEFAULT_CACHE_NAME))
+ return
Integer.valueOf(entryFromJson.get("value").toString());
+ else if (cacheId() == CU.cacheId(CACHE_0)) {
+ Map<String, Object> val = (Map<String,
Object>)entryFromJson.get("value");
+ Map<String, Object> role = (Map<String,
Object>)val.get("role");
+
+ return new User(
+ (Integer)val.get("id"),
+ ACL.valueOf(val.get("acl").toString()),
+ new Role(
+ role.get("name").toString(),
+
AccessLevel.valueOf(role.get("accessLevel").toString())
+ )
+ );
+ }
+ else if (cacheId() == CU.cacheId(CACHE_1)) {
+ Map<String, Object> val = (Map<String,
Object>)entryFromJson.get("value");
+
+ return new
Value(val.get("val").toString());
+ }
+
+ throw new IllegalArgumentException("Unknown
cache: " + cacheId());
+ }
+ };
+ }
+ catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+ }
+
+ /** */
+ private static CacheEntryVersion version(Map<String, Object> version) {
+ return new CacheEntryVersion() {
+ @Override public long order() {
+ return Long.parseLong(version.get("order").toString());
+ }
+
+ @Override public int nodeOrder() {
+ return Integer.parseInt(version.get("nodeOrder").toString());
+ }
+
+ @Override public byte clusterId() {
+ return Byte.parseByte(version.get("clusterId").toString());
+ }
+
+ @Override public int topologyVersion() {
+ return
Integer.parseInt(version.get("topologyVersion").toString());
+ }
+
+ @Override public CacheEntryVersion otherClusterVersion() {
+ return version.containsKey("otherClusterVersion")
+ ? version((Map<String,
Object>)version.get("otherClusterVersion"))
+ : null;
+ }
+
+ @Override public int compareTo(@NotNull CacheEntryVersion o) {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+}
diff --git a/modules/rest-http/pom.xml b/modules/rest-http/pom.xml
index f326f428621..2eb640b145b 100644
--- a/modules/rest-http/pom.xml
+++ b/modules/rest-http/pom.xml
@@ -47,6 +47,11 @@
<artifactId>ignite-core</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ignite-json</artifactId>
+ </dependency>
+
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
@@ -95,24 +100,6 @@
<version>3.1.0</version>
</dependency>
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-core</artifactId>
- <version>${jackson.version}</version>
- </dependency>
-
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-annotations</artifactId>
- <version>${jackson.version}</version>
- </dependency>
-
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-databind</artifactId>
- <version>${jackson.version}</version>
- </dependency>
-
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
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 ba09e7ff04b..e9550d7a358 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,6 +51,8 @@ import org.apache.ignite.binary.BinaryObject;
import org.apache.ignite.cache.CacheWriteSynchronizationMode;
import org.apache.ignite.cluster.ClusterState;
import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.jackson.IgniteBinaryObjectJsonDeserializer;
+import org.apache.ignite.internal.jackson.IgniteObjectMapper;
import org.apache.ignite.internal.processors.cache.CacheConfigurationOverride;
import org.apache.ignite.internal.processors.rest.GridRestCommand;
import org.apache.ignite.internal.processors.rest.GridRestProtocolHandler;
@@ -172,7 +174,7 @@ public class GridJettyRestHandler extends AbstractHandler {
this.hnd = hnd;
this.authChecker = authChecker;
this.log = ctx.log(getClass());
- this.jsonMapper = new GridJettyObjectMapper(ctx);
+ this.jsonMapper = new IgniteObjectMapper(ctx);
// Init default page and favicon.
try {
diff --git a/pom.xml b/pom.xml
index de4d928f2dc..91bdcac129f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,6 +52,7 @@
<module>modules/web</module>
<module>modules/urideploy</module>
<module>modules/indexing</module>
+ <module>modules/json</module>
<module>modules/rest-http</module>
<module>modules/jta</module>
<module>modules/log4j2</module>