blob: 272e7fb530cb8a316163e64130f2fef06edd29fd [file] [log] [blame]
// /*
// * Licensed to the Apache Software Foundation (ASF) under one or more
// * contributor license agreements. See the NOTICE file distributed with
// * this work for additional information regarding copyright ownership.
// * The ASF licenses this file to You 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.
// */
//
using System;
using System.Collections;
using System.IO;
using System.Text;
using Apache.NMS;
namespace Apache.NMS.Stomp.Protocol
{
public class StompFrame
{
/// Used to terminate a header line or end of a headers section of the Frame.
public const String NEWLINE = "\n";
/// Used to seperate the Key / Value pairing in Frame Headers
public const String SEPARATOR = ":";
/// Used to mark the End of the Frame.
public const byte FRAME_TERMINUS = (byte) 0;
private string command;
private IDictionary properties = new Hashtable();
private byte[] content;
private Encoding encoding = new UTF8Encoding();
public StompFrame()
{
}
public StompFrame(string command)
{
this.command = command;
}
public byte[] Content
{
get { return this.content; }
set { this.content = value; }
}
public string Command
{
get { return this.command; }
set { this.command = value; }
}
public IDictionary Properties
{
get { return this.properties; }
set { this.properties = value; }
}
public bool HasProperty(string name)
{
return this.properties.Contains(name);
}
public void SetProperty(string name, Object value)
{
if(value == null)
{
return;
}
this.Properties[name] = value.ToString();
}
public string GetProperty(string name)
{
return GetProperty(name, null);
}
public string GetProperty(string name, string fallback)
{
if(this.properties.Contains(name))
{
return this.properties[name] as string;
}
return fallback;
}
public string RemoveProperty(string name)
{
string result = null;
if(this.properties.Contains(name))
{
result = this.properties[name] as string;
this.properties.Remove(name);
}
return result;
}
public void ClearProperties()
{
this.properties.Clear();
}
public void ToStream(BinaryWriter dataOut)
{
StringBuilder builder = new StringBuilder();
builder.Append(this.Command);
builder.Append(NEWLINE);
foreach(String key in this.Properties.Keys)
{
builder.Append(key);
builder.Append(SEPARATOR);
builder.Append(this.Properties[key] as string);
builder.Append(NEWLINE);
}
builder.Append(NEWLINE);
dataOut.Write(this.encoding.GetBytes(builder.ToString()));
if(this.Content != null)
{
dataOut.Write(this.Content);
}
dataOut.Write(FRAME_TERMINUS);
}
public void FromStream(BinaryReader dataIn)
{
this.ReadCommandHeader(dataIn);
this.ReadHeaders(dataIn);
this.ReadContent(dataIn);
}
private void ReadCommandHeader(BinaryReader dataIn)
{
do
{
this.command = ReadLine(dataIn);
}
while(this.command == "");
}
private void ReadHeaders(BinaryReader dataIn)
{
string line;
while((line = ReadLine(dataIn)) != "")
{
int idx = line.IndexOf(':');
if(idx > 0)
{
string key = line.Substring(0, idx);
string value = line.Substring(idx + 1);
this.properties[key] = value;
}
else
{
Tracer.Debug("StompFrame - Read Malformed Header: " + line);
}
}
}
private void ReadContent(BinaryReader dataIn)
{
if(this.properties.Contains("content-length"))
{
int size = Int32.Parse(this.properties["content-length"] as string);
this.content = dataIn.ReadBytes(size);
// Read the terminating NULL byte for this frame.
if(dataIn.Read() != 0)
{
Tracer.Debug("StompFrame - Error Invalid Frame, no trailing Null.");
}
}
else
{
MemoryStream ms = new MemoryStream();
int nextChar;
while((nextChar = dataIn.Read()) != 0)
{
// The first Null in this case marks the end of data.
if(nextChar < 0)
{
break;
}
ms.WriteByte((byte)nextChar);
}
this.content = ms.ToArray();
}
}
private String ReadLine(BinaryReader dataIn)
{
MemoryStream ms = new MemoryStream();
while(true)
{
int nextChar = dataIn.Read();
if(nextChar < 0)
{
throw new IOException("Peer closed the stream.");
}
if(nextChar == 10)
{
break;
}
ms.WriteByte((byte)nextChar);
}
byte[] data = ms.ToArray();
return encoding.GetString(data, 0, data.Length);
}
}
}