/* * Copyright 2017 Async-IO.org * * 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 org.atmosphere.nettosphere; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.MultithreadEventLoopGroup; import io.netty.channel.epoll.EpollEventLoopGroup; import io.netty.channel.epoll.EpollServerSocketChannel; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.ChannelGroupFuture; import io.netty.channel.group.DefaultChannelGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.util.concurrent.ImmediateEventExecutor; import org.atmosphere.cpr.AtmosphereFramework; import org.atmosphere.nettosphere.extra.FlashPolicyServerChannelInitializer; import org.atmosphere.nettosphere.util.Version; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.concurrent.atomic.AtomicBoolean; /** * Start Atmosphere on top of Netty. To configure Atmosphere, use the {@link Config}. As simple as * <blockquote><pre> * <p/> * Config config = new Config.Builder() * .port(port) * .host("127.0.0.1") * .initParam("foo", "bar") * .resource("/", new AtmosphereHandlerAdapter() { * <p/> * public void onStateChange(AtmosphereResourceEvent r) throws IOException { * } * <p/> * }).build(); * <p/> * server = new Nettosphere.Builder().config(config).build(); * </pre></blockquote> * * @author Jeanfrancois Arcand */ public final class Nettosphere { public final static String FLASH_SUPPORT = Nettosphere.class.getName() + ".enableFlash"; private static final Logger logger = LoggerFactory.getLogger(Nettosphere.class); private static final ChannelGroup ALL_CHANNELS = new DefaultChannelGroup("atmosphere", ImmediateEventExecutor.INSTANCE); @SuppressWarnings("rawtypes") private final ChannelInitializer channelInitializer; private final ServerBootstrap bootstrap; private final SocketAddress localSocket; private final BridgeRuntime runtime; private final AtomicBoolean started = new AtomicBoolean(); private final ServerBootstrap bootstrapFlashPolicy; private final SocketAddress localPolicySocket; private final RuntimeEngine runtimeEngine; private MultithreadEventLoopGroup parentGroup; private MultithreadEventLoopGroup childGroup; private Nettosphere(Config config) { runtime = new BridgeRuntime(config); this.channelInitializer = new NettyChannelInitializer(runtime); this.localSocket = new InetSocketAddress(config.host(), config.port()); this.bootstrap = buildBootstrap(config); if (config.initParams().containsKey(FLASH_SUPPORT)) { this.bootstrapFlashPolicy = buildBootstrapFlashPolicy(config); localPolicySocket = new InetSocketAddress(843); } else { configureBootstrap(bootstrap, config); this.bootstrapFlashPolicy = null; localPolicySocket = null; } runtimeEngine = new RuntimeEngine(runtime); } private void configureBootstrap(ServerBootstrap bootstrap, Config config) { bootstrap.childOption(ChannelOption.TCP_NODELAY, config.socketNoTcpDelay()); bootstrap.childOption(ChannelOption.SO_KEEPALIVE, config.socketKeepAlive()); } /** * Return the {@link org.atmosphere.cpr.AtmosphereFramework} instance * * @return the {@link AtmosphereFramework} instance */ public AtmosphereFramework framework() { return runtime.framework(); } /** * Start the server */ public void start() { final Channel serverChannel = bootstrap.bind(localSocket).channel(); ALL_CHANNELS.add(serverChannel); started.set(true); if (bootstrapFlashPolicy != null) { try { bootstrapFlashPolicy.bind(localPolicySocket); logger.info("NettoSphere Flash Support Started on port {}.", localPolicySocket); } catch (Exception ex) { logger.error("", ex); } } logger.info("NettoSphere {} Started.", Version.getRawVersion()); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { Nettosphere.this.stop(); } }); } /** * Stop the Server */ public void stop() { if (started.getAndSet(false)) { runtime.destroy(); final ChannelGroupFuture future = ALL_CHANNELS.close(); future.awaitUninterruptibly(); ALL_CHANNELS.clear(); } } /** * Return true is the server was successfully started. * * @return true is the server was successfully started. */ public boolean isStarted() { return started.get(); } private ServerBootstrap buildBootstrap(Config config) { final ServerBootstrap bootstrap = new ServerBootstrap(); parentGroup = config.epoll() ? new EpollEventLoopGroup() : new NioEventLoopGroup(); childGroup = config.epoll() ? new EpollEventLoopGroup() : new NioEventLoopGroup(); bootstrap .channel(config.epoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class) .group(parentGroup, childGroup); bootstrap.childHandler(channelInitializer); return bootstrap; } private ServerBootstrap buildBootstrapFlashPolicy(Config config) { final ServerBootstrap bootstrap = new ServerBootstrap(); parentGroup = config.epoll() ? new EpollEventLoopGroup() : new NioEventLoopGroup(); childGroup = config.epoll() ? new EpollEventLoopGroup() : new NioEventLoopGroup(); bootstrap .channel(config.epoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class) .group(parentGroup, childGroup); // Set up the event pipeline factory. bootstrap.childHandler(new FlashPolicyServerChannelInitializer()); return bootstrap; } /** * Construct a {@link Nettosphere}. */ public final static class Builder { private Config config = new Config.Builder().build(); public Builder config(Config config) { this.config = config; return this; } public Nettosphere build() { return new Nettosphere(config); } } /** * Return the {@link RuntimeEngine} * * @return the {@link RuntimeEngine} */ public RuntimeEngine runtimeEngine() { return runtimeEngine; } public static void main(String[] args) throws Exception { Config.Builder b = new Config.Builder(); b.resource(args[0]).port(8080).host("127.0.0.1"); Nettosphere s = new Nettosphere(b.build()); s.start(); String a = ""; logger.info("NettoSphere Server started"); logger.info("Type quit to stop the server"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); while (!(a.equals("quit"))) { a = br.readLine(); } System.exit(-1); } }