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.stomp;
018
019import java.io.IOException;
020
021import javax.jms.JMSException;
022
023import org.apache.activemq.broker.BrokerContext;
024import org.apache.activemq.command.Command;
025import org.apache.activemq.transport.Transport;
026import org.apache.activemq.transport.TransportFilter;
027import org.apache.activemq.transport.TransportListener;
028import org.apache.activemq.util.IOExceptionSupport;
029import org.apache.activemq.wireformat.WireFormat;
030import org.slf4j.Logger;
031import org.slf4j.LoggerFactory;
032
033/**
034 * The StompTransportFilter normally sits on top of a TcpTransport that has been
035 * configured with the StompWireFormat and is used to convert STOMP commands to
036 * ActiveMQ commands. All of the conversion work is done by delegating to the
037 * ProtocolConverter.
038 *
039 * @author <a href="http://hiramchirino.com">chirino</a>
040 */
041public class StompTransportFilter extends TransportFilter implements StompTransport {
042    private static final Logger TRACE = LoggerFactory.getLogger(StompTransportFilter.class.getPackage().getName() + ".StompIO");
043    private final ProtocolConverter protocolConverter;
044    private StompInactivityMonitor monitor;
045    private StompWireFormat wireFormat;
046
047    private boolean trace;
048
049    public StompTransportFilter(Transport next, WireFormat wireFormat, BrokerContext brokerContext) {
050        super(next);
051        this.protocolConverter = new ProtocolConverter(this, brokerContext);
052
053        if (wireFormat instanceof StompWireFormat) {
054            this.wireFormat = (StompWireFormat) wireFormat;
055        }
056    }
057
058    @Override
059    public void oneway(Object o) throws IOException {
060        try {
061            final Command command = (Command) o;
062            protocolConverter.onActiveMQCommand(command);
063        } catch (JMSException e) {
064            throw IOExceptionSupport.create(e);
065        }
066    }
067
068    @Override
069    public void onCommand(Object command) {
070        try {
071            if (trace) {
072                TRACE.trace("Received: \n" + command);
073            }
074
075            protocolConverter.onStompCommand((StompFrame) command);
076        } catch (IOException e) {
077            onException(e);
078        } catch (JMSException e) {
079            onException(IOExceptionSupport.create(e));
080        }
081    }
082
083    @Override
084    public void sendToActiveMQ(Command command) {
085        TransportListener l = transportListener;
086        if (l != null) {
087            l.onCommand(command);
088        }
089    }
090
091    @Override
092    public void sendToStomp(StompFrame command) throws IOException {
093        if (trace) {
094            TRACE.trace("Sending: \n" + command);
095        }
096        Transport n = next;
097        if (n != null) {
098            n.oneway(command);
099        }
100    }
101
102    public boolean isTrace() {
103        return trace;
104    }
105
106    public void setTrace(boolean trace) {
107        this.trace = trace;
108    }
109
110    @Override
111    public StompInactivityMonitor getInactivityMonitor() {
112        return monitor;
113    }
114
115    public void setInactivityMonitor(StompInactivityMonitor monitor) {
116        this.monitor = monitor;
117    }
118
119    @Override
120    public StompWireFormat getWireFormat() {
121        return this.wireFormat;
122    }
123
124    public String getDefaultHeartBeat() {
125        return protocolConverter != null ? protocolConverter.getDefaultHeartBeat() : null;
126    }
127
128    public void setDefaultHeartBeat(String defaultHeartBeat) {
129        protocolConverter.setDefaultHeartBeat(defaultHeartBeat);
130    }
131
132    /**
133     * Returns the currently configured Read check grace period multiplier.
134     *
135     * @return the hbGracePeriodMultiplier
136     */
137    public float getHbGracePeriodMultiplier() {
138        return protocolConverter != null ? protocolConverter.getHbGracePeriodMultiplier() : null;
139    }
140
141    /**
142     * Sets the read check grace period multiplier.  New CONNECT frames that indicate a heart beat
143     * value with a read check interval will have that value multiplied by this value to add a
144     * grace period before the connection is considered invalid.  By default this value is set to
145     * zero and no grace period is given.  When set the value must be larger than 1.0 or it will
146     * be ignored.
147     *
148     * @param hbGracePeriodMultiplier the hbGracePeriodMultiplier to set
149     */
150    public void setHbGracePeriodMultiplier(float hbGracePeriodMultiplier) {
151        if (hbGracePeriodMultiplier > 1.0f) {
152            protocolConverter.setHbGracePeriodMultiplier(hbGracePeriodMultiplier);
153        }
154    }
155
156    /**
157     * Sets the maximum number of bytes that the data portion of a STOMP frame is allowed to
158     * be, any incoming STOMP frame with a data section larger than this value will receive
159     * an error response.
160     *
161     * @param maxDataLength
162     *        size in bytes of the maximum data portion of a STOMP frame.
163     */
164    public void setMaxDataLength(int maxDataLength) {
165        wireFormat.setMaxDataLength(maxDataLength);
166    }
167
168    public int getMaxDataLength() {
169        return wireFormat.getMaxDataLength();
170    }
171}