org.apache.hedwig.server.proxy.HedwigProxy.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hedwig.server.proxy.HedwigProxy.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.hedwig.server.proxy;

import java.io.File;
import java.lang.Thread.UncaughtExceptionHandler;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.commons.configuration.ConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.channel.socket.ServerSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.logging.InternalLoggerFactory;
import org.jboss.netty.logging.Log4JLoggerFactory;

import org.apache.hedwig.client.HedwigClient;
import org.apache.hedwig.protocol.PubSubProtocol.OperationType;
import org.apache.hedwig.server.common.TerminateJVMExceptionHandler;
import org.apache.hedwig.server.handlers.ChannelDisconnectListener;
import org.apache.hedwig.server.handlers.Handler;
import org.apache.hedwig.server.netty.PubSubServer;
import org.apache.hedwig.server.netty.PubSubServerPipelineFactory;
import org.apache.hedwig.server.netty.UmbrellaHandler;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

public class HedwigProxy {
    private static final Logger logger = LoggerFactory.getLogger(HedwigProxy.class);

    HedwigClient client;
    ServerSocketChannelFactory serverSocketChannelFactory;
    ChannelGroup allChannels;
    Map<OperationType, Handler> handlers;
    ProxyConfiguration cfg;
    ChannelTracker tracker;
    ThreadGroup tg;

    public HedwigProxy(final ProxyConfiguration cfg, final UncaughtExceptionHandler exceptionHandler) {
        this.cfg = cfg;

        tg = new ThreadGroup("hedwigproxy") {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                exceptionHandler.uncaughtException(t, e);
            }
        };
    }

    public HedwigProxy(ProxyConfiguration conf) throws InterruptedException {
        this(conf, new TerminateJVMExceptionHandler());
    }

    public void start() throws InterruptedException {
        final LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<Boolean>();

        new Thread(tg, new Runnable() {
            @Override
            public void run() {
                client = new HedwigClient(cfg);
                ThreadFactoryBuilder tfb = new ThreadFactoryBuilder();
                serverSocketChannelFactory = new NioServerSocketChannelFactory(
                        Executors.newCachedThreadPool(tfb.setNameFormat("HedwigProxy-NIOBoss-%d").build()),
                        Executors.newCachedThreadPool(tfb.setNameFormat("HedwigProxy-NIOWorker-%d").build()));
                initializeHandlers();
                initializeNetty();

                queue.offer(true);
            }
        }).start();

        queue.take();
    }

    // used for testing
    public ChannelTracker getChannelTracker() {
        return tracker;
    }

    protected void initializeHandlers() {
        handlers = new HashMap<OperationType, Handler>();
        tracker = new ChannelTracker(client.getSubscriber());

        handlers.put(OperationType.PUBLISH, new ProxyPublishHander(client.getPublisher()));
        handlers.put(OperationType.SUBSCRIBE, new ProxySubscribeHandler(client.getSubscriber(), tracker));
        handlers.put(OperationType.UNSUBSCRIBE, new ProxyUnsubscribeHandler(client.getSubscriber(), tracker));
        handlers.put(OperationType.CONSUME, new ProxyConsumeHandler(client.getSubscriber()));
        handlers.put(OperationType.STOP_DELIVERY, new ProxyStopDeliveryHandler(client.getSubscriber(), tracker));
        handlers.put(OperationType.START_DELIVERY, new ProxyStartDeliveryHandler(client.getSubscriber(), tracker));
        handlers.put(OperationType.CLOSESUBSCRIPTION,
                new ProxyCloseSubscriptionHandler(client.getSubscriber(), tracker));
    }

    protected void initializeNetty() {
        InternalLoggerFactory.setDefaultFactory(new Log4JLoggerFactory());
        allChannels = new DefaultChannelGroup("hedwigproxy");
        ServerBootstrap bootstrap = new ServerBootstrap(serverSocketChannelFactory);
        ChannelDisconnectListener disconnectListener = (ChannelDisconnectListener) handlers
                .get(OperationType.SUBSCRIBE);
        UmbrellaHandler umbrellaHandler = new UmbrellaHandler(allChannels, handlers, disconnectListener, false);
        PubSubServerPipelineFactory pipeline = new PubSubServerPipelineFactory(umbrellaHandler, null,
                cfg.getMaximumMessageSize());

        bootstrap.setPipelineFactory(pipeline);
        bootstrap.setOption("child.tcpNoDelay", true);
        bootstrap.setOption("child.keepAlive", true);
        bootstrap.setOption("reuseAddress", true);

        // Bind and start to accept incoming connections.
        allChannels.add(bootstrap.bind(new InetSocketAddress(cfg.getProxyPort())));
        logger.info("Going into receive loop");
    }

    public void shutdown() {
        allChannels.close().awaitUninterruptibly();
        client.close();
        serverSocketChannelFactory.releaseExternalResources();
    }

    // the following method only exists for unit-testing purposes, should go
    // away once we make start delivery totally server-side
    public Handler getStartDeliveryHandler() {
        return handlers.get(OperationType.START_DELIVERY);
    }

    public Handler getStopDeliveryHandler() {
        return handlers.get(OperationType.STOP_DELIVERY);
    }

    /**
     * @param args
     */
    public static void main(String[] args) {

        logger.info("Attempting to start Hedwig Proxy");
        ProxyConfiguration conf = new ProxyConfiguration();
        if (args.length > 0) {
            String confFile = args[0];
            try {
                conf.loadConf(new File(confFile).toURI().toURL());
            } catch (MalformedURLException e) {
                String msg = "Could not open configuration file: " + confFile;
                PubSubServer.errorMsgAndExit(msg, e, PubSubServer.RC_INVALID_CONF_FILE);
            } catch (ConfigurationException e) {
                String msg = "Malformed configuration file: " + confFile;
                PubSubServer.errorMsgAndExit(msg, e, PubSubServer.RC_MISCONFIGURED);
            }
            logger.info("Using configuration file " + confFile);
        }
        try {
            new HedwigProxy(conf).start();
        } catch (Throwable t) {
            PubSubServer.errorMsgAndExit("Error during startup", t, PubSubServer.RC_OTHER);
        }
    }

}