/*
* 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.binary;
import java.io.Serializable;
import java.util.Arrays;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.binary.BinaryObject;
import org.apache.ignite.binary.BinaryTypeConfiguration;
import org.apache.ignite.cache.CacheMode;
import org.apache.ignite.configuration.BinaryConfiguration;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.IgniteEx;
import org.apache.ignite.internal.IgniteKernal;
import org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl;
import org.apache.ignite.marshaller.Marshaller;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
/**
* Contains tests for binary enums.
*/
@SuppressWarnings("unchecked")
public class BinaryEnumsSelfTest extends GridCommonAbstractTest {
/** Cache name. */
private static String CACHE_NAME = "cache";
/** Whether to register types or not. */
private boolean register;
/** Node 1. */
private Ignite node1;
/** Node 2. */
private Ignite node2;
/** Cache 1. */
private IgniteCache cache1;
/** Cache 2. */
private IgniteCache cache2;
/** Binary cache 1. */
private IgniteCache cacheBinary1;
/** Binary cache 2. */
private IgniteCache cacheBinary2;
/** {@inheritDoc} */
@Override protected void beforeTest() throws Exception {
register = false;
}
/** {@inheritDoc} */
@Override protected void afterTest() throws Exception {
stopAllGrids();
}
/** {@inheritDoc} */
@Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
if (register) {
BinaryConfiguration bCfg = new BinaryConfiguration();
BinaryTypeConfiguration enumCfg = new BinaryTypeConfiguration(EnumType.class.getName());
enumCfg.setEnum(true);
bCfg.setTypeConfigurations(Arrays.asList(enumCfg, new BinaryTypeConfiguration(EnumHolder.class.getName())));
cfg.setBinaryConfiguration(bCfg);
}
cfg.setMarshaller(new BinaryMarshaller());
CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
ccfg.setName(CACHE_NAME);
ccfg.setCacheMode(CacheMode.PARTITIONED);
cfg.setCacheConfiguration(ccfg);
return cfg;
}
/**
* Start up routine.
*
* @throws Exception If failed.
*/
private void startUp(boolean register) throws Exception {
this.register = register;
node1 = startGrid(0);
cache1 = node1.cache(CACHE_NAME);
cacheBinary1 = cache1.withKeepBinary();
node2 = startGrid(1);
cache2 = node2.cache(CACHE_NAME);
cacheBinary2 = cache2.withKeepBinary();
awaitPartitionMapExchange();
}
/**
* Test operations on simple type which is registered in advance.
*
* @throws Exception If failed.
*/
public void testSimpleRegistered() throws Exception {
checkSimple(true);
}
/**
* Test operations on simple type which is not registered in advance.
*
* @throws Exception If failed.
*/
public void testSimpleNotRegistered() throws Exception {
checkSimple(false);
}
/**
* Test operations when enum is nested into an object (registered).
*
* @throws Exception If failed.
*/
public void testNestedRegistered() throws Exception {
checkNested(true);
}
/**
* Test operations when enum is nested into an object (not registered).
*
* @throws Exception If failed.
*/
public void testNestedNotRegistered() throws Exception {
checkNested(false);
}
/**
* Test builder operations on simple type which is registered in advance.
*
* @throws Exception If failed.
*/
public void testSimpleBuilderRegistered() throws Exception {
checkSimpleBuilder(true);
}
/**
* Test builder operations on simple type which is not registered in advance.
*
* @throws Exception If failed.
*/
public void testSimpleBuilderNotRegistered() throws Exception {
checkSimpleBuilder(false);
}
/**
* Test builder operations when enum is nested into an object (registered).
*
* @throws Exception If failed.
*/
public void testNestedBuilderRegistered() throws Exception {
checkNestedBuilder(true);
}
/**
* Test builder operations when enum is nested into an object (not registered).
*
* @throws Exception If failed.
*/
public void testNestedBuilderNotRegistered() throws Exception {
checkNestedBuilder(false);
}
/**
* @throws Exception If failed.
*/
public void testInstanceFromBytes() throws Exception {
startUp(true);
BinaryContext binCtx =
((CacheObjectBinaryProcessorImpl)((IgniteKernal)node1).context().cacheObjects()).binaryContext();
int ord = EnumType.ONE.ordinal();
String clsName = EnumType.class.getName();
checkInstanceFromBytes(binCtx, ord, GridBinaryMarshaller.UNREGISTERED_TYPE_ID, clsName);
checkInstanceFromBytes(binCtx, ord, 42, null);
}
/**
* @param binCtx Binary context.
* @param ord Enum ordinal.
* @param typeId Type Id.
* @param clsName Class name.
*/
private void checkInstanceFromBytes(BinaryContext binCtx, int ord, int typeId, String clsName)
throws IgniteCheckedException {
BinaryEnumObjectImpl srcBinEnum =new BinaryEnumObjectImpl(binCtx, typeId, clsName, ord);
Marshaller marsh = node1.configuration().getMarshaller();
byte[] bytes = marsh.marshal(srcBinEnum);
BinaryEnumObjectImpl binEnum = new BinaryEnumObjectImpl(binCtx, bytes);
assertEquals(clsName, binEnum.className());
assertEquals(typeId, binEnum.typeId());
assertEquals(ord, binEnum.enumOrdinal());
}
/**
* Check simple serialization - deserialization.
*
* @param registered If type should be registered in advance.
* @throws Exception If failed.
*/
public void checkSimple(boolean registered) throws Exception {
startUp(registered);
cache1.put(1, EnumType.ONE);
validateSimple(1, EnumType.ONE, registered);
}
/**
* Check nested serialization - deserialization.
*
* @param registered If type should be registered in advance.
* @throws Exception If failed.
*/
private void checkNested(boolean registered) throws Exception {
startUp(registered);
cache1.put(1, new EnumHolder(EnumType.ONE));
validateNested(1, EnumType.ONE, registered);
}
/**
* Check nested builder serialization - deserialization.
*
* @param registered If type should be registered in advance.
* @throws Exception If failed.
*/
private void checkNestedBuilder(boolean registered) throws Exception {
startUp(registered);
BinaryObject obj = node1.binary().builder(EnumHolder.class.getName()).setField("val", EnumType.ONE).build();
assert node1.binary().type(EnumHolder.class.getName()) != null;
assert node1.binary().type(EnumType.class.getName()) != null;
cacheBinary1.put(1, obj);
validateNested(1, EnumType.ONE, registered);
obj = (BinaryObject)cacheBinary1.get(1);
obj = node1.binary().builder(obj).setField("val", EnumType.TWO).build();
cacheBinary1.put(1, obj);
validateNested(1, EnumType.TWO, registered);
}
/**
* Validate nested object.
*
* @param key Key.
* @param val Value.
* @param registered Registered flag.
* @throws Exception If failed.
*/
private void validateNested(int key, EnumType val, boolean registered) throws Exception {
if (registered) {
EnumHolder res1 = (EnumHolder) cache1.get(key);
EnumHolder res2 = (EnumHolder) cache2.get(key);
assertEquals(val, res1.val);
assertEquals(val, res2.val);
}
BinaryObject resBinary1 = (BinaryObject)cacheBinary1.get(key);
BinaryObject resBinary2 = (BinaryObject)cacheBinary2.get(key);
validate((BinaryObject)resBinary1.field("val"), val);
validate((BinaryObject)resBinary2.field("val"), val);
}
/**
* Check simple serialization - deserialization using builder.
*
* @param registered If type should be registered in advance.
* @throws Exception If failed.
*/
public void checkSimpleBuilder(boolean registered) throws Exception {
startUp(registered);
BinaryObject binary = node1.binary().buildEnum(EnumType.class.getName(), EnumType.ONE.ordinal());
cacheBinary1.put(1, binary);
validateSimple(1, EnumType.ONE, registered);
}
/**
* Test enum array (registered).
*
* @throws Exception If failed.
*/
public void testSimpleArrayRegistered() throws Exception {
checkSimpleArray(true);
}
/**
* Test enum array (not registered).
*
* @throws Exception If failed.
*/
public void testSimpleArrayNotRegistered() throws Exception {
checkSimpleArray(false);
}
/**
* Test enum array created using builder (registered).
*
* @throws Exception If failed.
*/
public void testSimpleBuilderArrayRegistered() throws Exception {
checkSimpleBuilderArray(true);
}
/**
* Test enum array created using builder (not registered).
*
* @throws Exception If failed.
*/
public void testSimpleBuilderArrayNotRegistered() throws Exception {
checkSimpleBuilderArray(false);
}
/**
* Check arrays with builder.
*
* @param registered Registered flag.
* @throws Exception If failed.
*/
public void checkSimpleArray(boolean registered) throws Exception {
startUp(registered);
cache1.put(1, new EnumType[] { EnumType.ONE, EnumType.TWO });
validateSimpleArray(registered);
}
/**
* Check arrays with builder.
*
* @param registered Registered flag.
* @throws Exception If failed.
*/
public void checkSimpleBuilderArray(boolean registered) throws Exception {
startUp(registered);
BinaryObject binaryOne = node1.binary().buildEnum(EnumType.class.getName(), EnumType.ONE.ordinal());
BinaryObject binaryTwo = node1.binary().buildEnum(EnumType.class.getName(), EnumType.TWO.ordinal());
cacheBinary1.put(1, new BinaryObject[] { binaryOne, binaryTwo });
validateSimpleArray(registered);
}
/**
* Check ability to resolve typeId from class name.
*
* @throws Exception If failed.
*/
public void testZeroTypeId() throws Exception {
startUp(true);
final BinaryContext ctx =
((CacheObjectBinaryProcessorImpl)((IgniteEx)node1).context().cacheObjects()).binaryContext();
final BinaryObject enumObj =
new BinaryEnumObjectImpl(ctx, 0, EnumType.class.getName(), EnumType.ONE.ordinal());
assert enumObj.type().isEnum();
}
/**
* Validate simple array.
*
* @param registered Registered flag.
*/
private void validateSimpleArray(boolean registered) {
if (registered) {
Object[] arr1 = (Object[])cache1.get(1);
Object[] arr2 = (Object[])cache2.get(1);
assertEquals(2, arr1.length);
assertEquals(2, arr2.length);
assertEquals(EnumType.ONE, arr1[0]);
assertEquals(EnumType.TWO, arr1[1]);
assertEquals(EnumType.ONE, arr2[0]);
assertEquals(EnumType.TWO, arr2[1]);
}
Object[] arrBinary1 = (Object[])cacheBinary1.get(1);
Object[] arrBinary2 = (Object[])cacheBinary2.get(1);
assertEquals(2, arrBinary1.length);
assertEquals(2, arrBinary2.length);
validate((BinaryObject) arrBinary1[0], EnumType.ONE);
validate((BinaryObject) arrBinary1[1], EnumType.TWO);
validate((BinaryObject) arrBinary2[0], EnumType.ONE);
validate((BinaryObject) arrBinary2[1], EnumType.TWO);
}
/**
* Internal check routine for simple scenario.
*
* @param key Key.
* @param val Value.
* @param registered Registered flag.
* @throws Exception If failed.
*/
private void validateSimple(int key, EnumType val, boolean registered) throws Exception {
if (registered) {
assertEquals(val, cache1.get(key));
assertEquals(val, cache2.get(key));
}
validate((BinaryObject) cacheBinary1.get(key), val);
validate((BinaryObject) cacheBinary2.get(key), val);
}
/**
* Validate single value.
*
* @param obj Binary value.
* @param val Expected value.
*/
private void validate(BinaryObject obj, EnumType val) {
assertTrue(obj.type().isEnum());
assertEquals(node1.binary().typeId(EnumType.class.getName()), obj.type().typeId());
assertEquals(node2.binary().typeId(EnumType.class.getName()), obj.type().typeId());
assertEquals(val.ordinal(), obj.enumOrdinal());
}
/**
* Enumeration holder.
*/
public static class EnumHolder implements Serializable {
/** Value. */
public EnumType val;
/**
* Default constructor.
*/
@SuppressWarnings("UnusedDeclaration")
public EnumHolder() {
// No-op.
}
/**
* Constructor.
*
* @param val Value.
*/
public EnumHolder(EnumType val) {
this.val = val;
}
}
/**
* Enumeration for tests.
*/
public enum EnumType {
ONE,
TWO
}
}