001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.transport.ws.jetty9; 018 019import java.io.IOException; 020import java.util.concurrent.TimeUnit; 021 022import org.apache.activemq.transport.stomp.Stomp; 023import org.apache.activemq.transport.stomp.StompFrame; 024import org.apache.activemq.transport.ws.AbstractStompSocket; 025import org.apache.activemq.util.IOExceptionSupport; 026import org.eclipse.jetty.websocket.api.Session; 027import org.eclipse.jetty.websocket.api.WebSocketListener; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031/** 032 * Implements web socket and mediates between servlet and the broker 033 */ 034public class StompSocket extends AbstractStompSocket implements WebSocketListener { 035 036 private static final Logger LOG = LoggerFactory.getLogger(StompSocket.class); 037 038 private final int ORDERLY_CLOSE_TIMEOUT = 10; 039 040 private Session session; 041 042 public StompSocket(String remoteAddress) { 043 super(remoteAddress); 044 } 045 046 @Override 047 public void sendToStomp(StompFrame command) throws IOException { 048 try { 049 //timeout after a period of time so we don't wait forever and hold the protocol lock 050 session.getRemote().sendStringByFuture(getWireFormat().marshalToString(command)).get(getDefaultSendTimeOut(), TimeUnit.SECONDS); 051 } catch (Exception e) { 052 throw IOExceptionSupport.create(e); 053 } 054 } 055 056 @Override 057 public void handleStopped() throws IOException { 058 if (session != null && session.isOpen()) { 059 session.close(); 060 } 061 } 062 063 //----- WebSocketListener event callbacks --------------------------------// 064 065 @Override 066 public void onWebSocketBinary(byte[] arg0, int arg1, int arg2) { 067 } 068 069 @Override 070 public void onWebSocketClose(int arg0, String arg1) { 071 try { 072 if (protocolLock.tryLock() || protocolLock.tryLock(ORDERLY_CLOSE_TIMEOUT, TimeUnit.SECONDS)) { 073 LOG.debug("Stomp WebSocket closed: code[{}] message[{}]", arg0, arg1); 074 protocolConverter.onStompCommand(new StompFrame(Stomp.Commands.DISCONNECT)); 075 } 076 } catch (Exception e) { 077 LOG.debug("Failed to close STOMP WebSocket cleanly", e); 078 } finally { 079 if (protocolLock.isHeldByCurrentThread()) { 080 protocolLock.unlock(); 081 } 082 } 083 } 084 085 @Override 086 public void onWebSocketConnect(Session session) { 087 this.session = session; 088 } 089 090 @Override 091 public void onWebSocketError(Throwable arg0) { 092 } 093 094 @Override 095 public void onWebSocketText(String data) { 096 processStompFrame(data); 097 } 098 099 private static int getDefaultSendTimeOut() { 100 return Integer.getInteger("org.apache.activemq.transport.ws.StompSocket.sendTimeout", 30); 101 } 102}