io.dyn.net.tcp.stomp.StompServer.java Source code

Java tutorial

Introduction

Here is the source code for io.dyn.net.tcp.stomp.StompServer.java

Source

/*
 * Copyright (c) 2011-2012 by the original author or authors.
 *
 * 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 io.dyn.net.tcp.stomp;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import io.dyn.core.Evented;
import io.dyn.core.Tasks;
import io.dyn.core.handler.Handler;
import io.dyn.core.sys.Sys;
import io.dyn.net.tcp.TcpServer;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelStateEvent;
import io.netty.channel.MessageEvent;
import io.netty.channel.SimpleChannelUpstreamHandler;
import org.springframework.core.task.TaskExecutor;
import org.springframework.http.converter.BufferedImageHttpMessageConverter;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;

/**
 * @author Jon Brisbin <jon@jbrisbin.com>
 */
public class StompServer extends TcpServer<StompServer> {

    static final String SERVER_NAME = "dyn.io.STOMP/1.0";

    private String hostname;
    private List<HttpMessageConverter> converters = new ArrayList<>();
    private Map<Channel, String> sessionIds = new ConcurrentHashMap<>();
    private Cache<String, StompSession> sessions = CacheBuilder.newBuilder().weakValues()
            .expireAfterAccess(15, TimeUnit.MINUTES).removalListener(new RemovalListener<String, StompSession>() {
                @Override
                public void onRemoval(RemovalNotification<String, StompSession> notif) {
                    log.info("Expiring session %s", notif.getValue().id());
                    sessionIds.remove(notif.getKey());
                }
            }).build();

    {
        converters.add(new StringHttpMessageConverter());
        converters.add(new ByteArrayHttpMessageConverter());
        converters.add(new BufferedImageHttpMessageConverter());
        converters.add(new FormHttpMessageConverter());
        converters.add(new ResourceHttpMessageConverter());
        if (Sys.isGroovyPresent()) {
            //converters.add(new io.dyn.http.convert.GroovyStringHttpMessageConverter());
        }
        if (Sys.isJacksonPresent()) {
            converters.add(new org.springframework.http.converter.json.MappingJacksonHttpMessageConverter());
        }
        if (Sys.isJaxb2Present()) {
            converters.add(new org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter());
        }
        if (Sys.isRomePresent()) {
            converters.add(new org.springframework.http.converter.feed.AtomFeedHttpMessageConverter());
        }
    }

    public String hostname() {
        if (null == hostname) {
            return host + ":" + port;
        } else {
            return hostname;
        }
    }

    public StompServer hostname(String hostname) {
        this.hostname = hostname;
        return this;
    }

    @Override
    protected void configurePipeline(ChannelPipeline pipeline) {
        pipeline.addLast("stompEncoder", new StompMessageEncoder());
        pipeline.addLast("stompDecoder", new StompMessageDecoder());
        pipeline.addLast("handler", new SimpleChannelUpstreamHandler() {
            @Override
            public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception {
                log.debug("message received: " + e.getMessage());
                if (null != e.getMessage() && e.getMessage() instanceof StompMessage) {
                    StompMessage msg = (StompMessage) e.getMessage();
                    if (null != msg.header("session-id")) {
                        msg.session = sessions.getIfPresent(msg.header("session-id"));
                    } else {
                        String sid = sessionIds.get(ctx.getChannel());
                        if (null != sid) {
                            msg.session = sessions.getIfPresent(sid);
                        }
                    }

                    switch (msg.command()) {
                    case CONNECT:
                    case STOMP:
                        // Each client connection gets a fresh session
                        UUID id = UUID.randomUUID();
                        msg.session = new StompSession(id);
                        sessions.put(id.toString(), msg.session);
                        sessionIds.put(ctx.getChannel(), id.toString());
                        msg.session.on("reply", new Handler<Object>() {
                            @Override
                            public void handle(Object o, Object... args) {
                                ctx.getChannel().write(o);
                            }
                        });
                        event("session", msg.session);

                        String vers = msg.header("accept-version");
                        if (null == vers) {
                            msg.session.version = StompSession.Version.v1_0;
                        } else if (vers.contains("1.1")) {
                            msg.session.version = StompSession.Version.v1_1;
                        } else if (vers.contains("1.0")) {
                            msg.session.version = StompSession.Version.v1_0;
                        } else {
                            ctx.getChannel().write(StompMessages
                                    .error("Supported protocol versions include 1.0 1.1", "version", "1.0, 1.1"));
                            return;
                        }
                        // Fire the event
                        event("connect", msg);
                        break;
                    case DISCONNECT:
                        // Fire the event
                        event("disconnect", msg);
                        break;
                    default:
                        // Fire the event
                        event(msg.command().toString().toLowerCase(), msg);
                    }
                }
            }
        });
    }

}