com.silica.Silica.java Source code

Java tutorial

Introduction

Here is the source code for com.silica.Silica.java

Source

/**
 *    Copyright (C) 2011 sndyuk
 *
 *    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.silica;

import java.io.IOException;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.silica.job.Callback;
import com.silica.job.Job;
import com.silica.job.JobExecutor;
import com.silica.rpc.server.Server;
import com.silica.rpc.server.ServerSelector;
import com.silica.service.Service;
import com.silica.service.ServiceException;

/**
 * Silica
 * <p>
 * ???
 * </p>
 */
public final class Silica {

    private static final Logger LOG = LoggerFactory.getLogger(Silica.class);

    private static String CONFIG_PATH;
    private static Config GLOBAL_CONFIG;
    private static Class<? extends Service> SERVICE_CLASS;

    private static ExecutorService EXECUTOR_POOL = Executors.newFixedThreadPool(3);

    /**
     * ????
     * 
     * @param key
     *            ??
     * @return ?
     */
    public static String getGlobalConfig(String key) {
        return GLOBAL_CONFIG.getMine(key);
    }

    /**
     * Silica 
     * 
     * @param args
     *            -o: (bind | unbind | exit) -S: xxx=hoge
     */
    public static void main(String[] args) {
        new Bootstrap().boot(args).execute();
    }

    public static void boot(String[] args) {
        new Bootstrap().boot(args);
    }

    public static void boot() {
        boot(new String[0]);
    }

    /**
     * ??
     * 
     * @return 
     */
    public static String getBaseDirectory() {
        return GLOBAL_CONFIG.get(Config.KEY_BASE_DIR);
    }

    /**
     * ??
     * 
     * @return 
     */
    public static String getResourceDirectory() {
        return GLOBAL_CONFIG.get(Config.KEY_RESOURCE_DIR);
    }

    /**
     * Silica?
     * 
     * @return
     */
    public static String getConfigPath() {
        return CONFIG_PATH;
    }

    /**
     * Silica??????ID?
     * 
     * @return Silica??????ID
     */
    public static String getResourceID() {
        return GLOBAL_CONFIG.get(Config.KEY_RESOURCE_ID);
    }

    /**
     * Service class??
     * 
     * @return Service class
     */
    public static Class<? extends Service> getServiceClass() {
        return SERVICE_CLASS;
    }

    /**
     * Job??
     * 
     * @return Job?
     */
    public static long getJobTimeout() {
        String jobTimeout = GLOBAL_CONFIG.get(Config.KEY_JOB_TIMEOUT_MSEC);
        if (jobTimeout == null) {
            return -1L;
        }
        return Long.parseLong(jobTimeout);
    }

    /**
     * ??Silica???????????????????
     * @return ??Silica??????????????????
     */
    public static int getNumOfKeepDeployed() {
        String keepDeployedLast = GLOBAL_CONFIG.get(Config.KEY_KEEP_DEPLOYED_LAST);
        if (keepDeployedLast == null) {
            return 0;
        }
        return Integer.parseInt(keepDeployedLast);
    }

    /**
     * Job??
     * 
     * @param job
     * @return
     * @throws ServiceException
     */
    public static <T extends Serializable> T execute(Job<T> job) throws ServiceException {
        return execute(job, getJobTimeout());
    }

    /**
     * Job??
     * 
     * @param job
     * @param jobTimeoutMsec
     * @return
     * @throws ServiceException
     */
    public static <T extends Serializable> T execute(Job<T> job, long jobTimeoutMsec) throws ServiceException {

        JobExecutor<T> executor = new JobExecutor<T>(job);
        Future<T> future = EXECUTOR_POOL.submit(executor);
        Exception err = null;
        try {
            return future.get(jobTimeoutMsec, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            LOG.info(job.toString(), e);
            err = e;
        } catch (ExecutionException e) {
            LOG.error(job.toString(), e);
            err = e;
        } catch (TimeoutException e) {
            LOG.warn(job.toString(), e);
            err = e;
        }
        throw new ServiceException(job.toString(), err);
    }

    /**
     * Job???
     * 
     * @param job
     * @return
     */
    public static <T extends Serializable> Future<T> executeAsync(Job<T> job) {

        JobExecutor<T> executor = new JobExecutor<T>(job);
        return EXECUTOR_POOL.submit(executor);
    }

    /**
     * Job?????jobCallback?
     * 
     * @param job
     * @param jobCallback
     */
    public static <T extends Serializable> void executeAsync(final Job<T> job, final Callback<T> jobCallback) {
        executeAsync(job, jobCallback, getJobTimeout());
    }

    /**
     * Job?????jobCallback?
     * 
     * @param job
     * @param jobCallback
     * @param jobTimeoutMsec
     */
    public static <T extends Serializable> void executeAsync(final Job<T> job, final Callback<T> jobCallback,
            final long jobTimeoutMsec) {

        JobExecutor<T> executor = new JobExecutor<T>(job);
        final Future<T> future = EXECUTOR_POOL.submit(executor);
        EXECUTOR_POOL.execute(new Runnable() {

            @Override
            public void run() {
                try {
                    T result = getResult(future, jobTimeoutMsec, job.toString());
                    jobCallback.execute(result);
                } catch (ServiceException e) {
                    LOG.error("", e);
                }
            }
        });
    }

    private static <T extends Serializable> T getResult(Future<T> future, long jobTimeoutMsec,
            String jobDescription) throws ServiceException {
        Exception exception = null;
        try {
            return future.get(jobTimeoutMsec, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            LOG.info(jobDescription, e);
            exception = e;
        } catch (ExecutionException e) {
            LOG.error(jobDescription, e);
            exception = e;
        } catch (TimeoutException e) {
            LOG.warn(jobDescription, e);
            exception = e;
        }
        throw new ServiceException(jobDescription, exception);
    }

    /**
     * ?Job??
     */
    protected static void shutdownAllJob() {
        EXECUTOR_POOL.shutdown();
        try {
            if (!EXECUTOR_POOL.awaitTermination(1, TimeUnit.SECONDS)) {
                EXECUTOR_POOL.shutdownNow();
                if (!EXECUTOR_POOL.awaitTermination(1, TimeUnit.SECONDS))
                    LOG.warn("Pool did not terminate");
            }
        } catch (InterruptedException ie) {
            EXECUTOR_POOL.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }

    private static class Bootstrap {
        private static final String KEY_CONFIG_PATH = "SILICA_CONF";
        private static final Options OPTS = new Options();
        static {
            OPTS.addOption("o", true, "bind | unbind");
            OPTS.addOption("c", true, "silica confing file");
            OPTS.addOption("s", true, "override properties");
        }

        private boolean initialized;
        private TypeOrderCmd order;

        private static enum TypeOrderCmd {
            bind, unbind
        }

        Bootstrap boot(String[] args) {
            if (initialized) {
                throw new IllegalStateException("Already initialized");
            }
            if (args == null) {
                args = new String[0];
            }
            if (LOG.isDebugEnabled()) {
                for (int i = 0; i < args.length; i++) {
                    LOG.debug("args[{}]={}", i, args[i]);
                }
            }
            try {
                CommandLineParser parser = new PosixParser();
                CommandLine cmd = parser.parse(OPTS, args);
                parseOptions(cmd);
            } catch (Exception e) {
                new HelpFormatter().printHelp("example", OPTS);
                throw new IllegalArgumentException(e);
            } finally {
                initialized = true;
            }
            return this;
        }

        Bootstrap execute() {

            Server localServer = ServerSelector.createSelector().getLocalServer();

            try {

                switch (order) {
                case bind:
                    localServer.bind(localServer.getServerContext().getService());
                    break;
                case unbind:
                    localServer.unbind(SERVICE_CLASS);
                    break;
                default:
                    throw new RuntimeException(MessageFormat.format("Unknown order command {0}", order));
                }
            } catch (Exception e) {
                throw new RuntimeException("Unknown error", e);
            }
            return this;
        }

        private CommandLine parseOptions(CommandLine cmd) throws ParseException, IOException {

            String o = cmd.getOptionValue("o");
            if (o != null) {
                order = TypeOrderCmd.valueOf(o);
            }
            String c = cmd.getOptionValue("c");
            if (c != null) {
                System.setProperty(KEY_CONFIG_PATH, c);
            }

            GLOBAL_CONFIG = new Config();

            String confPath = System.getProperty(KEY_CONFIG_PATH);

            if (confPath == null || confPath.length() == 0) {

                confPath = System.getenv(KEY_CONFIG_PATH);
            }
            if (confPath == null || confPath.length() == 0) {

                confPath = "silica.properties";
            }
            CONFIG_PATH = confPath;
            LOG.info("[SILICA_CONF]: {}", confPath);

            GLOBAL_CONFIG.init(Thread.currentThread().getContextClassLoader().getResource(confPath));

            String[] props = cmd.getOptionValues("s");
            if (props != null) {
                for (String prop : props) {

                    int pos = prop.indexOf("=");
                    String key = prop.substring(0, pos);
                    String value = prop.substring(pos + 1, prop.length());

                    if (key == null || key.length() == 0 || value == null || value.length() == 0) {
                        continue;
                    }
                    if (key.equals(Config.KEY_BASE_DIR)) {
                        String baseDir = value.endsWith("/") ? value : value + "/";
                        LOG.info(baseDir);
                        GLOBAL_CONFIG.set(Config.KEY_BASE_DIR, baseDir);

                    } else if (key.equals(Config.KEY_CLASS_PATHS)) {

                        String extpaths = value;
                        if (extpaths != null && extpaths.length() > 0) {
                            String orgpaths = getGlobalConfig(Config.KEY_CLASS_PATHS);
                            if (orgpaths != null && orgpaths.length() > 0) {
                                extpaths = orgpaths + "," + extpaths;
                            }
                            GLOBAL_CONFIG.set(Config.KEY_CLASS_PATHS, extpaths);
                        }
                    } else {

                        GLOBAL_CONFIG.set(key, value);
                    }
                }
            }
            String resourceID = getResourceID();
            if (resourceID == null) {
                /*
                 * * This is a first instance. *
                 * * Create a resource id. *
                 */
                GLOBAL_CONFIG.set(Config.KEY_RESOURCE_ID,
                        Long.toString(System.currentTimeMillis(), Character.MAX_RADIX));
                GLOBAL_CONFIG.set(Config.KEY_RESOURCE_DIR, getBaseDirectory());
                GLOBAL_CONFIG.set(Config.KEY_HOST_ADDRESS, "localhost");
            }

            try {
                @SuppressWarnings("unchecked")
                Class<? extends Service> serviceClass = (Class<? extends Service>) Class
                        .forName(getGlobalConfig("service.class"));
                SERVICE_CLASS = serviceClass;

            } catch (ClassNotFoundException e) {
                LOG.error("Could not difine service class.", e);
            }

            return cmd;
        }
    }
}