blob: 5559e6005f542460aeb0a476280f0f5b6f5bcf47 [file] [log] [blame]
/*
* 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.geode.pdx;
import static org.apache.geode.distributed.ConfigurationProperties.DISTRIBUTED_SYSTEM_ID;
import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Properties;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.cache.AttributesFactory;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.Scope;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientCacheFactory;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.apache.geode.cache.server.CacheServer;
import org.apache.geode.internal.Assert;
import org.apache.geode.internal.AvailablePortHelper;
import org.apache.geode.internal.cache.GemFireCacheImpl;
import org.apache.geode.pdx.internal.json.PdxToJSON;
import org.apache.geode.test.dunit.Host;
import org.apache.geode.test.dunit.NetworkUtils;
import org.apache.geode.test.dunit.SerializableCallable;
import org.apache.geode.test.dunit.VM;
import org.apache.geode.test.dunit.cache.internal.JUnit4CacheTestCase;
import org.apache.geode.test.junit.categories.RestAPITest;
import org.apache.geode.test.util.ResourceUtils;
@Category({RestAPITest.class})
public class JSONPdxClientServerDUnitTest extends JUnit4CacheTestCase {
@Override
public final void preTearDownCacheTestCase() {
// this test creates client caches in some VMs and so
// breaks the contract of CacheTestCase to hold caches in
// that class's "cache" instance variable
disconnectAllFromDS();
}
@Test
public void testSimplePut() {
Host host = Host.getHost(0);
VM vm0 = host.getVM(0);
VM vm1 = host.getVM(1);
VM vm2 = host.getVM(2);
VM vm3 = host.getVM(3);
createServerRegion(vm0);
int port = createServerRegion(vm3);
createClientRegion(vm1, port);
createClientRegion(vm2, port);
vm1.invoke(new SerializableCallable() {
@Override
public Object call() throws Exception {
JSONAllStringTest();
return null;
}
});
vm2.invoke(new SerializableCallable() {
@Override
public Object call() throws Exception {
JSONAllByteArrayTest();
return null;
}
});
}
@Test
public void testSimplePutWithSortedJSONField() {
Host host = Host.getHost(0);
VM vm0 = host.getVM(0);
VM vm1 = host.getVM(1);
VM vm2 = host.getVM(2);
VM vm3 = host.getVM(3);
createServerRegion(vm0);
int port = createServerRegion(vm3);
createClientRegion(vm1, port);
createClientRegion(vm2, port);
vm1.invoke(new SerializableCallable() {
@Override
public Object call() throws Exception {
try {
System.setProperty(JSONFormatter.SORT_JSON_FIELD_NAMES_PROPERTY, "true");
JSONAllStringTest();
} finally {
System.setProperty(JSONFormatter.SORT_JSON_FIELD_NAMES_PROPERTY, "false");
}
return null;
}
});
vm2.invoke(new SerializableCallable() {
@Override
public Object call() throws Exception {
try {
System.setProperty(JSONFormatter.SORT_JSON_FIELD_NAMES_PROPERTY, "true");
JSONAllByteArrayTest();
} finally {
System.setProperty(JSONFormatter.SORT_JSON_FIELD_NAMES_PROPERTY, "false");
}
return null;
}
});
}
// this is for unquote fielnames in json string
@Test
public void testSimplePut2() {
Host host = Host.getHost(0);
VM vm0 = host.getVM(0);
VM vm1 = host.getVM(1);
VM vm2 = host.getVM(2);
VM vm3 = host.getVM(3);
createServerRegion(vm0);
int port = createServerRegion(vm3);
createClientRegion(vm1, port);
createClientRegion(vm2, port);
vm1.invoke(new SerializableCallable() {
@Override
public Object call() throws Exception {
JSONUnQuoteFields();
return null;
}
});
}
@Test
public void testPdxInstanceAndJSONConversion() {
Host host = Host.getHost(0);
VM vm0 = host.getVM(0);
VM vm1 = host.getVM(1);
VM vm2 = host.getVM(2);
VM vm3 = host.getVM(3);
createServerRegion(vm0, true);
int port = createServerRegion(vm3, true);
createClientRegion(vm1, port, true);
createClientRegion(vm2, port, true);
vm1.invoke(new SerializableCallable() {
@Override
public Object call() throws Exception {
VerifyPdxInstanceAndJsonConversion();
return null;
}
});
}
public void VerifyPdxInstanceAndJsonConversion() throws Exception {
Region region = getRootRegion("testSimplePdx");
// Create Object and initialize its members.
TestObjectForJSONFormatter testObject = new TestObjectForJSONFormatter();
testObject.defaultInitialization();
// put the object into cache.
region.put("101", testObject);
// Get the object as PdxInstance
Object result = region.get("101");
assertTrue(result instanceof PdxInstance);
PdxInstance pi = (PdxInstance) result;
String json = JSONFormatter.toJSON(pi);
JSONFormatVerifyUtility.verifyJsonWithJavaObject(json, testObject);
// TestCase-2 : Validate Java-->JSON-->PdxInstance --> Java Mapping
TestObjectForJSONFormatter actualTestObject = new TestObjectForJSONFormatter();
actualTestObject.defaultInitialization();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setDateFormat(new SimpleDateFormat("MM/dd/yyyy"));
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
validateReceivedJSON(region, actualTestObject, objectMapper);
}
private void validateReceivedJSON(Region region, TestObjectForJSONFormatter actualTestObject,
ObjectMapper objectMapper) throws Exception {
// 1. get the json from the object using Jackson Object Mapper
String json = objectMapper.writeValueAsString(actualTestObject);
String jsonWithClassType = actualTestObject.addClassTypeToJson(json);
// 2. convert json into the PdxInstance and put it into the region
PdxInstance pi = JSONFormatter.fromJSON(jsonWithClassType);
region.put("201", pi);
// 3. get the value on key "201" and validate PdxInstance.getObject() API.
Object receivedObject = region.get("201");
assertTrue(receivedObject instanceof PdxInstance);
PdxInstance receivedPdxInstance = (PdxInstance) receivedObject;
// 4. get the actualType testObject from the pdxInstance and compare it with
// actualTestObject
Object getObj = receivedPdxInstance.getObject();
assertTrue(getObj instanceof TestObjectForJSONFormatter);
TestObjectForJSONFormatter receivedTestObject = (TestObjectForJSONFormatter) getObj;
assertEquals(actualTestObject, receivedTestObject);
}
String getJSONDir(String file) {
String path = ResourceUtils.getResource(getClass(), file).getPath();
return new File(path).getParent();
}
public void JSONUnQuoteFields() {
System.setProperty("pdxToJson.unqouteFieldNames", "true");
PdxToJSON.PDXTOJJSON_UNQUOTEFIELDNAMES = true;
String jsonStringsDir =
getJSONDir("/org/apache/geode/pdx/jsonStrings/unquoteJsonStrings/json1.txt");
JSONAllStringTest(jsonStringsDir);
PdxToJSON.PDXTOJJSON_UNQUOTEFIELDNAMES = false;
}
public void JSONAllStringTest() {
String jsonStringsDir = getJSONDir("jsonStrings/json1.txt");
JSONAllStringTest(jsonStringsDir);
}
public void JSONAllStringTest(String dirname) {
JSONData[] allJsons = loadAllJSON(dirname);
int i = 0;
for (JSONData jsonData : allJsons) {
if (jsonData != null) {
i++;
VerifyJSONString(jsonData);
}
}
Assert.assertTrue(i >= 1, "Number of files should be more than 10 : " + i);
}
public void JSONAllByteArrayTest() {
String jsonStringsDir = getJSONDir("jsonStrings/json1.txt");
JSONData[] allJsons = loadAllJSON(jsonStringsDir);
int i = 0;
for (JSONData jsonData : allJsons) {
if (jsonData != null) {
i++;
VerifyJSONByteArray(jsonData);
}
}
Assert.assertTrue(i > 10, "Number of files should be more than 10");
}
static class JSONData {
String jsonFileName;
byte[] jsonByteArray;
public JSONData(String fn, byte[] js) {
jsonFileName = fn;
jsonByteArray = js;
}
public String getFileName() {
return jsonFileName;
}
public String getJsonString() {
return new String(jsonByteArray);
}
public byte[] getJsonByteArray() {
return jsonByteArray;
}
}
public void VerifyJSONString(JSONData jd) {
Region r = getRootRegion("testSimplePdx");
PdxInstance pdx = JSONFormatter.fromJSON(jd.getJsonString());
r.put(1, pdx);
pdx = (PdxInstance) r.get(1);
String getJsonString = JSONFormatter.toJSON(pdx);
String o1 = jsonParse(jd.getJsonString());
String o2 = jsonParse(getJsonString);
if (!Boolean.getBoolean(JSONFormatter.SORT_JSON_FIELD_NAMES_PROPERTY)) {
assertEquals("Json Strings are not equal " + jd.getFileName() + " "
+ Boolean.getBoolean("pdxToJson.unqouteFieldNames"), o1, o2);
} else {
// we just need to compare length as blob will be different because fields are sorted
assertEquals("Json Strings are not equal " + jd.getFileName() + " "
+ Boolean.getBoolean("pdxToJson.unqouteFieldNames"), o1.length(), o2.length());
}
PdxInstance pdx2 = JSONFormatter.fromJSON(getJsonString);
assertEquals("Pdx are not equal; json filename " + jd.getFileName(), pdx, pdx2);
}
protected static final int INT_TAB = '\t';
protected static final int INT_LF = '\n';
protected static final int INT_CR = '\r';
protected static final int INT_SPACE = 0x0020;
public String jsonParse(String jsonSting) {
byte[] ba = jsonSting.getBytes();
byte[] withoutspace = new byte[ba.length];
int i = 0;
int j = 0;
for (i = 0; i < ba.length; i++) {
int cbyte = ba[i];
if (cbyte == INT_TAB || cbyte == INT_LF || cbyte == INT_CR || cbyte == INT_SPACE)
continue;
withoutspace[j++] = ba[i];
}
return new String(withoutspace, 0, j);
}
public void VerifyJSONByteArray(JSONData jd) {
Region r = getRootRegion("testSimplePdx");
PdxInstance pdx = JSONFormatter.fromJSON(jd.getJsonByteArray());
r.put(1, pdx);
pdx = (PdxInstance) r.get(1);
byte[] jsonByteArray = JSONFormatter.toJSONByteArray(pdx);
byte[] o1 = jsonParse(jd.getJsonByteArray());
byte[] o2 = jsonParse(jsonByteArray);
compareByteArray(o1, o2);
PdxInstance pdx2 = JSONFormatter.fromJSON(jsonByteArray);
boolean pdxequals = pdx.equals(pdx2);
assertEquals("Pdx are not equal for byte array ; json filename " + jd.getFileName(), pdx, pdx2);
}
public void compareByteArray(byte[] b1, byte[] b2) {
if (b1.length != b2.length)
throw new IllegalStateException(
"Json byte array length are not equal " + b1.length + " ; " + b2.length);
if (Boolean.getBoolean(JSONFormatter.SORT_JSON_FIELD_NAMES_PROPERTY))
return;// we just need to compare length as blob will be different because fields are sorted
for (int i = 0; i < b1.length; i++) {
if (b1[i] != b2[i])
throw new IllegalStateException("Json byte arrays are not equal ");
}
}
public byte[] jsonParse(byte[] jsonBA) {
byte[] ba = jsonBA;
byte[] withoutspace = new byte[ba.length];
int i = 0;
int j = 0;
for (i = 0; i < ba.length; i++) {
int cbyte = ba[i];
if (cbyte == INT_TAB || cbyte == INT_LF || cbyte == INT_CR || cbyte == INT_SPACE)
continue;
withoutspace[j++] = ba[i];
}
byte[] retBA = new byte[j];
for (i = 0; i < j; i++) {
retBA[i] = withoutspace[i];
}
return retBA;
}
public static JSONData[] loadAllJSON(String jsondir) {
File dir = new File(jsondir);
JSONData[] JSONDatas = new JSONData[dir.list().length];
int i = 0;
for (String jsonFileName : dir.list()) {
if (!jsonFileName.contains(".txt"))
continue;
try {
byte[] ba = getBytesFromFile(dir.getAbsolutePath() + File.separator + jsonFileName);
JSONDatas[i++] = new JSONData(jsonFileName, ba);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return JSONDatas;
}
public static byte[] getBytesFromFile(String fileName) throws IOException {
File file = new File(fileName);
java.io.InputStream is = new FileInputStream(file);
// Get the size of the file
long length = file.length();
// Create the byte array to hold the data
byte[] bytes = new byte[(int) length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file " + file.getName());
}
is.close();
return bytes;
}
private void closeCache(VM vm) {
vm.invoke(new SerializableCallable() {
@Override
public Object call() throws Exception {
closeCache();
return null;
}
});
}
private int createServerRegion(VM vm) {
SerializableCallable createRegion = new SerializableCallable() {
@Override
public Object call() throws Exception {
AttributesFactory af = new AttributesFactory();
// af.setScope(Scope.DISTRIBUTED_ACK);
af.setDataPolicy(DataPolicy.PARTITION);
createRootRegion("testSimplePdx", af.create());
CacheServer server = getCache().addCacheServer();
int port = AvailablePortHelper.getRandomAvailableTCPPort();
server.setPort(port);
server.start();
return port;
}
};
return (Integer) vm.invoke(createRegion);
}
private int createServerRegion(VM vm, final boolean isPdxReadSerialized) {
SerializableCallable createRegion = new SerializableCallable() {
@Override
public Object call() throws Exception {
AttributesFactory af = new AttributesFactory();
// af.setScope(Scope.DISTRIBUTED_ACK);
af.setDataPolicy(DataPolicy.PARTITION);
createRootRegion("testSimplePdx", af.create());
((GemFireCacheImpl) getCache()).getCacheConfig().setPdxReadSerialized(isPdxReadSerialized);
CacheServer server = getCache().addCacheServer();
int port = AvailablePortHelper.getRandomAvailableTCPPort();
server.setPort(port);
server.start();
return port;
}
};
return (Integer) vm.invoke(createRegion);
}
private int createServerRegionWithPersistence(VM vm, final boolean persistentPdxRegistry) {
SerializableCallable createRegion = new SerializableCallable() {
@Override
public Object call() throws Exception {
CacheFactory cf = new CacheFactory();
if (persistentPdxRegistry) {
cf.setPdxPersistent(true).setPdxDiskStore("store");
}
//
Cache cache = getCache(cf);
cache.createDiskStoreFactory().setDiskDirs(getDiskDirs()).create("store");
AttributesFactory af = new AttributesFactory();
af.setScope(Scope.DISTRIBUTED_ACK);
af.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE);
af.setDiskStoreName("store");
createRootRegion("testSimplePdx", af.create());
CacheServer server = getCache().addCacheServer();
int port = AvailablePortHelper.getRandomAvailableTCPPort();
server.setPort(port);
server.start();
return port;
}
};
return (Integer) vm.invoke(createRegion);
}
private int createServerAccessor(VM vm) {
SerializableCallable createRegion = new SerializableCallable() {
@Override
public Object call() throws Exception {
AttributesFactory af = new AttributesFactory();
// af.setScope(Scope.DISTRIBUTED_ACK);
af.setDataPolicy(DataPolicy.EMPTY);
createRootRegion("testSimplePdx", af.create());
CacheServer server = getCache().addCacheServer();
int port = AvailablePortHelper.getRandomAvailableTCPPort();
server.setPort(port);
server.start();
return port;
}
};
return (Integer) vm.invoke(createRegion);
}
private int createLonerServerRegion(VM vm, final String regionName, final String dsId) {
SerializableCallable createRegion = new SerializableCallable() {
@Override
public Object call() throws Exception {
Properties props = new Properties();
props.setProperty(LOCATORS, "");
props.setProperty(DISTRIBUTED_SYSTEM_ID, dsId);
getSystem(props);
AttributesFactory af = new AttributesFactory();
af.setScope(Scope.DISTRIBUTED_ACK);
af.setDataPolicy(DataPolicy.REPLICATE);
createRootRegion(regionName, af.create());
CacheServer server = getCache().addCacheServer();
int port = AvailablePortHelper.getRandomAvailableTCPPort();
server.setPort(port);
server.start();
return port;
}
};
return (Integer) vm.invoke(createRegion);
}
private void createClientRegion(final VM vm, final int port) {
SerializableCallable createRegion = new SerializableCallable() {
@Override
public Object call() throws Exception {
ClientCacheFactory cf = new ClientCacheFactory();
cf.addPoolServer(NetworkUtils.getServerHostName(vm.getHost()), port);
ClientCache cache = getClientCache(cf);
cache.createClientRegionFactory(ClientRegionShortcut.PROXY).create("testSimplePdx");
return null;
}
};
vm.invoke(createRegion);
}
private void createClientRegion(final VM vm, final int port, final boolean isPdxReadSerialized) {
SerializableCallable createRegion = new SerializableCallable() {
@Override
public Object call() throws Exception {
ClientCacheFactory cf = new ClientCacheFactory();
cf.addPoolServer(NetworkUtils.getServerHostName(vm.getHost()), port);
cf.setPdxReadSerialized(isPdxReadSerialized);
ClientCache cache = getClientCache(cf);
cache.createClientRegionFactory(ClientRegionShortcut.PROXY).create("testSimplePdx");
return null;
}
};
vm.invoke(createRegion);
}
}