io.datakernel.datagraph.server.DatagraphSerialization.java Source code

Java tutorial

Introduction

Here is the source code for io.datakernel.datagraph.server.DatagraphSerialization.java

Source

/*
 * Copyright (C) 2015 SoftIndex LLC.
 *
 * Licensed 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 io.datakernel.datagraph.server;

import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.common.collect.Ordering;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.InstanceCreator;
import io.datakernel.datagraph.graph.StreamId;
import io.datakernel.datagraph.node.*;
import io.datakernel.datagraph.server.command.DatagraphCommand;
import io.datakernel.datagraph.server.command.DatagraphCommandDownload;
import io.datakernel.datagraph.server.command.DatagraphCommandExecute;
import io.datakernel.serializer.BufferSerializer;
import io.datakernel.serializer.GsonSubclassesAdapter;
import io.datakernel.serializer.SerializerBuilder;
import io.datakernel.stream.processor.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Type;
import java.net.InetSocketAddress;
import java.util.*;

/**
 * Responsible for setting up serialization operations for datagraph.
 * Provides Gson object with specific adapters.
 * Maintains the cache of BufferSerializer's.
 */
public final class DatagraphSerialization {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public final Gson gson;

    private final Map<Class<?>, BufferSerializer<?>> serializers = new HashMap<>();

    public DatagraphSerialization() {
        this(Collections.<NodeSubclass>emptyList());
    }

    /**
     * Constructs a new datagraph serialization object, initializes Gson object with used classes.
     */
    public DatagraphSerialization(List<NodeSubclass> nodeSubclasses) {
        Class<?> naturalOrderingClass;
        Class<?> identityFunctionClass;
        try {
            naturalOrderingClass = Class.forName("com.google.common.collect.NaturalOrdering");
            identityFunctionClass = Class.forName("com.google.common.base.Functions$IdentityFunction");
        } catch (ClassNotFoundException e) {
            throw Throwables.propagate(e);
        }

        GsonSubclassesAdapter.Builder<Object> gsonSubclassesAdapterBuilder = GsonSubclassesAdapter.builder()
                .subclassField("nodeType").subclass("Download", NodeDownload.class)
                .subclass("Upload", NodeUpload.class).subclass("Map", NodeMap.class)
                .subclass("Filter", NodeFilter.class).subclass("Sort", NodeSort.class)
                .subclass("Shard", NodeShard.class).subclass("Merge", NodeMerge.class)
                .subclass("Reduce", NodeReduce.class).subclass("ReduceSimple", NodeReduceSimple.class)
                .subclass("Join", NodeJoin.class).subclass("ProducerOfIterable", NodeProducerOfIterable.class)
                .subclass("ConsumerToList", NodeConsumerToList.class);

        for (NodeSubclass nodeSubclass : nodeSubclasses) {
            gsonSubclassesAdapterBuilder.subclass(nodeSubclass.getSubclassName(), nodeSubclass.getSubclass());
        }

        this.gson = new GsonBuilder().registerTypeAdapter(Class.class, new GsonClassTypeAdapter())
                .registerTypeAdapter(StreamId.class, new GsonStreamIdAdapter())
                .registerTypeAdapter(InetSocketAddress.class, new GsonInetSocketAddressAdapter())
                .registerTypeAdapter(DatagraphCommand.class,
                        GsonSubclassesAdapter.builder().subclassField("commandType")
                                .subclass("Download", DatagraphCommandDownload.class)
                                .subclass("Execute", DatagraphCommandExecute.class).build())
                .registerTypeAdapter(Node.class, gsonSubclassesAdapterBuilder.build())
                .registerTypeAdapter(Predicate.class,
                        GsonSubclassesAdapter.builder().subclassField("predicateType").build())
                .registerTypeAdapter(Function.class,
                        GsonSubclassesAdapter.builder().subclassField("functionType")
                                .classTag(identityFunctionClass.getName(), identityFunctionClass,
                                        new InstanceCreator<Object>() {
                                            @Override
                                            public Object createInstance(Type type) {
                                                return Functions.identity();
                                            }
                                        })
                                .build())
                .registerTypeAdapter(Comparator.class,
                        GsonSubclassesAdapter.builder().subclassField("comparatorType")
                                .classTag(naturalOrderingClass.getName(), naturalOrderingClass,
                                        new InstanceCreator<Object>() {
                                            @Override
                                            public Object createInstance(Type type) {
                                                return Ordering.natural();
                                            }
                                        })
                                .build())
                .registerTypeAdapter(StreamMap.Mapper.class,
                        GsonSubclassesAdapter.builder().subclassField("mapperType").build())
                .registerTypeAdapter(StreamReducers.Reducer.class, GsonSubclassesAdapter.builder()
                        .subclassField("reducerType")
                        .classTag("MergeDeduplicateReducer", StreamReducers.MergeDeduplicateReducer.class)
                        .classTag("MergeSortReducer", StreamReducers.MergeSortReducer.class)
                        .subclass("InputToAccumulator", StreamReducers.ReducerToResult.InputToAccumulator.class)
                        .subclass("InputToOutput", StreamReducers.ReducerToResult.InputToOutput.class)
                        .subclass("AccumulatorToAccumulator",
                                StreamReducers.ReducerToResult.AccumulatorToAccumulator.class)
                        .subclass("AccumulatorToOutput", StreamReducers.ReducerToResult.AccumulatorToOutput.class)
                        .build())
                .registerTypeAdapter(StreamReducers.ReducerToResult.class,
                        GsonSubclassesAdapter.builder().subclassField("reducerToResultType").build())
                .registerTypeAdapter(Sharder.class,
                        GsonSubclassesAdapter.builder().subclassField("sharderType")
                                .subclass("HashSharder", Sharders.HashSharder.class).build())
                .registerTypeAdapter(StreamJoin.Joiner.class,
                        GsonSubclassesAdapter.builder().subclassField("joinerType").build())
                .setPrettyPrinting().enableComplexMapKeySerialization().create();
    }

    public synchronized <T> BufferSerializer<T> getSerializer(Class<T> type) {
        BufferSerializer<T> serializer = (BufferSerializer<T>) serializers.get(type);
        if (serializer == null) {
            logger.info("Creating serializer for {}", type);
            serializer = SerializerBuilder.newDefaultSerializer(type, ClassLoader.getSystemClassLoader());
            serializers.put(type, serializer);
        }
        return serializer;
    }

    <T> boolean checkGson(T item, Class<T> type) {
        String str = null;
        try {
            str = gson.toJson(item, type);
            gson.fromJson(str, type);
            return true;
        } catch (RuntimeException e) {
            logger.error("Gson error:\n{}\n\n{}", e, str);
            throw e;
        }
    }
}