import static org.apache.ignite.cache.CacheAtomicWriteOrderMode.PRIMARY;
import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
import static org.apache.ignite.cache.CacheMode.PARTITIONED;
import static org.apache.ignite.cache.CacheWriteSynchronizationMode.PRIMARY_SYNC;
import static org.apache.ignite.configuration.DeploymentMode.SHARED;

import java.io.ByteArrayOutputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Arrays;

import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.IgniteException;
import org.apache.ignite.Ignition;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.events.EventType;
import org.apache.ignite.marshaller.optimized.OptimizedMarshaller;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;

/**
 * 
 * @author mchelyada
 * 
 */
public class ExternalizableDeserializationFails {

    private CacheConfiguration<String, DummyExternalizable> createCacheConfiguration(String cacheName) {
        CacheConfiguration<String, DummyExternalizable> cacheConfiguration = new CacheConfiguration<String, DummyExternalizable>();

        cacheConfiguration.setName(cacheName);
        cacheConfiguration.setCacheMode(PARTITIONED);
        cacheConfiguration.setAtomicityMode(ATOMIC);
        cacheConfiguration.setAtomicWriteOrderMode(PRIMARY);
        cacheConfiguration.setWriteSynchronizationMode(PRIMARY_SYNC);
        cacheConfiguration.setStoreByValue(false);
        cacheConfiguration.setCopyOnRead(false);

        return cacheConfiguration;
    }

    private IgniteConfiguration getGridConfiguration(String gridName) throws IgniteException {
        IgniteConfiguration gridConfig = new IgniteConfiguration();
        gridConfig.setGridName(gridName);

        CacheConfiguration<String, DummyExternalizable> cacheConfig = createCacheConfiguration("testCache");
        gridConfig.setCacheConfiguration(cacheConfig);

        gridConfig.setLocalHost("127.0.0.1");
        gridConfig.setDeploymentMode(SHARED);

        gridConfig.setIncludeEventTypes(EventType.EVT_CACHE_OBJECT_PUT);
        gridConfig.setMarshalLocalJobs(false);

        gridConfig.setMarshaller(new OptimizedMarshaller());

        TcpDiscoveryVmIpFinder ipFinder = new TcpDiscoveryVmIpFinder();
        ipFinder.setAddresses(Arrays.asList("127.0.0.1:47501", "127.0.0.1:47502"));

        TcpDiscoverySpi spi = new TcpDiscoverySpi();
        spi.setIpFinder(ipFinder);
        spi.setLocalAddress("127.0.0.1");
        spi.setLocalPort(47501);

        gridConfig.setDiscoverySpi(spi);

        return gridConfig;
    }

    public void insertExternalizable() throws Exception {
        IgniteConfiguration gridConfig = getGridConfiguration("testGrid");
        Ignite grid = Ignition.start(gridConfig);

        final IgniteCache<String, DummyExternalizable> testCache = grid.cache("testCache");

        testCache.put("testKey1", new DummyExternalizable("dummy data".getBytes()));
    }

    private static class DummyExternalizable implements Externalizable {
        private byte[] data;

        public DummyExternalizable() {

        }

        public DummyExternalizable(byte[] data) {
            this.data = data;
        }

        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            out.write(data);
        }

        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            byte[] buffer = new byte[1024];
            int n = 0;
            while (-1 != (n = in.read(buffer))) {
                baos.write(buffer, 0, n);
            }

            data = baos.toByteArray();
        }
    }

    public static void main(String[] args) throws Exception {
        System.out.println("Running externalizable test.");

        ExternalizableDeserializationFails test = new ExternalizableDeserializationFails();

        test.insertExternalizable();

        System.out.println("Test complete!");
    }
}
