try {
                        return (Iterator) iter.invoke(obj);
                    } catch (IllegalAccessException e) {
                        // Cannot invoke this method, just give up
                    } catch (Exception e) {
                        throw new VelocityException("Error invoking the method 'iterator' on class '" + obj.getClass().getName() + "'", e, rsvc.getLogContext().getStackTrace());
                    }

package org.apache.velocity.util.introspection;

import org.apache.velocity.exception.VelocityException;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.parser.node.AbstractExecutor;
import org.apache.velocity.runtime.parser.node.BooleanPropertyExecutor;
import org.apache.velocity.runtime.parser.node.GetExecutor;
import org.apache.velocity.runtime.parser.node.MapGetExecutor;
import org.apache.velocity.runtime.parser.node.MapSetExecutor;
import org.apache.velocity.runtime.parser.node.PropertyExecutor;
import org.apache.velocity.runtime.parser.node.PutExecutor;
import org.apache.velocity.runtime.parser.node.SetExecutor;
import org.apache.velocity.runtime.parser.node.SetPropertyExecutor;
import org.apache.velocity.util.ArrayIterator;
import org.apache.velocity.util.ArrayListWrapper;
import org.apache.velocity.util.ClassUtils;
import org.apache.velocity.util.EnumerationIterator;
import org.apache.velocity.util.RuntimeServicesAware;
import org.slf4j.Logger;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;

/**
 *  Implementation of Uberspect to provide the default introspective
 *  functionality of Velocity
 *
 * @author Geir Magnusson Jr.
 * @author Henning P. Schmiedehausen
 * @version $Id$
 */
public class UberspectImpl implements Uberspect, RuntimeServicesAware {

    /**
     *  Our runtime logger.
     */
    protected Logger log;

    protected Introspector introspector;

    /**
     * the conversion handler
     */
    protected TypeConversionHandler conversionHandler;

    /**
     * runtime services
     */
    protected RuntimeServices rsvc;

    /**
     *  init - generates the Introspector. As the setup code
     *  makes sure that the log gets set before this is called,
     *  we can initialize the Introspector using the log object.
     */
    @Override
    public void init() {
        introspector = new Introspector(log, conversionHandler);
    }

    public TypeConversionHandler getConversionHandler() {
        return conversionHandler;
    }

    /**
     * sets the runtime services
     * @param rs runtime services
     */
    @Override
    @SuppressWarnings("deprecation")
    public void setRuntimeServices(RuntimeServices rs) {
        rsvc = rs;
        log = rsvc.getLog("introspection");
        Object conversionHandlerInstance = rs.getProperty(RuntimeConstants.CONVERSION_HANDLER_INSTANCE);
        if (conversionHandlerInstance == null) {
            String conversionHandlerClass = rs.getString(RuntimeConstants.CONVERSION_HANDLER_CLASS);
            if (conversionHandlerClass != null && !conversionHandlerClass.equals("none")) {
                try {
                    conversionHandlerInstance = ClassUtils.getNewInstance(conversionHandlerClass);
                } catch (ClassNotFoundException cnfe) {
                    String err = "The specified class for ConversionHandler (" + conversionHandlerClass + ") does not exist or is not accessible to the current classloader.";
                    log.error(err);
                    throw new VelocityException(err, cnfe);
                } catch (InstantiationException ie) {
                    throw new VelocityException("Could not instantiate class '" + conversionHandlerClass + "'", ie);
                } catch (IllegalAccessException ae) {
                    throw new VelocityException("Cannot access class '" + conversionHandlerClass + "'", ae);
                }
            }
        }
        if (conversionHandlerInstance != null) {
            if (conversionHandlerInstance instanceof ConversionHandler) {
                log.warn("The ConversionHandler interface is deprecated - see the TypeConversionHandler interface");
                final ConversionHandler ch = (ConversionHandler) conversionHandlerInstance;
                conversionHandler = new TypeConversionHandler() {

                    @Override
                    public boolean isExplicitlyConvertible(Type formal, Class<?> actual, boolean possibleVarArg) {
                        Class<?> formalClass = IntrospectionUtils.getTypeClass(formal);
                        if (formalClass != null)
                            return ch.isExplicitlyConvertible(formalClass, actual, possibleVarArg);
                        else
                            return false;
                    }

                    @Override
                    public Converter<?> getNeededConverter(Type formal, Class<?> actual) {
                        Class<?> formalClass = IntrospectionUtils.getTypeClass(formal);
                        if (formalClass != null)
                            return ch.getNeededConverter(formalClass, actual);
                        else
                            return null;
                    }

                    @Override
                    public void addConverter(Type formal, Class<?> actual, Converter<?> converter) {
                        Class<?> formalClass = IntrospectionUtils.getTypeClass(formal);
                        if (formalClass != null)
                            ch.addConverter(formalClass, actual, converter);
                        else
                            throw new UnsupportedOperationException("This conversion handler doesn't know how to handle Type: " + formal.getTypeName());
                    }
                };
            } else if (!(conversionHandlerInstance instanceof TypeConversionHandler)) {
                String err = "The specified class or provided instance for the conversion handler (" + conversionHandlerInstance.getClass().getName() + ") does not implement " + TypeConversionHandler.class.getName() + "; Velocity is not initialized correctly.";
                log.error(err);
                throw new VelocityException(err, null, rsvc.getLogContext().getStackTrace());
            } else {
                conversionHandler = (TypeConversionHandler) conversionHandlerInstance;
            }
        }
    }

    /**
     *  Sets the runtime logger - this must be called before anything
     *  else.
     *
     * @param log The logger instance to use.
     * @since 1.5
     * @deprecated logger is now set by default to the namespace logger "velocity.rendering".
     */
    public void setLog(Logger log) {
        this.log = log;
    }

    /**
     *  To support iterative objects used in a #foreach()
     *  loop.
     *
     * @param obj The iterative object.
     * @param i Info about the object's location.
     * @return An {@link Iterator} object.
     */
    @Override
    public Iterator getIterator(Object obj, Info i) {
        if (obj.getClass().isArray()) {
            return new ArrayIterator(obj);
        } else if (obj instanceof Iterable) {
            return ((Iterable) obj).iterator();
        } else if (obj instanceof Map) {
            return ((Map) obj).values().iterator();
        } else if (obj instanceof Iterator) {
            log.debug("The iterative object in the #foreach() loop at {}" + " is of type java.util.Iterator.  Because " + "it is not resettable, if used in more than once it " + "may lead to unexpected results.", i);
            return ((Iterator) obj);
        } else if (obj instanceof Enumeration) {
            log.debug("The iterative object in the #foreach() loop at {}" + " is of type java.util.Enumeration.  Because " + "it is not resettable, if used in more than once it " + "may lead to unexpected results.", i);
            return new EnumerationIterator((Enumeration) obj);
        } else {
            // look for an iterator() method to support the JDK5 Iterable
            // interface or any user tools/DTOs that want to work in
            // foreach without implementing the Collection interface
            Class<?> type = obj.getClass();
            try {
                Method iter = type.getMethod("iterator");
                Class<?> returns = iter.getReturnType();
                if (Iterator.class.isAssignableFrom(returns)) {

                } else {
                    log.debug("iterator() method of reference in #foreach loop at " + "{} does not return a true Iterator.", i);
                }
            } catch (NoSuchMethodException nsme) {
                // eat this one, but let all other exceptions thru
            }
        }
        /*  we have no clue what this is  */
        log.debug("Could not determine type of iterator in #foreach loop at {}", i);
        return null;
    }

    /**
     *  Method
     * @param obj
     * @param methodName
     * @param args
     * @param i
     * @return A Velocity Method.
     */
    @Override
    public VelMethod getMethod(Object obj, String methodName, Object[] args, Info i) {
        if (obj == null) {
            return null;
        }
        Method m = introspector.getMethod(obj.getClass(), methodName, args);
        if (m != null) {
            return new VelMethodImpl(m, false, getNeededConverters(m.getGenericParameterTypes(), args));
        }
        Class<?> cls = obj.getClass();
        // if it's an array
        if (cls.isArray()) {
            // check for support via our array->list wrapper
            m = introspector.getMethod(ArrayListWrapper.class, methodName, args);
            if (m != null) {
                // and create a method that knows to wrap the value
                // before invoking the method
                return new VelMethodImpl(m, true, getNeededConverters(m.getGenericParameterTypes(), args));
            }
        } else // watch for classes, to allow calling their static methods (VELOCITY-102)
        if (cls == Class.class) {
            m = introspector.getMethod((Class<?>) obj, methodName, args);
            if (m != null) {
                return new VelMethodImpl(m, false, getNeededConverters(m.getGenericParameterTypes(), args));
            }
        }
        return null;
    }

    /**
     * get the list of needed converters to adapt passed argument types to method types
     * @return null if not conversion needed, otherwise an array containing needed converters
     */
    private Converter<?>[] getNeededConverters(Type[] expected, Object[] provided) {
        if (conversionHandler == null)
            return null;
        // var args are not handled here - CB TODO
        int n = Math.min(expected.length, provided.length);
        Converter<?>[] converters = null;
        for (int i = 0; i < n; ++i) {
            Object arg = provided[i];
            if (arg == null)
                continue;
            Converter<?> converter = conversionHandler.getNeededConverter(expected[i], arg.getClass());
            if (converter != null) {
                if (converters == null) {
                    converters = new Converter[expected.length];
                }
                converters[i] = converter;
            }
        }
        return converters;
    }

    /**
     * Property  getter
     * @param obj
     * @param identifier
     * @param i
     * @return A Velocity Getter Method.
     */
    @Override
    public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i) {
        if (obj == null) {
            return null;
        }
        Class<?> claz = obj.getClass();
        /*
         *  first try for a getFoo() type of property
         *  (also getfoo() )
         */
        AbstractExecutor executor = new PropertyExecutor(log, introspector, claz, identifier);
        /*
         * Let's see if we are a map...
         */
        if (!executor.isAlive()) {
            executor = new MapGetExecutor(log, obj, identifier);
        }
        if (!executor.isAlive()) {
            executor = new GetExecutor(log, introspector, claz, identifier);
        }
        if (!executor.isAlive()) {
            executor = new BooleanPropertyExecutor(log, introspector, claz, identifier);
        }
        /*
         * and idem on an array
         */
        if (!executor.isAlive() && obj.getClass().isArray()) {
            executor = new BooleanPropertyExecutor(log, introspector, ArrayListWrapper.class, identifier, true);
        }
        return (executor.isAlive()) ? new VelGetterImpl(executor) : null;
    }

    /**
     * Property setter
     * @param obj
     * @param identifier
     * @param arg
     * @param i
     * @return A Velocity Setter method.
     */
    @Override
    public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, Info i) {
        if (obj == null) {
            return null;
        }
        Class<?> claz = obj.getClass();
        /*
         *  first try for a setFoo() type of property
         *  (also setfoo() )
         */
        SetExecutor executor = new SetPropertyExecutor(log, introspector, claz, identifier, arg);
        /*
         * Let's see if we are a map...
         */
        if (!executor.isAlive()) {
            executor = new MapSetExecutor(log, claz, identifier);
        }
        if (!executor.isAlive()) {
            executor = new PutExecutor(log, introspector, claz, arg, identifier);
        }
        return (executor.isAlive()) ? new VelSetterImpl(executor) : null;
    }

    /**
     *  Implementation of VelMethod
     */
    public static class VelMethodImpl implements VelMethod {

        final Method method;

        Boolean isVarArg;

        boolean wrapArray;

        Converter<?>[] converters;

        /**
         * @param m
         */
        public VelMethodImpl(Method m) {
            this(m, false, null);
        }

        /**
         * @param method
         * @param wrapArray
         * @since 1.6
         */
        public VelMethodImpl(Method method, boolean wrapArray) {
            this(method, wrapArray, null);
        }

        /**
         * @param method
         * @param wrapArray
         * @param converters
         * @since 2.0
         */
        public VelMethodImpl(Method method, boolean wrapArray, Converter<?>[] converters) {
            this.method = method;
            this.wrapArray = wrapArray;
            this.converters = converters;
        }

        private VelMethodImpl() {
            method = null;
        }

        /**
         * @param o
         * @param actual
         * @return invocation result
         * @see VelMethod#invoke(java.lang.Object, java.lang.Object[])
         */
        @Override
        public Object invoke(Object o, Object[] actual) throws IllegalAccessException, InvocationTargetException {
            // if we're pretending an array is a list...
            if (wrapArray) {
                o = new ArrayListWrapper(o);
            }
            if (isVarArg()) {
                Class<?>[] formal = method.getParameterTypes();
                int index = formal.length - 1;
                if (actual.length >= index) {
                    Class<?> type = formal[index].getComponentType();
                    actual = handleVarArg(type, index, actual);
                }
            }
            if (converters != null) {
                // some converters may throw an ArithmeticException
                // which we want to wrap into an IllegalArgumentException
                try {
                    for (int i = 0; i < actual.length; ++i) {
                        if (converters[i] != null) {
                            actual[i] = converters[i].convert(actual[i]);
                        }
                    }
                } catch (ArithmeticException ae) {
                    throw new IllegalArgumentException(ae);
                }
            }
            // call extension point invocation
            return doInvoke(o, actual);
        }

        /**
         * Offers an extension point for subclasses (in alternate Uberspects)
         * to alter the invocation after any array wrapping or varargs handling
         * has already been completed.
         * @param o target object
         * @param actual arguments
         * @return invocation result
         * @throws IllegalAccessException
         * @throws InvocationTargetException
         * @since 1.6
         */
        protected Object doInvoke(Object o, Object[] actual) throws IllegalAccessException, InvocationTargetException {
            return method.invoke(o, actual);
        }

        /**
         * @return true if this method can accept a variable number of arguments
         * @since 1.6
         */
        public boolean isVarArg() {
            if (isVarArg == null) {
                Class<?>[] formal = method.getParameterTypes();
                if (formal.length == 0) {
                    this.isVarArg = Boolean.FALSE;
                } else {
                    Class<?> last = formal[formal.length - 1];
                    // if the last arg is an array, then
                    // we consider this a varargs method
                    this.isVarArg = last.isArray();
                }
            }
            return isVarArg;
        }

        /**
         * @param type The vararg class type (aka component type
         *             of the expected array arg)
         * @param index The index of the vararg in the method declaration
         *              (This will always be one less than the number of
         *               expected arguments.)
         * @param actual The actual parameters being passed to this method
         * @return The actual parameters adjusted for the varargs in order
         *          to fit the method declaration.
         */
        private Object[] handleVarArg(final Class<?> type, final int index, Object[] actual) {
            // if no values are being passed into the vararg
            if (actual.length == index) {
                // copy existing args to new array
                Object[] newActual = new Object[actual.length + 1];
                System.arraycopy(actual, 0, newActual, 0, actual.length);
                // create an empty array of the expected type
                newActual[index] = Array.newInstance(type, 0);
                actual = newActual;
            } else // if one value is being passed into the vararg
            if (actual.length == index + 1 && actual[index] != null) {
                // make sure the last arg is an array of the expected type
                Class<?> argClass = actual[index].getClass();
                if (!argClass.isArray() && IntrospectionUtils.isMethodInvocationConvertible(type, argClass, false)) {
                    // create a 1-length array to hold and replace the last param
                    Object lastActual = Array.newInstance(type, 1);
                    Array.set(lastActual, 0, actual[index]);
                    actual[index] = lastActual;
                }
            } else // if multiple values are being passed into the vararg
            if (actual.length > index + 1) {
                // put the last and extra actual in an array of the expected type
                int size = actual.length - index;
                Object lastActual = Array.newInstance(type, size);
                for (int i = 0; i < size; i++) {
                    Array.set(lastActual, i, actual[index + i]);
                }
                // put all into a new actual array of the appropriate size
                Object[] newActual = new Object[index + 1];
                System.arraycopy(actual, 0, newActual, 0, index);
                newActual[index] = lastActual;
                // replace the old actual array
                actual = newActual;
            }
            return actual;
        }

        /**
         * @see org.apache.velocity.util.introspection.VelMethod#isCacheable()
         */
        @Override
        public boolean isCacheable() {
            return true;
        }

        /**
         * @see org.apache.velocity.util.introspection.VelMethod#getMethodName()
         */
        @Override
        public String getMethodName() {
            return method.getName();
        }

        /**
         * @see org.apache.velocity.util.introspection.VelMethod#getMethod()
         */
        @Override
        public Method getMethod() {
            return method;
        }

        /**
         * @see org.apache.velocity.util.introspection.VelMethod#getReturnType()
         */
        @Override
        public Class<?> getReturnType() {
            return method.getReturnType();
        }
    }

    public static class VelGetterImpl implements VelPropertyGet {

        final AbstractExecutor getExecutor;

        /**
         * @param exec
         */
        public VelGetterImpl(AbstractExecutor exec) {
            getExecutor = exec;
        }

        private VelGetterImpl() {
            getExecutor = null;
        }

        /**
         * @see org.apache.velocity.util.introspection.VelPropertyGet#invoke(java.lang.Object)
         */
        @Override
        public Object invoke(Object o) throws IllegalAccessException, InvocationTargetException {
            return getExecutor.execute(o);
        }

        /**
         * @see org.apache.velocity.util.introspection.VelPropertyGet#isCacheable()
         */
        @Override
        public boolean isCacheable() {
            return true;
        }

        /**
         * @see org.apache.velocity.util.introspection.VelPropertyGet#getMethodName()
         */
        @Override
        public String getMethodName() {
            return getExecutor.isAlive() ? getExecutor.getMethod().getName() : null;
        }
    }

    public static class VelSetterImpl implements VelPropertySet {

        private final SetExecutor setExecutor;

        /**
         * @param setExecutor
         */
        public VelSetterImpl(final SetExecutor setExecutor) {
            this.setExecutor = setExecutor;
        }

        private VelSetterImpl() {
            setExecutor = null;
        }

        /**
         * Invoke the found Set Executor.
         *
         * @param o is the Object to invoke it on.
         * @param value in the Value to set.
         * @return The resulting Object.
         */
        @Override
        public Object invoke(final Object o, final Object value) throws IllegalAccessException, InvocationTargetException {
            return setExecutor.execute(o, value);
        }

        /**
         * @see org.apache.velocity.util.introspection.VelPropertySet#isCacheable()
         */
        @Override
        public boolean isCacheable() {
            return true;
        }

        /**
         * @see org.apache.velocity.util.introspection.VelPropertySet#getMethodName()
         */
        @Override
        public String getMethodName() {
            return setExecutor.isAlive() ? setExecutor.getMethod().getName() : null;
        }
    }
}


for (int i = 0; i < 50; i++) {
            getRangeWithoutRefresh(i, 0, i, 9).setCellValue(new Random().nextInt(100));
        }

package zss.issue;

import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.*;
import org.zkoss.zss.api.*;
import org.zkoss.zss.api.model.CellStyle;
import org.zkoss.zss.ui.Spreadsheet;
import org.zkoss.zul.Vlayout;
import java.util.*;

public class OverflowRightAlignComposer extends SelectorComposer<Component> {

    @Wire
    private Spreadsheet ss;

    private LinkedList<Range> rangesToNotify = new LinkedList<Range>();

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        mergeAcrossFrozenColumns();
    }

    private void mergeAcrossFrozenColumns() {
        Range range = Ranges.range(ss.getSelectedSheet(), 8, 0, 8, 4);
        range.merge(false);
        range.setCellValue("A9:D9 merged by API with right alignement");
        CellOperationUtil.applyAlignment(range, CellStyle.Alignment.RIGHT);
    }

    @Listen("onClick = #fill")
    public void fill() {

        notifyRanges();
    }

    @Listen("onClick = #unfreeze")
    public void unfreeze() {
        Ranges.range(ss.getSelectedSheet()).setFreezePanel(0, 0);
    }

    @Listen("onClick = #freeze")
    public void freeze() {
        Ranges.range(ss.getSelectedSheet()).setFreezePanel(0, 3);
    }

    @Listen("onClick = #merge")
    public void merge() {
        Ranges.range(ss.getSelectedSheet(), 9, 0, 9, 3).merge(false);
        Ranges.range(ss.getSelectedSheet(), 10, 2, 10, 3).merge(false);
    }

    private void notifyRanges() {
        Ranges.range(ss.getSelectedSheet()).notifyChange();
        rangesToNotify.clear();
    }

    private Range getRangeWithoutRefresh(int topRow, int leftColumn, int bottomRow, int rightColumn) {
        Range range = Ranges.range(ss.getSelectedSheet(), topRow, leftColumn, bottomRow, rightColumn);
        range.setAutoRefresh(false);
        rangesToNotify.add(range);
        return range;
    }
}


for (int i = 0; i < useData.length; i++) {
            usefulData[i] = ((long) useData[i]) & 0xFF;
        }

/*
 * OrcaFrefill.java
 *
 * This file is part of FareBot.
 * Learn more at: http://example.com
 *
 *
 */
package com.codebutler.farebot.transit.orca;

import android.content.res.Resources;
import androidx.annotation.NonNull;
import com.codebutler.farebot.card.desfire.DesfireRecord;
import com.codebutler.farebot.transit.Refill;
import com.google.auto.value.AutoValue;
import java.text.NumberFormat;
import java.util.Locale;

@AutoValue
public abstract class OrcaRefill extends Refill {

    @NonNull
    static OrcaRefill create(@NonNull DesfireRecord record) {
        byte[] useData = record.getData().bytes();
        long[] usefulData = new long[useData.length];

        long timestamp = ((0x0F & usefulData[3]) << 28) | (usefulData[4] << 20) | (usefulData[5] << 12) | (usefulData[6] << 4) | (usefulData[7] >> 4);
        long ftpType = ((usefulData[7] & 0xf) << 4) | ((usefulData[8] & 0xf0) >> 4);
        long ftpId = ((usefulData[8] & 0xf) << 20) | (usefulData[9] << 12) | (usefulData[10] << 4) | ((usefulData[11] & 0xf0) >> 4);
        long amount;
        amount = (usefulData[15] << 7) | (usefulData[16] >> 1);
        long newBalance = (usefulData[34] << 8) | usefulData[35];
        long agency = usefulData[3] >> 4;
        long transType = (usefulData[17]);
        return new AutoValue_OrcaRefill(timestamp, amount, agency);
    }

    @Override
    public String getAgencyName(@NonNull Resources resources) {
        switch((int) getAgency()) {
            case OrcaTransitInfo.AGENCY_CT:
                return resources.getString(R.string.transit_orca_agency_ct);
            case OrcaTransitInfo.AGENCY_KCM:
                return resources.getString(R.string.transit_orca_agency_kcm);
            case OrcaTransitInfo.AGENCY_PT:
                return resources.getString(R.string.transit_orca_agency_pt);
            case OrcaTransitInfo.AGENCY_ST:
                return resources.getString(R.string.transit_orca_agency_st);
            case OrcaTransitInfo.AGENCY_WSF:
                return resources.getString(R.string.transit_orca_agency_wsf);
            case OrcaTransitInfo.AGENCY_ET:
                return resources.getString(R.string.transit_orca_agency_et);
            case OrcaTransitInfo.AGENCY_KT:
                return resources.getString(R.string.transit_orca_agency_kt);
        }
        return resources.getString(R.string.transit_orca_agency_unknown, Long.toString(getAgency()));
    }

    @Override
    public String getShortAgencyName(@NonNull Resources resources) {
        switch((int) getAgency()) {
            case OrcaTransitInfo.AGENCY_CT:
                return "CT";
            case OrcaTransitInfo.AGENCY_KCM:
                return "KCM";
            case OrcaTransitInfo.AGENCY_PT:
                return "PT";
            case OrcaTransitInfo.AGENCY_ST:
                return "ST";
            case OrcaTransitInfo.AGENCY_WSF:
                return "WSF";
            case OrcaTransitInfo.AGENCY_ET:
                return "ET";
            case OrcaTransitInfo.AGENCY_KT:
                return "KT";
        }
        return resources.getString(R.string.transit_orca_agency_unknown, Long.toString(getAgency()));
    }

    @Override
    public String getAmountString(Resources resources) {
        return NumberFormat.getCurrencyInstance(Locale.US).format(getAmount() / 100);
    }

    abstract long getAgency();
}


try {
            return JSONMessageDeserializer.mapper.writeValueAsString(this);
        } catch (Exception exception) {
            throw new IllegalArgumentException("Could not serialize: ", exception);
        }

package org.apache.hadoop.hive.metastore.messaging.json;

import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.hive.metastore.api.SQLNotNullConstraint;
import org.apache.hadoop.hive.metastore.messaging.AddNotNullConstraintMessage;
import org.apache.hadoop.hive.metastore.messaging.MessageBuilder;
import org.apache.thrift.TException;
import com.fasterxml.jackson.annotation.JsonProperty;

public class JSONAddNotNullConstraintMessage extends AddNotNullConstraintMessage {

    @JsonProperty
    String server, servicePrincipal;

    @JsonProperty
    Long timestamp;

    @JsonProperty
    List<String> notNullConstraintListJson;

    public JSONAddNotNullConstraintMessage() {
    }

    public JSONAddNotNullConstraintMessage(String server, String servicePrincipal, List<SQLNotNullConstraint> nns, Long timestamp) {
        this.server = server;
        this.servicePrincipal = servicePrincipal;
        this.timestamp = timestamp;
        this.notNullConstraintListJson = new ArrayList<>();
        try {
            for (SQLNotNullConstraint nn : nns) {
                notNullConstraintListJson.add(MessageBuilder.createNotNullConstraintObjJson(nn));
            }
        } catch (TException e) {
            throw new IllegalArgumentException("Could not serialize: ", e);
        }
    }

    @Override
    public String getServer() {
        return server;
    }

    @Override
    public String getServicePrincipal() {
        return servicePrincipal;
    }

    @Override
    public String getDB() {
        return null;
    }

    @Override
    public Long getTimestamp() {
        return timestamp;
    }

    @Override
    public List<SQLNotNullConstraint> getNotNullConstraints() throws Exception {
        List<SQLNotNullConstraint> nns = new ArrayList<>();
        for (String nnJson : notNullConstraintListJson) {
            nns.add((SQLNotNullConstraint) MessageBuilder.getTObj(nnJson, SQLNotNullConstraint.class));
        }
        return nns;
    }

    @Override
    public String toString() {


private MpscLinkedQueueNode<E> peekNode() {
        MpscLinkedQueueNode<E> head = headRef();
        MpscLinkedQueueNode<E> next = head.next();
        if (next == null && head != tailRef()) {
            // if tail != head this is not going to change until consumer makes progress
            // we can avoid reading the head and just spin on next until it shows up
            do {
                next = head.next();
            } while (next == null);
        }
        return next;
    }

package qunar.tc.qmq.batch;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * A lock-free concurrent single-consumer multi-producer {@link java.util.Queue}.
 * It allows multiple producer threads to perform the following operations simultaneously:
 *

 *
{@link #offer(Object)}, {@link #add(Object)}, and {@link #addAll(java.util.Collection)}

 *
All other read-only operations:
 *

 *
{@link #contains(Object)} and {@link #containsAll(java.util.Collection)}

 *
{@link #element()}, {@link #peek()}

 *
{@link #size()} and {@link #isEmpty()}

 *
{@link #iterator()} (except {@link java.util.Iterator#remove()}

 *
{@link #toArray()} and {@link #toArray(Object[])}

 *

 *

 *

 * .. while only one consumer thread is allowed to perform the following operations exclusively:
 *

 *
{@link #poll()} and {@link #remove()}

 *
{@link #remove(Object)}, {@link #removeAll(java.util.Collection)}, and {@link #retainAll(java.util.Collection)}

 *
{@link #clear()}
 {@link #}
 *

 *

 * The behavior of this implementation is undefined if you perform the operations for a consumer thread only
 * from multiple threads.
 *

 * The initial implementation is based on:
 *

 *
Non-intrusive MPSC node based queue from 1024cores.net

 *
AbstractNodeQueue from Akka

 *

 * and adopted padded head node changes from:
 *

 *
MpscPaddedQueue from RxJava

 *

 */
final class MpscLinkedQueue<E> extends MpscLinkedQueueTailRef<E> implements Queue<E> {

    private static final long serialVersionUID = -1878402552271506449L;

    long p00, p01, p02, p03, p04, p05, p06, p07;

    long p30, p31, p32, p33, p34, p35, p36, p37;

    // offer() occurs at the tail of the linked list.
    // poll() occurs at the head of the linked list.
    // Resulting layout is:
    // where the head is a dummy node whose value is null.
    // offer() appends a new node next to the tail using AtomicReference.getAndSet()
    // poll() removes head from the linked list and promotes the 1st element to the head,
    // setting its value to null if possible.
    // Also note that this class extends AtomicReference for the "tail" slot (which is the one that is appended to)
    // since Unsafe does not expose XCHG operation intrinsically.
    private final AtomicInteger count = new AtomicInteger();

    private final int size;

    public MpscLinkedQueue(int size) {
        this.size = size;
        MpscLinkedQueueNode<E> tombstone = new DefaultNode<E>(null);
        setHeadRef(tombstone);
        setTailRef(tombstone);
    }

    /**
     * Returns the node right next to the head, which contains the first element of this queue.
     */

    @Override
    @SuppressWarnings("unchecked")
    public boolean offer(E value) {
        if (value == null) {
            throw new NullPointerException("value");
        }
        if (count.get() > size)
            return false;
        final MpscLinkedQueueNode<E> newTail;
        if (value instanceof MpscLinkedQueueNode) {
            newTail = (MpscLinkedQueueNode<E>) value;
            newTail.setNext(null);
        } else {
            newTail = new DefaultNode<E>(value);
        }
        MpscLinkedQueueNode<E> oldTail = getAndSetTailRef(newTail);
        oldTail.setNext(newTail);
        count.incrementAndGet();
        return true;
    }

    @Override
    public E poll() {
        final MpscLinkedQueueNode<E> next = peekNode();
        if (next == null) {
            return null;
        }
        // next becomes a new head.
        MpscLinkedQueueNode<E> oldHead = headRef();
        // Similar to 'headRef.node = next', but slightly faster (storestore vs loadstore)
        lazySetHeadRef(next);
        // Break the linkage between the old head and the new head.
        oldHead.unlink();
        count.decrementAndGet();
        return next.clearMaybe();
    }

    public int drainTo(Collection<E> items, int size) {
        int index = 0;
        while (index < size) {
            E item = poll();
            if (item == null)
                break;
            items.add(item);
            ++index;
        }
        return index;
    }

    @Override
    public E peek() {
        final MpscLinkedQueueNode<E> next = peekNode();
        if (next == null) {
            return null;
        }
        return next.value();
    }

    @Override
    public int size() {
        int count = 0;
        MpscLinkedQueueNode<E> n = peekNode();
        for (; ; ) {
            if (n == null) {
                break;
            }
            count++;
            n = n.next();
        }
        return count;
    }

    public int SIZE() {
        return count.get();
    }

    @Override
    public boolean isEmpty() {
        return peekNode() == null;
    }

    @Override
    public boolean contains(Object o) {
        MpscLinkedQueueNode<E> n = peekNode();
        for (; ; ) {
            if (n == null) {
                break;
            }
            if (n.value() == o) {
                return true;
            }
            n = n.next();
        }
        return false;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {

            private MpscLinkedQueueNode<E> node = peekNode();

            @Override
            public boolean hasNext() {
                return node != null;
            }

            @Override
            public E next() {
                MpscLinkedQueueNode<E> node = this.node;
                if (node == null) {
                    throw new NoSuchElementException();
                }
                E value = node.value();
                this.node = node.next();
                return value;
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }

    @Override
    public boolean add(E e) {
        if (offer(e)) {
            return true;
        }
        throw new IllegalStateException("queue full");
    }

    @Override
    public E remove() {
        E e = poll();
        if (e != null) {
            return e;
        }
        throw new NoSuchElementException();
    }

    @Override
    public E element() {
        E e = peek();
        if (e != null) {
            return e;
        }
        throw new NoSuchElementException();
    }

    @Override
    public Object[] toArray() {
        final Object[] array = new Object[size()];
        final Iterator<E> it = iterator();
        for (int i = 0; i < array.length; i++) {
            if (it.hasNext()) {
                array[i] = it.next();
            } else {
                return Arrays.copyOf(array, i);
            }
        }
        return array;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        final int size = size();
        final T[] array;
        if (a.length >= size) {
            array = a;
        } else {
            array = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
        }
        final Iterator<E> it = iterator();
        for (int i = 0; i < array.length; i++) {
            if (it.hasNext()) {
                array[i] = (T) it.next();
            } else {
                if (a == array) {
                    array[i] = null;
                    return array;
                }
                if (a.length < i) {
                    return Arrays.copyOf(array, i);
                }
                System.arraycopy(array, 0, a, 0, i);
                if (a.length > i) {
                    a[i] = null;
                }
                return a;
            }
        }
        return array;
    }

    @Override
    public boolean remove(Object o) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        for (Object e : c) {
            if (!contains(e)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        if (c == null) {
            throw new NullPointerException("c");
        }
        if (c == this) {
            throw new IllegalArgumentException("c == this");
        }
        boolean modified = false;
        for (E e : c) {
            add(e);
            modified = true;
        }
        return modified;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void clear() {
        while (poll() != null) {
            continue;
        }
    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        for (E e : this) {
            out.writeObject(e);
        }
        out.writeObject(null);
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        final MpscLinkedQueueNode<E> tombstone = new DefaultNode<E>(null);
        setHeadRef(tombstone);
        setTailRef(tombstone);
        for (; ; ) {
            @SuppressWarnings("unchecked")
            E e = (E) in.readObject();
            if (e == null) {
                break;
            }
            add(e);
        }
    }

    private static final class DefaultNode<T> extends MpscLinkedQueueNode<T> {

        private T value;

        DefaultNode(T value) {
            this.value = value;
        }

        @Override
        public T value() {
            return value;
        }

        @Override
        protected T clearMaybe() {
            T value = this.value;
            this.value = null;
            return value;
        }
    }
}


for (int i = 0; i < array.length; i++) {
            if (it.hasNext()) {
                array[i] = it.next();
            } else {
                return Arrays.copyOf(array, i);
            }
        }

package qunar.tc.qmq.batch;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * A lock-free concurrent single-consumer multi-producer {@link java.util.Queue}.
 * It allows multiple producer threads to perform the following operations simultaneously:
 *

 *
{@link #offer(Object)}, {@link #add(Object)}, and {@link #addAll(java.util.Collection)}

 *
All other read-only operations:
 *

 *
{@link #contains(Object)} and {@link #containsAll(java.util.Collection)}

 *
{@link #element()}, {@link #peek()}

 *
{@link #size()} and {@link #isEmpty()}

 *
{@link #iterator()} (except {@link java.util.Iterator#remove()}

 *
{@link #toArray()} and {@link #toArray(Object[])}

 *

 *

 *

 * .. while only one consumer thread is allowed to perform the following operations exclusively:
 *

 *
{@link #poll()} and {@link #remove()}

 *
{@link #remove(Object)}, {@link #removeAll(java.util.Collection)}, and {@link #retainAll(java.util.Collection)}

 *
{@link #clear()}
 {@link #}
 *

 *

 * The behavior of this implementation is undefined if you perform the operations for a consumer thread only
 * from multiple threads.
 *

 * The initial implementation is based on:
 *

 *
Non-intrusive MPSC node based queue from 1024cores.net

 *
AbstractNodeQueue from Akka

 *

 * and adopted padded head node changes from:
 *

 *
MpscPaddedQueue from RxJava

 *

 */
final class MpscLinkedQueue<E> extends MpscLinkedQueueTailRef<E> implements Queue<E> {

    private static final long serialVersionUID = -1878402552271506449L;

    long p00, p01, p02, p03, p04, p05, p06, p07;

    long p30, p31, p32, p33, p34, p35, p36, p37;

    // offer() occurs at the tail of the linked list.
    // poll() occurs at the head of the linked list.
    // Resulting layout is:
    // where the head is a dummy node whose value is null.
    // offer() appends a new node next to the tail using AtomicReference.getAndSet()
    // poll() removes head from the linked list and promotes the 1st element to the head,
    // setting its value to null if possible.
    // Also note that this class extends AtomicReference for the "tail" slot (which is the one that is appended to)
    // since Unsafe does not expose XCHG operation intrinsically.
    private final AtomicInteger count = new AtomicInteger();

    private final int size;

    public MpscLinkedQueue(int size) {
        this.size = size;
        MpscLinkedQueueNode<E> tombstone = new DefaultNode<E>(null);
        setHeadRef(tombstone);
        setTailRef(tombstone);
    }

    /**
     * Returns the node right next to the head, which contains the first element of this queue.
     */
    private MpscLinkedQueueNode<E> peekNode() {
        MpscLinkedQueueNode<E> head = headRef();
        MpscLinkedQueueNode<E> next = head.next();
        if (next == null && head != tailRef()) {
            // if tail != head this is not going to change until consumer makes progress
            // we can avoid reading the head and just spin on next until it shows up
            do {
                next = head.next();
            } while (next == null);
        }
        return next;
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean offer(E value) {
        if (value == null) {
            throw new NullPointerException("value");
        }
        if (count.get() > size)
            return false;
        final MpscLinkedQueueNode<E> newTail;
        if (value instanceof MpscLinkedQueueNode) {
            newTail = (MpscLinkedQueueNode<E>) value;
            newTail.setNext(null);
        } else {
            newTail = new DefaultNode<E>(value);
        }
        MpscLinkedQueueNode<E> oldTail = getAndSetTailRef(newTail);
        oldTail.setNext(newTail);
        count.incrementAndGet();
        return true;
    }

    @Override
    public E poll() {
        final MpscLinkedQueueNode<E> next = peekNode();
        if (next == null) {
            return null;
        }
        // next becomes a new head.
        MpscLinkedQueueNode<E> oldHead = headRef();
        // Similar to 'headRef.node = next', but slightly faster (storestore vs loadstore)
        lazySetHeadRef(next);
        // Break the linkage between the old head and the new head.
        oldHead.unlink();
        count.decrementAndGet();
        return next.clearMaybe();
    }

    public int drainTo(Collection<E> items, int size) {
        int index = 0;
        while (index < size) {
            E item = poll();
            if (item == null)
                break;
            items.add(item);
            ++index;
        }
        return index;
    }

    @Override
    public E peek() {
        final MpscLinkedQueueNode<E> next = peekNode();
        if (next == null) {
            return null;
        }
        return next.value();
    }

    @Override
    public int size() {
        int count = 0;
        MpscLinkedQueueNode<E> n = peekNode();
        for (; ; ) {
            if (n == null) {
                break;
            }
            count++;
            n = n.next();
        }
        return count;
    }

    public int SIZE() {
        return count.get();
    }

    @Override
    public boolean isEmpty() {
        return peekNode() == null;
    }

    @Override
    public boolean contains(Object o) {
        MpscLinkedQueueNode<E> n = peekNode();
        for (; ; ) {
            if (n == null) {
                break;
            }
            if (n.value() == o) {
                return true;
            }
            n = n.next();
        }
        return false;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {

            private MpscLinkedQueueNode<E> node = peekNode();

            @Override
            public boolean hasNext() {
                return node != null;
            }

            @Override
            public E next() {
                MpscLinkedQueueNode<E> node = this.node;
                if (node == null) {
                    throw new NoSuchElementException();
                }
                E value = node.value();
                this.node = node.next();
                return value;
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }

    @Override
    public boolean add(E e) {
        if (offer(e)) {
            return true;
        }
        throw new IllegalStateException("queue full");
    }

    @Override
    public E remove() {
        E e = poll();
        if (e != null) {
            return e;
        }
        throw new NoSuchElementException();
    }

    @Override
    public E element() {
        E e = peek();
        if (e != null) {
            return e;
        }
        throw new NoSuchElementException();
    }

    @Override
    public Object[] toArray() {
        final Object[] array = new Object[size()];
        final Iterator<E> it = iterator();

        return array;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        final int size = size();
        final T[] array;
        if (a.length >= size) {
            array = a;
        } else {
            array = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
        }
        final Iterator<E> it = iterator();
        for (int i = 0; i < array.length; i++) {
            if (it.hasNext()) {
                array[i] = (T) it.next();
            } else {
                if (a == array) {
                    array[i] = null;
                    return array;
                }
                if (a.length < i) {
                    return Arrays.copyOf(array, i);
                }
                System.arraycopy(array, 0, a, 0, i);
                if (a.length > i) {
                    a[i] = null;
                }
                return a;
            }
        }
        return array;
    }

    @Override
    public boolean remove(Object o) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        for (Object e : c) {
            if (!contains(e)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        if (c == null) {
            throw new NullPointerException("c");
        }
        if (c == this) {
            throw new IllegalArgumentException("c == this");
        }
        boolean modified = false;
        for (E e : c) {
            add(e);
            modified = true;
        }
        return modified;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void clear() {
        while (poll() != null) {
            continue;
        }
    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        for (E e : this) {
            out.writeObject(e);
        }
        out.writeObject(null);
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        final MpscLinkedQueueNode<E> tombstone = new DefaultNode<E>(null);
        setHeadRef(tombstone);
        setTailRef(tombstone);
        for (; ; ) {
            @SuppressWarnings("unchecked")
            E e = (E) in.readObject();
            if (e == null) {
                break;
            }
            add(e);
        }
    }

    private static final class DefaultNode<T> extends MpscLinkedQueueNode<T> {

        private T value;

        DefaultNode(T value) {
            this.value = value;
        }

        @Override
        public T value() {
            return value;
        }

        @Override
        protected T clearMaybe() {
            T value = this.value;
            this.value = null;
            return value;
        }
    }
}


while (poll() != null) {
            continue;
        }

package qunar.tc.qmq.batch;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * A lock-free concurrent single-consumer multi-producer {@link java.util.Queue}.
 * It allows multiple producer threads to perform the following operations simultaneously:
 *

 *
{@link #offer(Object)}, {@link #add(Object)}, and {@link #addAll(java.util.Collection)}

 *
All other read-only operations:
 *

 *
{@link #contains(Object)} and {@link #containsAll(java.util.Collection)}

 *
{@link #element()}, {@link #peek()}

 *
{@link #size()} and {@link #isEmpty()}

 *
{@link #iterator()} (except {@link java.util.Iterator#remove()}

 *
{@link #toArray()} and {@link #toArray(Object[])}

 *

 *

 *

 * .. while only one consumer thread is allowed to perform the following operations exclusively:
 *

 *
{@link #poll()} and {@link #remove()}

 *
{@link #remove(Object)}, {@link #removeAll(java.util.Collection)}, and {@link #retainAll(java.util.Collection)}

 *
{@link #clear()}
 {@link #}
 *

 *

 * The behavior of this implementation is undefined if you perform the operations for a consumer thread only
 * from multiple threads.
 *

 * The initial implementation is based on:
 *

 *
Non-intrusive MPSC node based queue from 1024cores.net

 *
AbstractNodeQueue from Akka

 *

 * and adopted padded head node changes from:
 *

 *
MpscPaddedQueue from RxJava

 *

 */
final class MpscLinkedQueue<E> extends MpscLinkedQueueTailRef<E> implements Queue<E> {

    private static final long serialVersionUID = -1878402552271506449L;

    long p00, p01, p02, p03, p04, p05, p06, p07;

    long p30, p31, p32, p33, p34, p35, p36, p37;

    // offer() occurs at the tail of the linked list.
    // poll() occurs at the head of the linked list.
    // Resulting layout is:
    // where the head is a dummy node whose value is null.
    // offer() appends a new node next to the tail using AtomicReference.getAndSet()
    // poll() removes head from the linked list and promotes the 1st element to the head,
    // setting its value to null if possible.
    // Also note that this class extends AtomicReference for the "tail" slot (which is the one that is appended to)
    // since Unsafe does not expose XCHG operation intrinsically.
    private final AtomicInteger count = new AtomicInteger();

    private final int size;

    public MpscLinkedQueue(int size) {
        this.size = size;
        MpscLinkedQueueNode<E> tombstone = new DefaultNode<E>(null);
        setHeadRef(tombstone);
        setTailRef(tombstone);
    }

    /**
     * Returns the node right next to the head, which contains the first element of this queue.
     */
    private MpscLinkedQueueNode<E> peekNode() {
        MpscLinkedQueueNode<E> head = headRef();
        MpscLinkedQueueNode<E> next = head.next();
        if (next == null && head != tailRef()) {
            // if tail != head this is not going to change until consumer makes progress
            // we can avoid reading the head and just spin on next until it shows up
            do {
                next = head.next();
            } while (next == null);
        }
        return next;
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean offer(E value) {
        if (value == null) {
            throw new NullPointerException("value");
        }
        if (count.get() > size)
            return false;
        final MpscLinkedQueueNode<E> newTail;
        if (value instanceof MpscLinkedQueueNode) {
            newTail = (MpscLinkedQueueNode<E>) value;
            newTail.setNext(null);
        } else {
            newTail = new DefaultNode<E>(value);
        }
        MpscLinkedQueueNode<E> oldTail = getAndSetTailRef(newTail);
        oldTail.setNext(newTail);
        count.incrementAndGet();
        return true;
    }

    @Override
    public E poll() {
        final MpscLinkedQueueNode<E> next = peekNode();
        if (next == null) {
            return null;
        }
        // next becomes a new head.
        MpscLinkedQueueNode<E> oldHead = headRef();
        // Similar to 'headRef.node = next', but slightly faster (storestore vs loadstore)
        lazySetHeadRef(next);
        // Break the linkage between the old head and the new head.
        oldHead.unlink();
        count.decrementAndGet();
        return next.clearMaybe();
    }

    public int drainTo(Collection<E> items, int size) {
        int index = 0;
        while (index < size) {
            E item = poll();
            if (item == null)
                break;
            items.add(item);
            ++index;
        }
        return index;
    }

    @Override
    public E peek() {
        final MpscLinkedQueueNode<E> next = peekNode();
        if (next == null) {
            return null;
        }
        return next.value();
    }

    @Override
    public int size() {
        int count = 0;
        MpscLinkedQueueNode<E> n = peekNode();
        for (; ; ) {
            if (n == null) {
                break;
            }
            count++;
            n = n.next();
        }
        return count;
    }

    public int SIZE() {
        return count.get();
    }

    @Override
    public boolean isEmpty() {
        return peekNode() == null;
    }

    @Override
    public boolean contains(Object o) {
        MpscLinkedQueueNode<E> n = peekNode();
        for (; ; ) {
            if (n == null) {
                break;
            }
            if (n.value() == o) {
                return true;
            }
            n = n.next();
        }
        return false;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {

            private MpscLinkedQueueNode<E> node = peekNode();

            @Override
            public boolean hasNext() {
                return node != null;
            }

            @Override
            public E next() {
                MpscLinkedQueueNode<E> node = this.node;
                if (node == null) {
                    throw new NoSuchElementException();
                }
                E value = node.value();
                this.node = node.next();
                return value;
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }

    @Override
    public boolean add(E e) {
        if (offer(e)) {
            return true;
        }
        throw new IllegalStateException("queue full");
    }

    @Override
    public E remove() {
        E e = poll();
        if (e != null) {
            return e;
        }
        throw new NoSuchElementException();
    }

    @Override
    public E element() {
        E e = peek();
        if (e != null) {
            return e;
        }
        throw new NoSuchElementException();
    }

    @Override
    public Object[] toArray() {
        final Object[] array = new Object[size()];
        final Iterator<E> it = iterator();
        for (int i = 0; i < array.length; i++) {
            if (it.hasNext()) {
                array[i] = it.next();
            } else {
                return Arrays.copyOf(array, i);
            }
        }
        return array;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        final int size = size();
        final T[] array;
        if (a.length >= size) {
            array = a;
        } else {
            array = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
        }
        final Iterator<E> it = iterator();
        for (int i = 0; i < array.length; i++) {
            if (it.hasNext()) {
                array[i] = (T) it.next();
            } else {
                if (a == array) {
                    array[i] = null;
                    return array;
                }
                if (a.length  i) {
                    a[i] = null;
                }
                return a;
            }
        }
        return array;
    }

    @Override
    public boolean remove(Object o) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        for (Object e : c) {
            if (!contains(e)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        if (c == null) {
            throw new NullPointerException("c");
        }
        if (c == this) {
            throw new IllegalArgumentException("c == this");
        }
        boolean modified = false;
        for (E e : c) {
            add(e);
            modified = true;
        }
        return modified;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void clear() {

    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        for (E e : this) {
            out.writeObject(e);
        }
        out.writeObject(null);
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        final MpscLinkedQueueNode<E> tombstone = new DefaultNode<E>(null);
        setHeadRef(tombstone);
        setTailRef(tombstone);
        for (; ; ) {
            @SuppressWarnings("unchecked")
            E e = (E) in.readObject();
            if (e == null) {
                break;
            }
            add(e);
        }
    }

    private static final class DefaultNode<T> extends MpscLinkedQueueNode<T> {

        private T value;

        DefaultNode(T value) {
            this.value = value;
        }

        @Override
        public T value() {
            return value;
        }

        @Override
        protected T clearMaybe() {
            T value = this.value;
            this.value = null;
            return value;
        }
    }
}


private static void setPlatformCache(BinaryRawReaderEx reader, IgniteCacheProxy cache) {
        if (reader.readBoolean())
            cache.context().cache().configuration().setPlatformCacheConfiguration(PlatformConfigurationUtils.readPlatformCacheConfiguration(reader));
    }

package org.apache.ignite.internal.processors.platform;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteAtomicSequence;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteDataStreamer;
import org.apache.ignite.IgniteException;
import org.apache.ignite.IgniteLock;
import org.apache.ignite.IgniteLogger;
import org.apache.ignite.cluster.BaselineNode;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.NearCacheConfiguration;
import org.apache.ignite.configuration.PlatformConfiguration;
import org.apache.ignite.internal.GridKernalContext;
import org.apache.ignite.internal.IgniteInternalFuture;
import org.apache.ignite.internal.binary.BinaryRawReaderEx;
import org.apache.ignite.internal.binary.BinaryRawWriterEx;
import org.apache.ignite.internal.cluster.DetachedClusterNode;
import org.apache.ignite.internal.logger.platform.PlatformLogger;
import org.apache.ignite.internal.processors.GridProcessorAdapter;
import org.apache.ignite.internal.processors.cache.IgniteCacheProxy;
import org.apache.ignite.internal.processors.datastreamer.DataStreamerImpl;
import org.apache.ignite.internal.processors.datastructures.GridCacheAtomicLongImpl;
import org.apache.ignite.internal.processors.platform.binary.PlatformBinaryProcessor;
import org.apache.ignite.internal.processors.platform.cache.PlatformCache;
import org.apache.ignite.internal.processors.platform.cache.PlatformCacheExtension;
import org.apache.ignite.internal.processors.platform.cache.PlatformCacheManager;
import org.apache.ignite.internal.processors.platform.cache.affinity.PlatformAffinity;
import org.apache.ignite.internal.processors.platform.cache.affinity.PlatformAffinityManager;
import org.apache.ignite.internal.processors.platform.cache.store.PlatformCacheStore;
import org.apache.ignite.internal.processors.platform.cluster.PlatformClusterGroup;
import org.apache.ignite.internal.processors.platform.datastreamer.PlatformDataStreamer;
import org.apache.ignite.internal.processors.platform.datastructures.PlatformAtomicLong;
import org.apache.ignite.internal.processors.platform.datastructures.PlatformAtomicReference;
import org.apache.ignite.internal.processors.platform.datastructures.PlatformAtomicSequence;
import org.apache.ignite.internal.processors.platform.dotnet.PlatformDotNetCacheStore;
import org.apache.ignite.internal.processors.platform.memory.PlatformMemory;
import org.apache.ignite.internal.processors.platform.memory.PlatformOutputStream;
import org.apache.ignite.internal.processors.platform.transactions.PlatformTransactions;
import org.apache.ignite.internal.processors.platform.utils.PlatformConfigurationUtils;
import org.apache.ignite.internal.processors.platform.utils.PlatformUtils;
import org.apache.ignite.internal.util.typedef.CI1;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteFuture;
import org.apache.ignite.lang.IgniteProductVersion;
import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.internal.processors.platform.PlatformAbstractTarget.FALSE;
import static org.apache.ignite.internal.processors.platform.PlatformAbstractTarget.TRUE;

@SuppressWarnings({ "unchecked", "rawtypes" })
public class PlatformProcessorImpl extends GridProcessorAdapter implements PlatformProcessor, PlatformTarget {

    private static final int OP_GET_CACHE = 1;

    private static final int OP_CREATE_CACHE = 2;

    private static final int OP_GET_OR_CREATE_CACHE = 3;

    private static final int OP_CREATE_CACHE_FROM_CONFIG = 4;

    private static final int OP_GET_OR_CREATE_CACHE_FROM_CONFIG = 5;

    private static final int OP_DESTROY_CACHE = 6;

    private static final int OP_GET_AFFINITY = 7;

    private static final int OP_GET_DATA_STREAMER = 8;

    private static final int OP_GET_TRANSACTIONS = 9;

    private static final int OP_GET_CLUSTER_GROUP = 10;

    private static final int OP_GET_EXTENSION = 11;

    private static final int OP_GET_ATOMIC_LONG = 12;

    private static final int OP_GET_ATOMIC_REFERENCE = 13;

    private static final int OP_GET_ATOMIC_SEQUENCE = 14;

    private static final int OP_GET_IGNITE_CONFIGURATION = 15;

    private static final int OP_GET_CACHE_NAMES = 16;

    private static final int OP_CREATE_NEAR_CACHE = 17;

    private static final int OP_GET_OR_CREATE_NEAR_CACHE = 18;

    private static final int OP_LOGGER_IS_LEVEL_ENABLED = 19;

    private static final int OP_LOGGER_LOG = 20;

    private static final int OP_GET_BINARY_PROCESSOR = 21;

    private static final int OP_RELEASE_START = 22;

    private static final int OP_ADD_CACHE_CONFIGURATION = 23;

    private static final int OP_SET_BASELINE_TOPOLOGY_VER = 24;

    private static final int OP_SET_BASELINE_TOPOLOGY_NODES = 25;

    private static final int OP_GET_BASELINE_TOPOLOGY = 26;

    private static final int OP_DISABLE_WAL = 27;

    private static final int OP_ENABLE_WAL = 28;

    private static final int OP_IS_WAL_ENABLED = 29;

    private static final int OP_SET_TX_TIMEOUT_ON_PME = 30;

    private static final int OP_NODE_VERSION = 31;

    private static final int OP_IS_BASELINE_AUTO_ADJ_ENABLED = 32;

    private static final int OP_SET_BASELINE_AUTO_ADJ_ENABLED = 33;

    private static final int OP_GET_BASELINE_AUTO_ADJ_TIMEOUT = 34;

    private static final int OP_SET_BASELINE_AUTO_ADJ_TIMEOUT = 35;

    private static final int OP_GET_CACHE_CONFIG = 36;

    private static final int OP_GET_THREAD_LOCAL = 37;

    private static final int OP_GET_OR_CREATE_LOCK = 38;

    private static final int OP_GET_AFFINITY_MANAGER = 39;

    /**
     * Start latch.
     */
    private final CountDownLatch startLatch = new CountDownLatch(1);

    /**
     * Stores pending initialization.
     */
    private final Collection<StoreInfo> pendingStores = Collections.newSetFromMap(new ConcurrentHashMap<StoreInfo, Boolean>());

    /**
     * Lock for store lifecycle operations.
     */
    private final ReadWriteLock storeLock = new ReentrantReadWriteLock();

    @SuppressWarnings("FieldCanBeLocal")
    private final IgniteLogger log;

    private final PlatformContext platformCtx;

    /**
     * Interop configuration.
     */
    private final PlatformConfigurationEx interopCfg;

    private final PlatformPluginExtension[] extensions;

    /**
     * Whether processor is started.
     */
    private boolean started;

    /**
     * Whether processor if stopped (or stopping).
     */
    private volatile boolean stopped;

    /**
     * Cache extensions.
     */
    private final PlatformCacheExtension[] cacheExts;

    /**
     * Cluster restart flag for the reconnect callback.
     */
    private volatile boolean clusterRestarted;

    /**
     * Thread local storage for platform needs.
     */
    private final ThreadLocal<Object> threadLocal = new ThreadLocal<>();

    /**
     * Constructor.
     *
     * @param ctx Kernal context.
     */
    public PlatformProcessorImpl(GridKernalContext ctx) {
        super(ctx);
        log = ctx.log(PlatformProcessorImpl.class);
        PlatformConfiguration interopCfg0 = ctx.config().getPlatformConfiguration();
        assert interopCfg0 != null : "Must be checked earlier during component creation.";
        if (!(interopCfg0 instanceof PlatformConfigurationEx))
            throw new IgniteException("Unsupported platform configuration: " + interopCfg0.getClass().getName());
        interopCfg = (PlatformConfigurationEx) interopCfg0;
        if (!F.isEmpty(interopCfg.warnings())) {
            for (String w : interopCfg.warnings()) U.warn(log, w);
        }
        platformCtx = new PlatformContextImpl(ctx, interopCfg.gate(), interopCfg.memory(), interopCfg.platform());
        // Initialize cache extensions (if any).
        cacheExts = prepareCacheExtensions(interopCfg.cacheExtensions());
        if (interopCfg.logger() != null)
            interopCfg.logger().setContext(platformCtx);
        extensions = prepareExtensions(ctx.plugins().extensions(PlatformPluginExtension.class));
    }

    @Override
    public void start() throws IgniteCheckedException {
        try (PlatformMemory mem = platformCtx.memory().allocate()) {
            PlatformOutputStream out = mem.output();
            BinaryRawWriterEx writer = platformCtx.writer(out);
            writer.writeString(ctx.igniteInstanceName());
            out.synchronize();
            platformCtx.gateway().onStart(new PlatformTargetProxyImpl(this, platformCtx), mem.pointer());
        }
        // At this moment all necessary native libraries must be loaded, so we can process with store creation.
        storeLock.writeLock().lock();
        try {
            for (StoreInfo store : pendingStores) registerStore0(store.store, store.convertBinary);
            pendingStores.clear();
            started = true;
        } finally {
            storeLock.writeLock().unlock();
        }
        // Add Interop node attributes.
        ctx.addNodeAttribute(PlatformUtils.ATTR_PLATFORM, interopCfg.platform());
        // Register query entity meta.
        ctx.query().registerMetadataForRegisteredCaches(true);
    }

    @Override
    public void onKernalStop(boolean cancel) {
        startLatch.countDown();
    }

    @Override
    public void stop(boolean cancel) throws IgniteCheckedException {
        if (platformCtx != null) {
            stopped = true;
            platformCtx.gateway().onStop();
        }
    }

    @Override
    public Ignite ignite() {
        return ctx.grid();
    }

    @Override
    public long environmentPointer() {
        return platformCtx.gateway().environmentPointer();
    }

    @Override
    public void releaseStart() {
        startLatch.countDown();
    }

    @Override
    public void awaitStart() throws IgniteCheckedException {
        U.await(startLatch);
    }

    @Override
    public PlatformContext context() {
        return platformCtx;
    }

    @Override
    public boolean hasContext() {
        return true;
    }

    @Override
    public void registerStore(PlatformCacheStore store, boolean convertBinary) throws IgniteCheckedException {
        storeLock.readLock().lock();
        try {
            if (stopped)
                throw new IgniteCheckedException("Failed to initialize interop store because node is stopping: " + store);
            if (started)
                registerStore0(store, convertBinary);
            else
                pendingStores.add(new StoreInfo(store, convertBinary));
        } finally {
            storeLock.readLock().unlock();
        }
    }

    @Override
    public PlatformCacheManager cacheManager() {
        return new PlatformCacheManager(platformCtx.gateway());
    }

    @Override
    public void onDisconnected(IgniteFuture<?> reconnectFut) throws IgniteCheckedException {
        platformCtx.gateway().onClientDisconnected();
        // 1) onReconnected is called on all grid components.
        // 2) After all of grid components have completed their reconnection, reconnectFut is completed.
        reconnectFut.listen(new CI1<IgniteFuture<?>>() {

            @Override
            public void apply(IgniteFuture<?> future) {
                platformCtx.gateway().onClientReconnected(clusterRestarted);
            }
        });
    }

    @Override
    public IgniteInternalFuture<?> onReconnected(boolean clusterRestarted) throws IgniteCheckedException {
        // Save the flag value for callback of reconnectFut.
        this.clusterRestarted = clusterRestarted;
        return null;
    }

    private PlatformTarget createPlatformCache(IgniteCacheProxy cache) {
        assert cache != null;
        return new PlatformCache(platformCtx, cache, false, cacheExts);
    }

    /**
     * Checks whether logger level is enabled.
     *
     * @param level Level.
     * @return Result.
     */
    private boolean loggerIsLevelEnabled(int level) {
        IgniteLogger log = ctx.grid().log();
        switch(level) {
            case PlatformLogger.LVL_TRACE:
                return log.isTraceEnabled();
            case PlatformLogger.LVL_DEBUG:
                return log.isDebugEnabled();
            case PlatformLogger.LVL_INFO:
                return log.isInfoEnabled();
            case PlatformLogger.LVL_WARN:
                return true;
            case PlatformLogger.LVL_ERROR:
                return true;
            default:
                assert false;
        }
        return false;
    }

    /**
     * Logs to the Ignite logger.
     *
     * @param level Level.
     * @param message Message.
     * @param category Category.
     * @param errorInfo Exception.
     */
    private void loggerLog(int level, String message, String category, String errorInfo) {
        IgniteLogger log = ctx.grid().log();
        if (category != null)
            log = log.getLogger(category);
        Throwable err = errorInfo == null ? null : new IgniteException("Platform error:" + errorInfo);
        switch(level) {
            case PlatformLogger.LVL_TRACE:
                log.trace(message);
                break;
            case PlatformLogger.LVL_DEBUG:
                log.debug(message);
                break;
            case PlatformLogger.LVL_INFO:
                log.info(message);
                break;
            case PlatformLogger.LVL_WARN:
                log.warning(message, err);
                break;
            case PlatformLogger.LVL_ERROR:
                log.error(message, err);
                break;
            default:
                assert false;
        }
    }

    @Override
    public long processInLongOutLong(int type, long val) throws IgniteCheckedException {
        switch(type) {
            case OP_LOGGER_IS_LEVEL_ENABLED:
                {
                    return loggerIsLevelEnabled((int) val) ? TRUE : FALSE;
                }
            case OP_RELEASE_START:
                {
                    releaseStart();
                    return 0;
                }
            case OP_SET_BASELINE_TOPOLOGY_VER:
                {
                    ctx.grid().cluster().setBaselineTopology(val);
                    return 0;
                }
            case OP_SET_BASELINE_AUTO_ADJ_TIMEOUT:
                {
                    ctx.grid().cluster().baselineAutoAdjustTimeout(val);
                    return 0;
                }
        }
        return PlatformAbstractTarget.throwUnsupported(type);
    }

    @Override
    public long processInStreamOutLong(int type, BinaryRawReaderEx reader) throws IgniteCheckedException {
        switch(type) {
            case OP_DESTROY_CACHE:
                {
                    ctx.grid().destroyCache(reader.readString());
                    return 0;
                }
            case OP_LOGGER_LOG:
                {
                    loggerLog(reader.readInt(), reader.readString(), reader.readString(), reader.readString());
                    return 0;
                }
            case OP_SET_BASELINE_TOPOLOGY_NODES:
                {
                    int cnt = reader.readInt();
                    Collection<BaselineNode> nodes = new ArrayList<>(cnt);
                    for (int i = 0; i < cnt; i++) {
                        Object consId = reader.readObjectDetached();
                        Map<String, Object> attrs = PlatformUtils.readNodeAttributes(reader);
                        nodes.add(new DetachedClusterNode(consId, attrs));
                    }
                    ctx.grid().cluster().setBaselineTopology(nodes);
                    return 0;
                }
            case OP_ADD_CACHE_CONFIGURATION:
                CacheConfiguration cfg = PlatformConfigurationUtils.readCacheConfiguration(reader);
                ctx.grid().addCacheConfiguration(cfg);
                return 0;
            case OP_DISABLE_WAL:
                ctx.grid().cluster().disableWal(reader.readString());
                return 0;
            case OP_ENABLE_WAL:
                ctx.grid().cluster().enableWal(reader.readString());
                return 0;
            case OP_SET_TX_TIMEOUT_ON_PME:
                ctx.grid().cluster().setTxTimeoutOnPartitionMapExchange(reader.readLong());
                return 0;
            case OP_IS_WAL_ENABLED:
                return ctx.grid().cluster().isWalEnabled(reader.readString()) ? TRUE : FALSE;
            case OP_IS_BASELINE_AUTO_ADJ_ENABLED:
                return ctx.grid().cluster().isBaselineAutoAdjustEnabled() ? TRUE : FALSE;
            case OP_SET_BASELINE_AUTO_ADJ_ENABLED:
                boolean isEnabled = reader.readBoolean();
                ctx.grid().cluster().baselineAutoAdjustEnabled(isEnabled);
                return 0;
            case OP_GET_BASELINE_AUTO_ADJ_TIMEOUT:
                return ctx.grid().cluster().baselineAutoAdjustTimeout();
        }
        return PlatformAbstractTarget.throwUnsupported(type);
    }

    @Override
    public long processInStreamOutLong(int type, BinaryRawReaderEx reader, PlatformMemory mem) throws IgniteCheckedException {
        return processInStreamOutLong(type, reader);
    }

    @Override
    public void processInStreamOutStream(int type, BinaryRawReaderEx reader, BinaryRawWriterEx writer) throws IgniteCheckedException {
        if (type == OP_GET_CACHE_CONFIG) {
            int cacheId = reader.readInt();
            CacheConfiguration cfg = ctx.cache().cacheDescriptor(cacheId).cacheConfiguration();
            PlatformConfigurationUtils.writeCacheConfiguration(writer, cfg);
            return;
        }
        PlatformAbstractTarget.throwUnsupported(type);
    }

    @Override
    public PlatformTarget processInStreamOutObject(int type, BinaryRawReaderEx reader) throws IgniteCheckedException {
        switch(type) {
            case OP_GET_CACHE:
                {
                    String name = reader.readString();
                    IgniteCacheProxy cache = (IgniteCacheProxy) ctx.grid().cache(name);
                    if (cache == null)
                        throw new IllegalArgumentException("Cache doesn't exist: " + name);
                    return createPlatformCache(cache);
                }
            case OP_CREATE_CACHE:
                {
                    String name = reader.readString();
                    IgniteCacheProxy cache = (IgniteCacheProxy) ctx.grid().createCache(name);
                    return createPlatformCache(cache);
                }
            case OP_GET_OR_CREATE_CACHE:
                {
                    String name = reader.readString();
                    IgniteCacheProxy cache = (IgniteCacheProxy) ctx.grid().getOrCreateCache(name);
                    return createPlatformCache(cache);
                }
            case OP_CREATE_CACHE_FROM_CONFIG:
                {
                    CacheConfiguration cfg = PlatformConfigurationUtils.readCacheConfiguration(reader);
                    IgniteCacheProxy cache = reader.readBoolean() ? (IgniteCacheProxy) ctx.grid().createCache(cfg, PlatformConfigurationUtils.readNearConfiguration(reader)) : (IgniteCacheProxy) ctx.grid().createCache(cfg);
                    setPlatformCache(reader, cache);
                    return createPlatformCache(cache);
                }
            case OP_GET_OR_CREATE_CACHE_FROM_CONFIG:
                {
                    CacheConfiguration cfg = PlatformConfigurationUtils.readCacheConfiguration(reader);
                    IgniteCacheProxy cache = reader.readBoolean() ? (IgniteCacheProxy) ctx.grid().getOrCreateCache(cfg, PlatformConfigurationUtils.readNearConfiguration(reader)) : (IgniteCacheProxy) ctx.grid().getOrCreateCache(cfg);
                    setPlatformCache(reader, cache);
                    return createPlatformCache(cache);
                }
            case OP_GET_AFFINITY:
                {
                    return new PlatformAffinity(platformCtx, reader.readString());
                }
            case OP_GET_DATA_STREAMER:
                {
                    String cacheName = reader.readString();
                    boolean keepBinary = reader.readBoolean();
                    IgniteDataStreamer ldr = ctx.dataStream().dataStreamer(cacheName);
                    ldr.keepBinary(true);
                    return new PlatformDataStreamer(platformCtx, cacheName, (DataStreamerImpl) ldr, keepBinary);
                }
            case OP_GET_EXTENSION:
                {
                    int id = reader.readInt();
                    if (extensions != null && id < extensions.length) {
                        PlatformPluginExtension ext = extensions[id];
                        if (ext != null) {
                            return ext.createTarget();
                        }
                    }
                    throw new IgniteException("Platform extension is not registered [id=" + id + ']');
                }
            case OP_GET_ATOMIC_LONG:
                {
                    String name = reader.readString();
                    long initVal = reader.readLong();
                    boolean create = reader.readBoolean();
                    GridCacheAtomicLongImpl atomicLong = (GridCacheAtomicLongImpl) ignite().atomicLong(name, initVal, create);
                    if (atomicLong == null)
                        return null;
                    return new PlatformAtomicLong(platformCtx, atomicLong);
                }
            case OP_GET_ATOMIC_REFERENCE:
                {
                    String name = reader.readString();
                    Object initVal = reader.readObjectDetached();
                    boolean create = reader.readBoolean();
                    return PlatformAtomicReference.createInstance(platformCtx, name, initVal, create);
                }
            case OP_GET_ATOMIC_SEQUENCE:
                {
                    String name = reader.readString();
                    long initVal = reader.readLong();
                    boolean create = reader.readBoolean();
                    IgniteAtomicSequence atomicSeq = ignite().atomicSequence(name, initVal, create);
                    if (atomicSeq == null)
                        return null;
                    return new PlatformAtomicSequence(platformCtx, atomicSeq);
                }
            case OP_CREATE_NEAR_CACHE:
                {
                    String cacheName = reader.readString();
                    NearCacheConfiguration cfg = PlatformConfigurationUtils.readNearConfiguration(reader);
                    IgniteCacheProxy cache = (IgniteCacheProxy) ctx.grid().createNearCache(cacheName, cfg);
                    setPlatformCache(reader, cache);
                    return createPlatformCache(cache);
                }
            case OP_GET_OR_CREATE_NEAR_CACHE:
                {
                    String cacheName = reader.readString();
                    NearCacheConfiguration cfg = PlatformConfigurationUtils.readNearConfiguration(reader);
                    IgniteCacheProxy cache = (IgniteCacheProxy) ctx.grid().getOrCreateNearCache(cacheName, cfg);
                    setPlatformCache(reader, cache);
                    return createPlatformCache(cache);
                }
            case OP_GET_TRANSACTIONS:
                {
                    String lbl = reader.readString();
                    return new PlatformTransactions(platformCtx, lbl);
                }
            case OP_GET_OR_CREATE_LOCK:
                {
                    String name = reader.readString();
                    boolean failoverSafe = reader.readBoolean();
                    boolean fair = reader.readBoolean();
                    boolean create = reader.readBoolean();
                    IgniteLock lock = ctx.grid().reentrantLock(name, failoverSafe, fair, create);
                    return lock == null ? null : new PlatformLock(platformCtx, lock);
                }
            case OP_GET_AFFINITY_MANAGER:
                {
                    int cacheId = reader.readInt();
                    return new PlatformAffinityManager(platformCtx, cacheId);
                }
        }
        return PlatformAbstractTarget.throwUnsupported(type);
    }

    @Override
    public PlatformTarget processInObjectStreamOutObjectStream(int type, @Nullable PlatformTarget arg, BinaryRawReaderEx reader, BinaryRawWriterEx writer) throws IgniteCheckedException {
        return PlatformAbstractTarget.throwUnsupported(type);
    }

    @Override
    public void processOutStream(int type, BinaryRawWriterEx writer) throws IgniteCheckedException {
        switch(type) {
            case OP_GET_IGNITE_CONFIGURATION:
                {
                    PlatformConfigurationUtils.writeIgniteConfiguration(writer, ignite().configuration());
                    return;
                }
            case OP_GET_CACHE_NAMES:
                {
                    Collection<String> names = ignite().cacheNames();
                    writer.writeInt(names.size());
                    for (String name : names) writer.writeString(name);
                    return;
                }
            case OP_GET_BASELINE_TOPOLOGY:
                {
                    Collection<BaselineNode> blt = ignite().cluster().currentBaselineTopology();
                    writer.writeInt(blt.size());
                    for (BaselineNode n : blt) {
                        writer.writeObjectDetached(n.consistentId());
                        PlatformUtils.writeNodeAttributes(writer, n.attributes());
                    }
                    return;
                }
            case OP_NODE_VERSION:
                {
                    IgniteProductVersion productVersion = ignite().cluster().node().version();
                    PlatformUtils.writeNodeVersion(writer, productVersion);
                    return;
                }
            case OP_GET_THREAD_LOCAL:
                {
                    writer.writeObjectDetached(threadLocal.get());
                    return;
                }
        }
        PlatformAbstractTarget.throwUnsupported(type);
    }

    @Override
    public PlatformTarget processOutObject(int type) throws IgniteCheckedException {
        switch(type) {
            case OP_GET_TRANSACTIONS:
                return new PlatformTransactions(platformCtx);
            case OP_GET_CLUSTER_GROUP:
                return new PlatformClusterGroup(platformCtx, ctx.grid().cluster());
            case OP_GET_BINARY_PROCESSOR:
                {
                    return new PlatformBinaryProcessor(platformCtx);
                }
        }
        return PlatformAbstractTarget.throwUnsupported(type);
    }

    @Override
    public PlatformAsyncResult processInStreamAsync(int type, BinaryRawReaderEx reader) throws IgniteCheckedException {
        return PlatformAbstractTarget.throwUnsupported(type);
    }

    @Override
    public Exception convertException(Exception e) {
        return e;
    }

    @Override
    public void setThreadLocal(Object value) {
        threadLocal.set(value);
    }

    /**
     * Internal store initialization routine.
     *
     * @param store Store.
     * @param convertBinary Convert binary flag.
     * @throws IgniteCheckedException If failed.
     */
    private void registerStore0(PlatformCacheStore store, boolean convertBinary) throws IgniteCheckedException {
        if (store instanceof PlatformDotNetCacheStore) {
            PlatformDotNetCacheStore store0 = (PlatformDotNetCacheStore) store;
            store0.initialize(ctx, convertBinary);
        } else
            throw new IgniteCheckedException("Unsupported interop store: " + store);
    }

    /**
     * Sets platform cache config when present in the given reader.
     *
     * @param reader Reader.
     * @param cache Cache.
     */

    /**
     * Prepare cache extensions.
     *
     * @param cacheExts Original extensions.
     * @return Prepared extensions.
     */
    private static PlatformCacheExtension[] prepareCacheExtensions(Collection<PlatformCacheExtension> cacheExts) {
        if (!F.isEmpty(cacheExts)) {
            int maxExtId = 0;
            Map<Integer, PlatformCacheExtension> idToExt = new HashMap<>();
            for (PlatformCacheExtension cacheExt : cacheExts) {
                if (cacheExt == null)
                    throw new IgniteException("Platform cache extension cannot be null.");
                if (cacheExt.id() < 0)
                    throw new IgniteException("Platform cache extension ID cannot be negative: " + cacheExt);
                PlatformCacheExtension oldCacheExt = idToExt.put(cacheExt.id(), cacheExt);
                if (oldCacheExt != null)
                    throw new IgniteException("Platform cache extensions cannot have the same ID [" + "id=" + cacheExt.id() + ", first=" + oldCacheExt + ", second=" + cacheExt + ']');
                if (cacheExt.id() > maxExtId)
                    maxExtId = cacheExt.id();
            }
            PlatformCacheExtension[] res = new PlatformCacheExtension[maxExtId + 1];
            for (PlatformCacheExtension cacheExt : cacheExts) res[cacheExt.id()] = cacheExt;
            return res;
        } else
            // noinspection ZeroLengthArrayAllocation
            return new PlatformCacheExtension[0];
    }

    /**
     * Prepare extensions.
     *
     * @param exts Original extensions.
     * @return Prepared extensions.
     */
    private static PlatformPluginExtension[] prepareExtensions(PlatformPluginExtension[] exts) {
        if (!F.isEmpty(exts)) {
            int maxExtId = 0;
            Map<Integer, PlatformPluginExtension> idToExt = new HashMap<>();
            for (PlatformPluginExtension ext : exts) {
                if (ext == null)
                    throw new IgniteException("Platform extension cannot be null.");
                if (ext.id() < 0)
                    throw new IgniteException("Platform extension ID cannot be negative: " + ext);
                PlatformPluginExtension oldCacheExt = idToExt.put(ext.id(), ext);
                if (oldCacheExt != null)
                    throw new IgniteException("Platform extensions cannot have the same ID [" + "id=" + ext.id() + ", first=" + oldCacheExt + ", second=" + ext + ']');
                if (ext.id() > maxExtId)
                    maxExtId = ext.id();
            }
            PlatformPluginExtension[] res = new PlatformPluginExtension[maxExtId + 1];
            for (PlatformPluginExtension ext : exts) res[ext.id()] = ext;
            return res;
        } else
            // noinspection ZeroLengthArrayAllocation
            return new PlatformPluginExtension[0];
    }

    /**
     * Store and manager pair.
     */
    private static class StoreInfo {

        private final PlatformCacheStore store;

        /**
         * Convert binary flag.
         */
        private final boolean convertBinary;

        /**
         * Constructor.
         *
         * @param store Store.
         * @param convertBinary Convert binary flag.
         */
        private StoreInfo(PlatformCacheStore store, boolean convertBinary) {
            this.store = store;
            this.convertBinary = convertBinary;
        }
    }
}