Java tutorial
/* * 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); } } } }); } }