edu.umass.cs.gnsserver.activecode.ActiveCodeHandler.java Source code

Java tutorial

Introduction

Here is the source code for edu.umass.cs.gnsserver.activecode.ActiveCodeHandler.java

Source

/*
 *
 *  Copyright (c) 2015 University of Massachusetts
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you
 *  may not use this file except in compliance with the License. You
 *  may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 *  implied. See the License for the specific language governing
 *  permissions and limitations under the License.
 *
 *  Initial developer(s): Misha Badov, Westy
 *
 */
package edu.umass.cs.gnsserver.activecode;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.codec.binary.Base64;

import edu.umass.cs.gnsserver.activecode.protocol.ActiveCodeParams;
import edu.umass.cs.gnscommon.exceptions.server.FieldNotFoundException;
import edu.umass.cs.gnsserver.gnsapp.GNSApplicationInterface;
import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commandSupport.ActiveCode;
import edu.umass.cs.gnsserver.gnsapp.recordmap.NameRecord;
import edu.umass.cs.gnsserver.utils.ValuesMap;

/**
 * This class is the entry of activecode, it provides
 * the interface for GNS to run active code. It's creates
 * a threadpool to connect the real isolated active worker
 * to run active code. It also handles the misbehaviours.
 *
 * @author Zhaoyu Gao, Westy
 */
public class ActiveCodeHandler {

    private final ClientPool clientPool;
    private final ThreadPoolExecutor executorPool;
    private final Map<String, Long> blacklist;
    private final long blacklistSeconds;

    protected static final int NANOSECONDS_PER_SEC = 1000000000;

    /**
     * Initializes an ActiveCodeHandler
     *
     * @param app
     * @param numProcesses
     * @param blacklistSeconds
     */
    public ActiveCodeHandler(GNSApplicationInterface<?> app, int numProcesses, long blacklistSeconds) {
        clientPool = new ClientPool(app);
        // Get the ThreadFactory implementation to use
        ThreadFactory threadFactory = new ActiveCodeThreadFactory(clientPool);
        // Create the ThreadPoolExecutor
        executorPool = new ActiveCodeExecutor(numProcesses, numProcesses, 0, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(100),
                // new SynchronousQueue<Runnable>(),
                threadFactory, new ThreadPoolExecutor.DiscardPolicy());
        // Start the processes
        executorPool.prestartAllCoreThreads();
        // Blacklist init
        blacklist = new HashMap<>();
        this.blacklistSeconds = blacklistSeconds;
    }

    /**
     * Checks to see if this guid has active code for the specified action.
     *
     * @param nameRecord
     * @param action can be 'read' or 'write'
     * @return whether or not there is active code
     */
    public boolean hasCode(NameRecord nameRecord, String action) {
        try {
            return nameRecord.getValuesMap().has(ActiveCode.getCodeField(action));
        } catch (FieldNotFoundException e) {
            return false;
        }
    }

    /**
     * Checks to see if all of the workers are busy.
     *
     * @return true if all workers are busy
     */
    public boolean isPoolBusy() {
        return executorPool.getActiveCount() == executorPool.getMaximumPoolSize();
    }

    /**
     * Checks to see if the guid is currently blacklisted.
     *
     * @param guid
     * @return true if the guid is blacklisted
     */
    public boolean isBlacklisted(String guid) {
        if (!blacklist.containsKey(guid)) {
            return false;
        }

        long blacklistedAt = blacklist.get(guid);

        return (System.nanoTime() - blacklistedAt) < (blacklistSeconds * NANOSECONDS_PER_SEC);
    }

    /**
     * Adds the guid to the blacklist
     *
     * @param guid
     */
    public void addToBlacklist(String guid) {
        blacklist.put(guid, System.nanoTime());
    }

    /**
     * Runs the active code. Returns a {@link ValuesMap}.
     *
     * @param code64 base64 encoded active code, as stored in the db
     * @param guid the guid
     * @param field the field
     * @param action either 'read' or 'write'
     * @param valuesMap
     * @param activeCodeTTL the remaining active code TTL
     * @return a Valuesmap
     */
    public ValuesMap runCode(String code64, String guid, String field, String action, ValuesMap valuesMap,
            int activeCodeTTL) {
        String code = new String(Base64.decodeBase64(code64));
        String values = valuesMap.toString();
        ValuesMap result = null;

        ActiveCodeParams acp = new ActiveCodeParams(guid, field, action, code, values, activeCodeTTL);
        FutureTask<ValuesMap> futureTask = new FutureTask<>(new ActiveCodeTask(acp, clientPool));

        // If the guid is blacklisted, just return immediately
        if (isBlacklisted(guid)) {
            System.out.println("Guid " + guid + " is blacklisted from running code!");
            return valuesMap;
        }

        // Only run if there are free workers and queue space
        // This prevents excessive CPU usage
        if (executorPool.getPoolSize() > 0 && executorPool.getQueue().remainingCapacity() > 0) {
            executorPool.execute(futureTask);

            try {
                result = futureTask.get();
            } catch (ExecutionException e) {
                System.out.println("Added " + guid + " to blacklist!");
                addToBlacklist(guid);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("Rejecting task!");
        }

        return result;
    }
}