edu.umass.cs.reconfiguration.reconfigurationpackets.ReconfigurationPacket.java Source code

Java tutorial

Introduction

Here is the source code for edu.umass.cs.reconfiguration.reconfigurationpackets.ReconfigurationPacket.java

Source

/* Copyright (c) 2015 University of Massachusetts
 * 
 * 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.
 * 
 * Initial developer(s): V. Arun */
package edu.umass.cs.reconfiguration.reconfigurationpackets;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

import org.json.JSONException;
import org.json.JSONObject;

import edu.umass.cs.gigapaxos.PaxosConfig.PC;
import edu.umass.cs.gigapaxos.interfaces.Request;
import edu.umass.cs.nio.JSONPacket;
import edu.umass.cs.nio.interfaces.Byteable;
import edu.umass.cs.nio.interfaces.IntegerPacketType;
import edu.umass.cs.nio.interfaces.Stringifiable;
import edu.umass.cs.protocoltask.ProtocolTask;
import edu.umass.cs.protocoltask.json.ProtocolPacket;
import edu.umass.cs.reconfiguration.Reconfigurator;
import edu.umass.cs.utils.Config;
import edu.umass.cs.utils.DelayProfiler;
import edu.umass.cs.utils.IntegerPacketTypeMap;

/**
 * @author V. Arun
 * @param <NodeIDType>
 */
@SuppressWarnings("javadoc")
public abstract class ReconfigurationPacket<NodeIDType>
        extends ProtocolPacket<NodeIDType, ReconfigurationPacket.PacketType> implements Byteable {

    /**
     * Reconfiguration packet type JSON key.
     */
    public static final String PACKET_TYPE = JSONPacket.PACKET_TYPE;
    /**
     * Used for reflection for invoking packet handling methods.
     */
    public static final String HANDLER_METHOD_PREFIX = "handle";

    /********************************* End of ReconfigurationpacketType ***********************/
    public enum PacketType implements IntegerPacketType {

        /**
         * A typical sequence of events is as follows. Active replicas regularly
         * send DEMAND_REPORTs to reconfigurators. Upon the receipt of some (but
         * far from all) demand report, a reconfigurator might decide to
         * initiate a reconfiguration that proceeds as follows:
         * 
         * DEMAND_REPORT: coordinate "reconfiguration intent" RC_RECORD_REQUEST
         * with other reconfigurators.
         * 
         * RC_RECORD_REQUEST (RECONFIGURATION_INTENT) : send STOP_EPOCH to all
         * active replicas.
         * 
         * STOP_EPOCH: coordinate STOP_EPOCH with other active replicas.
         * 
         * PaxosPacket.DECISION(STOP_EPOCH) : send ACK_STOP_EPOCH to
         * reconfigurators.
         * 
         * ACK_STOP_EPOCH : send START_EPOCH to next epoch active replicas.
         * 
         * START_EPOCH : send REQUEST_EPOCH_FINAL_STATE to previous epoch active
         * replicas.
         * 
         * REQUEST_EPOCH_FINAL_STATE : send EPOCH_FINAL_STATE
         * 
         * EPOCH_FINAL_STATE : create new epoch group locally and send
         * ACK_START_EPOCH to initiating reconfigurator.
         * 
         * ACK_START_EPOCH : upon receiving a majority of these from the new
         * epoch, send DROP_EPOCH_FINAL_STATE to old epoch active replicas, and
         * and coordinate RC_RECORD_REQUEST marking "reconfiguration complete"
         * with other reconfigurators (although the reconfiguration is not
         * completely complete yet).
         * 
         * RC_RECORD_REQUEST (RECONFIGURATION_COMPLETE) : mark the reconfigured
         * name as READY to receive client requests.
         * 
         * DROP_EPOCH_FINAL_STATE : drop old, stopped epoch's final state and
         * send ACK_DROP_EPOCH_FINAL_STATE to reconfigurator.
         * 
         * ACK_DROP_EPOCH_FINAL_STATE : wait until all old epoch active replicas
         * have dropped their state, marking the final completion of the
         * reconfiguration.
         * 
         */

        // reconfigurator -> active_replica
        STOP_EPOCH(224), // : coordinate stop with other actives
        START_EPOCH(226), // : request previous epoch final state
        DROP_EPOCH_FINAL_STATE(227), // : drop final state locally

        // active_replica -> active_replica
        REQUEST_EPOCH_FINAL_STATE(228), // : send epoch final state
        EPOCH_FINAL_STATE(229), // : record locally and ack to reconfigurator

        // active_replica -> reconfigurator
        DEMAND_REPORT(230), // : send stop_epoch if reconfiguration needed
        ACK_STOP_EPOCH(231), // : record locally
        ACK_START_EPOCH(232), // : record locally
        ACK_DROP_EPOCH_FINAL_STATE(233), // : record locally

        // app_client -> reconfigurator
        CREATE_SERVICE_NAME(234), // : initiate create
        DELETE_SERVICE_NAME(235), // : initiate delete
        REQUEST_ACTIVE_REPLICAS(236), // : send current active replicas

        // active_replica -> app_client
        ACTIVE_REPLICA_ERROR(237),

        // reconfigurator -> reconfigurator
        RC_RECORD_REQUEST(238),

        // admin -> reconfigurator
        RECONFIGURE_RC_NODE_CONFIG(239), RECONFIGURE_ACTIVE_NODE_CONFIG(240),

        ECHO_REQUEST(241),

        REPLICABLE_CLIENT_REQUEST(242)

        ;

        private final int number;

        PacketType(int t) {
            this.number = t;
        }

        public int getInt() {
            return number;
        }

        public static final IntegerPacketTypeMap<PacketType> intToType = new IntegerPacketTypeMap<PacketType>(
                PacketType.values());
    }

    public static final ReconfigurationPacket.PacketType[] clientPacketTypes = { PacketType.CREATE_SERVICE_NAME,
            PacketType.DELETE_SERVICE_NAME, PacketType.REQUEST_ACTIVE_REPLICAS, PacketType.ACTIVE_REPLICA_ERROR,
            PacketType.ECHO_REQUEST, PacketType.REPLICABLE_CLIENT_REQUEST };
    public static final ReconfigurationPacket.PacketType[] serverPacketTypes = {
            PacketType.RECONFIGURE_RC_NODE_CONFIG, PacketType.RECONFIGURE_ACTIVE_NODE_CONFIG };

    /********************************* End of ReconfigurationpacketType ***********************/

    /**************************** Start of ReconfigurationpacketType class map **************/
    private static final HashMap<ReconfigurationPacket.PacketType, Class<?>> typeMap = new HashMap<ReconfigurationPacket.PacketType, Class<?>>();
    static {
        /* This map prevents the need for laborious switch/case sequences as it
         * automatically handles both json-to-ReconfigurationPacket conversion
         * and invocation of the corresponding handler method. We have to rely
         * on reflection for both and the cost of the former seems to be the
         * bottleneck as it adds ~25us per conversion, but it seems not
         * problematic for now. */
        typeMap.put(ReconfigurationPacket.PacketType.STOP_EPOCH, StopEpoch.class);
        typeMap.put(ReconfigurationPacket.PacketType.START_EPOCH, StartEpoch.class);
        typeMap.put(ReconfigurationPacket.PacketType.REQUEST_EPOCH_FINAL_STATE, RequestEpochFinalState.class);
        typeMap.put(ReconfigurationPacket.PacketType.EPOCH_FINAL_STATE, EpochFinalState.class);
        typeMap.put(ReconfigurationPacket.PacketType.DROP_EPOCH_FINAL_STATE, DropEpochFinalState.class);

        typeMap.put(ReconfigurationPacket.PacketType.DEMAND_REPORT, DemandReport.class);
        typeMap.put(ReconfigurationPacket.PacketType.ACK_STOP_EPOCH, AckStopEpoch.class);
        typeMap.put(ReconfigurationPacket.PacketType.ACK_START_EPOCH, AckStartEpoch.class);
        typeMap.put(ReconfigurationPacket.PacketType.ACK_DROP_EPOCH_FINAL_STATE, AckDropEpochFinalState.class);

        typeMap.put(ReconfigurationPacket.PacketType.CREATE_SERVICE_NAME, CreateServiceName.class);
        typeMap.put(ReconfigurationPacket.PacketType.DELETE_SERVICE_NAME, DeleteServiceName.class);
        typeMap.put(ReconfigurationPacket.PacketType.REQUEST_ACTIVE_REPLICAS, RequestActiveReplicas.class);

        typeMap.put(ReconfigurationPacket.PacketType.ACTIVE_REPLICA_ERROR, ActiveReplicaError.class);

        typeMap.put(ReconfigurationPacket.PacketType.RC_RECORD_REQUEST, RCRecordRequest.class);

        typeMap.put(ReconfigurationPacket.PacketType.RECONFIGURE_RC_NODE_CONFIG, ReconfigureRCNodeConfig.class);
        typeMap.put(ReconfigurationPacket.PacketType.RECONFIGURE_ACTIVE_NODE_CONFIG,
                ReconfigureActiveNodeConfig.class);
        typeMap.put(ReconfigurationPacket.PacketType.ECHO_REQUEST, EchoRequest.class);
        typeMap.put(ReconfigurationPacket.PacketType.REPLICABLE_CLIENT_REQUEST, ReplicableClientRequest.class);

        for (ReconfigurationPacket.PacketType type : ReconfigurationPacket.PacketType.intToType.values()) {
            assert (getPacketTypeClassName(type) != null) : type;
        }
    }

    /**************************** End of ReconfigurationpacketType class map **************/

    // FIXME: probably should be removed
    protected ReconfigurationPacket(NodeIDType initiator) {
        super(initiator);
        // this.setType(t);
    }

    public ReconfigurationPacket(JSONObject json, Stringifiable<NodeIDType> unstringer) throws JSONException {
        super(json, unstringer);
        this.setType(getPacketType(json));
    }

    @Override
    public JSONObject toJSONObjectImpl() throws JSONException {
        JSONObject json = new JSONObject();
        return json;
    }

    @Override
    public Object getMessage() {
        return this;
    }

    @Override
    public PacketType getPacketType(JSONObject json) throws JSONException {
        return getReconfigurationPacketType(json);
    }

    @Override
    public void putPacketType(JSONObject json, PacketType type) throws JSONException {
        json.put(PACKET_TYPE, type.getInt());
    }

    public String toString() {
        try {
            return this.toJSONObject().toString();
        } catch (JSONException je) {
            je.printStackTrace();
        }
        return null;
    }

    public ReconfigurationPacket.PacketType getReconfigurationPacketType() {
        return this.type;
    }

    public static final boolean isReconfigurationPacket(JSONObject json) throws JSONException {
        return getReconfigurationPacketType(json) != null;
    }

    public static final ReconfigurationPacket.PacketType getReconfigurationPacketType(JSONObject json)
            throws JSONException {
        if (json.has(ReconfigurationPacket.PACKET_TYPE))
            return ReconfigurationPacket.PacketType.intToType.get(json.getInt(PACKET_TYPE));
        else
            return null;
    }

    public static final String getPacketTypeCanonicalClassName(ReconfigurationPacket.PacketType type) {
        return typeMap.get(type) != null ? typeMap.get(type).getCanonicalName() : null;
    }

    public static final String getPacketTypeClassName(ReconfigurationPacket.PacketType type) {
        return typeMap.get(type) != null ? typeMap.get(type).getSimpleName() : null;
    }

    public static final Class<?> getPacketTypeClass(ReconfigurationPacket.PacketType type) {
        return typeMap.get(type) != null ? typeMap.get(type) : null;
    }

    private static BasicReconfigurationPacket<?> getReconfigurationPacket(JSONObject json,
            Map<ReconfigurationPacket.PacketType, Class<?>> typeMap, Stringifiable<?> unstringer)
            throws JSONException {
        return getReconfigurationPacket(json, typeMap, unstringer, false);
    }

    private static BasicReconfigurationPacket<?> getReconfigurationPacket(JSONObject json,
            Map<ReconfigurationPacket.PacketType, Class<?>> typeMap, Stringifiable<?> unstringer,
            boolean forcePrintException) throws JSONException {
        BasicReconfigurationPacket<?> rcPacket = null;
        ReconfigurationPacket.PacketType rcType = null;
        String canonicalClassName = null;
        try {
            long t = System.nanoTime();
            if ((rcType = ReconfigurationPacket.PacketType.intToType.get(JSONPacket.getPacketType(json))) != null
                    && (canonicalClassName = getPacketTypeCanonicalClassName(rcType)) != null) {
                rcPacket = (BasicReconfigurationPacket<?>) (Class.forName(canonicalClassName)
                        .getConstructor(JSONObject.class, Stringifiable.class).newInstance(json, unstringer));
            }
            DelayProfiler.updateDelayNano("rc_reflection", t);
        } catch (NoSuchMethodException nsme) {
            nsme.printStackTrace();
        } catch (InvocationTargetException ite) {
            ite.printStackTrace();
        } catch (IllegalAccessException iae) {
            iae.printStackTrace();
        } catch (ClassNotFoundException cnfe) {
            Reconfigurator.getLogger().info("Class " + canonicalClassName + " not found");
            cnfe.printStackTrace();
        } catch (InstantiationException ie) {
            ie.printStackTrace();
        } finally {
            if (forcePrintException
                    && ReconfigurationPacket.PacketType.intToType.get(JSONPacket.getPacketType(json)) == null) {
                (new RuntimeException("No reconfiguration packet type found in: " + json)).printStackTrace();
            }
        }

        return rcPacket;
    }

    public static BasicReconfigurationPacket<?> getReconfigurationPacketSuppressExceptions(JSONObject json,
            Stringifiable<?> unstringer) {
        try {
            return getReconfigurationPacket(json, typeMap, unstringer);
        } catch (Exception e) {
            // do nothing
        }
        return null;
    }

    public static BasicReconfigurationPacket<?> getReconfigurationPacketSuppressExceptions(String str,
            Stringifiable<?> unstringer) {
        try {
            return JSONPacket.couldBeJSON(str) ? getReconfigurationPacket(new JSONObject(str), typeMap, unstringer)
                    : null;
        } catch (Exception e) {
            // do nothing
        }
        return null;
    }

    public static BasicReconfigurationPacket<?> getReconfigurationPacket(JSONObject json,
            Stringifiable<?> unstringer) throws JSONException {
        return getReconfigurationPacket(json, typeMap, unstringer);
    }

    public static BasicReconfigurationPacket<?> getReconfigurationPacket(Request request,
            Stringifiable<?> unstringer) throws JSONException {
        if (request instanceof BasicReconfigurationPacket<?>)
            return (BasicReconfigurationPacket<?>) request;
        return getReconfigurationPacket(new JSONObject(request.toString()), typeMap, unstringer);
    }

    /*  ************************ Start of assertion methods
     * ************************************************* */
    /* The assertion methods below are just convenience methods to let
     * protocoltasks assert that they have set up handlers for all packet types
     * for which they are responsible. */
    public static void assertPacketTypeChecks(ReconfigurationPacket.PacketType[] types, Class<?> target,
            String handlerMethodPrefix) {
        for (ReconfigurationPacket.PacketType type : types) {
            assertPacketTypeChecks(type, getPacketTypeClassName(type), target, handlerMethodPrefix);
        }
    }

    public static void assertPacketTypeChecks(Map<ReconfigurationPacket.PacketType, Class<?>> typeMap,
            Class<?> target, String handlerMethodPrefix) {
        // Assertions ensure that method name changes do not break code.
        for (ReconfigurationPacket.PacketType type : typeMap.keySet()) {
            assertPacketTypeChecks(type, getPacketTypeClassName(type), target, handlerMethodPrefix);
        }
    }

    public static void assertPacketTypeChecks(ReconfigurationPacket.PacketType type, String packetName,
            Class<?> target, String handlerMethodPrefix) {
        String errMsg = "Method " + handlerMethodPrefix + packetName + " does not exist in "
                + target.getSimpleName();
        try {
            // System.out.println(type + " : " + packetName + " : " +
            // handlerMethodPrefix+packetName);
            if (packetName != null)
                assert (target.getMethod(handlerMethodPrefix + packetName, getPacketTypeClass(type),
                        ProtocolTask[].class) != null) : errMsg;
        } catch (NoSuchMethodException nsme) {
            System.err.println(errMsg);
            nsme.printStackTrace();
        }
    }

    public static void assertPacketTypeChecks(Map<ReconfigurationPacket.PacketType, Class<?>> typeMap,
            Class<?> target) {
        assertPacketTypeChecks(typeMap, target, HANDLER_METHOD_PREFIX);
    }

    public static ReconfigurationPacket.PacketType[] concatenate(ReconfigurationPacket.PacketType[]... types) {
        int size = 0;
        for (ReconfigurationPacket.PacketType[] tarray : types)
            size += tarray.length;
        ReconfigurationPacket.PacketType[] allTypes = new ReconfigurationPacket.PacketType[size];
        int i = 0;
        for (ReconfigurationPacket.PacketType[] tarray : types) {
            for (ReconfigurationPacket.PacketType type : tarray) {
                allTypes[i++] = type;
            }
        }
        return allTypes;
    }

    /************************* End of assertion methods **************************************************/

    static void main(String[] args) {
        System.out.println(ReconfigurationPacket.PacketType.intToType.get(225));
    }

    private static final String CHARSET = "ISO-8859-1";

    private static final boolean BYTEIFICATION = Config.getGlobalBoolean(PC.BYTEIFICATION);

    @Override
    public byte[] toBytes() {
        byte[] body = null;
        try {
            body = this.toString().getBytes(CHARSET);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
        if (!BYTEIFICATION)
            return body;
        // else
        byte[] bytes = new byte[body.length + 4];
        ByteBuffer bbuf = ByteBuffer.wrap(bytes);
        bbuf.putInt(this.getType().getInt());
        bbuf.put(body);
        return bytes;
    }
}