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     */
017    package org.apache.activemq.transport.stomp;
018    
019    import java.io.UnsupportedEncodingException;
020    import java.util.Arrays;
021    import java.util.HashMap;
022    import java.util.Locale;
023    import java.util.Map;
024    
025    import org.apache.activemq.command.Command;
026    import org.apache.activemq.command.Endpoint;
027    import org.apache.activemq.command.Response;
028    import org.apache.activemq.state.CommandVisitor;
029    import org.apache.activemq.util.MarshallingSupport;
030    
031    /**
032     * Represents all the data in a STOMP frame.
033     *
034     * @author <a href="http://hiramchirino.com">chirino</a>
035     */
036    public class StompFrame implements Command {
037    
038        public static final byte[] NO_DATA = new byte[] {};
039    
040        private String action;
041        private Map<String, String> headers = new HashMap<String, String>();
042        private byte[] content = NO_DATA;
043    
044        private transient Object transportContext = null;
045    
046        public StompFrame(String command) {
047            this(command, null, null);
048        }
049    
050        public StompFrame(String command, Map<String, String> headers) {
051            this(command, headers, null);
052        }
053    
054        public StompFrame(String command, Map<String, String> headers, byte[] data) {
055            this.action = command;
056            if (headers != null)
057                this.headers = headers;
058            if (data != null)
059                this.content = data;
060        }
061    
062        public StompFrame() {
063        }
064    
065        public String getAction() {
066            return action;
067        }
068    
069        public void setAction(String command) {
070            this.action = command;
071        }
072    
073        public byte[] getContent() {
074            return content;
075        }
076    
077        public String getBody() {
078            try {
079                return new String(content, "UTF-8");
080            } catch (UnsupportedEncodingException e) {
081                return new String(content);
082            }
083        }
084    
085        public void setContent(byte[] data) {
086            this.content = data;
087        }
088    
089        public Map<String, String> getHeaders() {
090            return headers;
091        }
092    
093        public void setHeaders(Map<String, String> headers) {
094            this.headers = headers;
095        }
096    
097        //
098        // Methods in the Command interface
099        //
100        public int getCommandId() {
101            return 0;
102        }
103    
104        public Endpoint getFrom() {
105            return null;
106        }
107    
108        public Endpoint getTo() {
109            return null;
110        }
111    
112        public boolean isBrokerInfo() {
113            return false;
114        }
115    
116        public boolean isMessage() {
117            return false;
118        }
119    
120        public boolean isMessageAck() {
121            return false;
122        }
123    
124        public boolean isMessageDispatch() {
125            return false;
126        }
127    
128        public boolean isMessageDispatchNotification() {
129            return false;
130        }
131    
132        public boolean isResponse() {
133            return false;
134        }
135    
136        public boolean isResponseRequired() {
137            return false;
138        }
139    
140        public boolean isShutdownInfo() {
141            return false;
142        }
143    
144        public boolean isConnectionControl() {
145            return false;
146        }
147    
148        public boolean isWireFormatInfo() {
149            return false;
150        }
151    
152        public void setCommandId(int value) {
153        }
154    
155        public void setFrom(Endpoint from) {
156        }
157    
158        public void setResponseRequired(boolean responseRequired) {
159        }
160    
161        public void setTo(Endpoint to) {
162        }
163    
164        public Response visit(CommandVisitor visitor) throws Exception {
165            return null;
166        }
167    
168        public byte getDataStructureType() {
169            return 0;
170        }
171    
172        public boolean isMarshallAware() {
173            return false;
174        }
175    
176        public String toString() {
177            return format(true);
178        }
179    
180        public String format() {
181            return format(false);
182        }
183    
184        public String format(boolean forLogging) {
185            StringBuilder buffer = new StringBuilder();
186            buffer.append(getAction());
187            buffer.append("\n");
188            Map<String, String> headers = getHeaders();
189            for (Map.Entry<String, String> entry : headers.entrySet()) {
190                buffer.append(entry.getKey());
191                buffer.append(":");
192                if (forLogging && entry.getKey().toString().toLowerCase(Locale.ENGLISH).contains(Stomp.Headers.Connect.PASSCODE)) {
193                    buffer.append("*****");
194                } else {
195                    buffer.append(entry.getValue());
196                }
197                buffer.append("\n");
198            }
199            buffer.append("\n");
200            if (getContent() != null) {
201                try {
202                    String contentString = new String(getContent(), "UTF-8");
203                    if (forLogging) {
204                        contentString = MarshallingSupport.truncate64(contentString);
205                    }
206                    buffer.append(contentString);
207                } catch (Throwable e) {
208                    buffer.append(Arrays.toString(getContent()));
209                }
210            }
211            // terminate the frame
212            buffer.append('\u0000');
213            return buffer.toString();
214        }
215    
216        /**
217         * Transports may wish to associate additional data with the connection. For
218         * example, an SSL transport may use this field to attach the client
219         * certificates used when the connection was established.
220         *
221         * @return the transport context.
222         */
223        public Object getTransportContext() {
224            return transportContext;
225        }
226    
227        /**
228         * Transports may wish to associate additional data with the connection. For
229         * example, an SSL transport may use this field to attach the client
230         * certificates used when the connection was established.
231         *
232         * @param transportContext value used to set the transport context
233         */
234        public void setTransportContext(Object transportContext) {
235            this.transportContext = transportContext;
236        }
237    }