/*
 * Copyright (c) 2013-2016 Cinchapi Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.cinchapi.concourse.server.plugin;

import java.nio.ByteBuffer;
import java.util.concurrent.ConcurrentMap;

import javax.annotation.Nullable;

import com.cinchapi.concourse.server.plugin.io.SharedMemory;
import com.cinchapi.concourse.thrift.AccessToken;
import com.cinchapi.concourse.thrift.ComplexTObject;
import com.cinchapi.concourse.thrift.TransactionToken;
import com.cinchapi.concourse.util.ByteBuffers;
import com.cinchapi.concourse.util.Reflection;
import com.cinchapi.concourse.util.Serializables;

/**
 * A daemon {@link Thread} that is responsible for processing a
 * {@link RemoteMethodRequest} and sending a {@link RemoteMethodResponse} on
 * the appropriate {@link SharedMemory channel}.
 * 
 * @author Jeff Nelson
 */
final class RemoteInvocationThread extends Thread {

    /**
     * The request that is being processed by this thread.
     */
    private final RemoteMethodRequest request;

    /**
     * The {@link SharedMemory} segment that is used for broadcasting the
     * response.
     */
    private final SharedMemory responseChannel;

    /**
     * The {@link SharedMemory} segment that is used for brodcasting upstream
     * requests.
     */
    private final SharedMemory requestChannel;

    /**
     * The local object that contains the methods to invoke.
     */
    private final Object invokable;

    /**
     * A flag that indicates whether thrift arguments should be passed when
     * invoking a local method on behalf of a remote request.
     */
    private final boolean useLocalThriftArgs;

    /**
     * A collection of responses from the upstream service. Made available for
     * async processing.
     */
    protected final ConcurrentMap<AccessToken, RemoteMethodResponse> responses;

    /**
     * Construct a new instance.
     * 
     * @param request
     * @param responseChannel
     * @param invokable
     * @param useLocalThriftArgs
     * @param responses
     */
    public RemoteInvocationThread(RemoteMethodRequest request,
            SharedMemory responseChannel, SharedMemory requestChannel,
            Object invokable, boolean useLocalThriftArgs,
            ConcurrentMap<AccessToken, RemoteMethodResponse> responses) {
        this.request = request;
        this.responseChannel = responseChannel;
        this.requestChannel = requestChannel;
        this.invokable = invokable;
        this.useLocalThriftArgs = useLocalThriftArgs;
        this.responses = responses;
        setDaemon(true);
    }

    /**
     * Return the {@link AccessToken} associated with the user session that owns
     * this thread.
     * 
     * @return the associated {@link AccessToken}
     */
    public AccessToken accessToken() {
        return request.creds;
    }

    /**
     * Return the name of the most recent environment associated with the user
     * session that owns this thread.
     * 
     * @return the environment
     */
    public String environment() {
        return request.environment;
    }

    /**
     * Return the {@link SharedMemory} segment that is used to send any upstream
     * {@link RemoteMethodRequest requests}.
     * 
     * @return the request channel
     */
    public SharedMemory requestChannel() {
        return requestChannel;
    }

    /**
     * Return the most recent {@link TransactionToken} associated with the user
     * session that owns this thread.
     * 
     * @return the {@link TransactionToken}
     */
    @Nullable
    public TransactionToken transactionToken() {
        return request.transaction;
    }

    @Override
    public final void run() {
        int argCount = request.args.size() + (useLocalThriftArgs ? 3 : 0);
        Object[] jargs = new Object[argCount];
        int i = 0;
        for (; i < request.args.size(); ++i) {
            jargs[i] = request.args.get(i).getJavaObject();
        }
        if(useLocalThriftArgs) {
            jargs[i + 1] = request.creds;
            jargs[i + 2] = request.transaction;
            jargs[i + 3] = request.environment;
        }
        RemoteMethodResponse response = null;
        try {
            Object rawResult = Reflection.callIfAccessible(invokable,
                    request.method, jargs);
            ComplexTObject result = ComplexTObject.fromJavaObject(rawResult);
            response = new RemoteMethodResponse(request.creds, result);
        }
        catch (Exception e) {
            response = new RemoteMethodResponse(request.creds, e);
        }
        ByteBuffer responseBytes = Serializables.getBytes(response);
        ByteBuffer message = ByteBuffer.allocate(responseBytes.capacity() + 4);
        message.putInt(Plugin.Instruction.RESPONSE.ordinal());
        message.put(responseBytes);
        responseChannel.write(ByteBuffers.rewind(message));
    }

}

@@ -4735,35 +4735,190 @@
 tion
-.callIfAccessible(invokable
+%0A                    .callIf((method) -%3E method.isAccessible()%0A                            && !method%0A                                    .isAnnotationPresent(PluginRestricted.class)
 ,%0A  
@@ -4934,16 +4934,35 @@
         
+         invokable,
  request

Add logic to check for PluginRestricted annotation on methods when invoking server methods