summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Ross <tross@apache.org>2009-06-11 15:54:37 +0000
committerTed Ross <tross@apache.org>2009-06-11 15:54:37 +0000
commit641f048cb8b86be0304441a6227759d7ad420ff3 (patch)
treee450e074085d41a476a3c2d6daafcfe99183a60f
parent91f06a93d86eff2a597347dc2f15b2431eb0feae (diff)
downloadqpid-python-641f048cb8b86be0304441a6227759d7ad420ff3.tar.gz
QPID-1786 - Committed qmf patches from Bryan Kearney
Additionally updated existing qmf and Qman to be compatible. The magic number for qmf messages has been incremented. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@783818 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--qpid/cpp/bindings/qmf/ruby/Makefile.am2
-rw-r--r--qpid/cpp/examples/qmf-agent/Makefile2
-rw-r--r--qpid/cpp/managementgen/qmfgen/management-types.xml2
-rw-r--r--qpid/cpp/managementgen/qmfgen/templates/Class.cpp1
-rw-r--r--qpid/cpp/managementgen/qmfgen/templates/Event.cpp1
-rw-r--r--qpid/cpp/src/qmf/Agent.cpp4
-rw-r--r--qpid/cpp/src/qmf/SchemaImpl.cpp1
-rw-r--r--qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp4
-rw-r--r--qpid/cpp/src/qpid/console/Broker.cpp4
-rw-r--r--qpid/cpp/src/qpid/console/Schema.cpp15
-rw-r--r--qpid/cpp/src/qpid/console/Value.cpp2
-rw-r--r--qpid/cpp/src/qpid/console/Value.h6
-rw-r--r--qpid/cpp/src/qpid/framing/FieldTable.cpp135
-rw-r--r--qpid/cpp/src/qpid/framing/FieldTable.h4
-rw-r--r--qpid/cpp/src/qpid/management/ManagementAgent.cpp19
-rw-r--r--qpid/java/agent/build.xml41
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/Agent.java650
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/AgentException.java43
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/EventSeverity.java6
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedEJB.java104
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedObject.java49
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedObjectBase.java72
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedPOJO.java87
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFEvent.java38
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFHide.java35
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFObject.java38
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFProperty.java36
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFSeeAlso.java36
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFType.java38
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/BindingContext.java209
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/BindingException.java50
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/BindingUtils.java137
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/ClassBinding.java599
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/EnumBinding.java99
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/ListBinding.java122
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/MapBinding.java133
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/MethodBinding.java88
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/ParameterBinding.java118
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/PropertyBinding.java128
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/QMFTypeBinding.java462
-rw-r--r--qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/TypeBinding.java43
-rw-r--r--qpid/java/agent/src/test/java/org/apache/qpid/agent/Crumpet.java70
-rw-r--r--qpid/java/agent/src/test/java/org/apache/qpid/agent/Muppet.java113
-rw-r--r--qpid/java/agent/src/test/java/org/apache/qpid/agent/Pikelet.java52
-rw-r--r--qpid/java/agent/src/test/java/org/apache/qpid/agent/Puppet.java29
-rw-r--r--qpid/java/build.deps4
-rw-r--r--qpid/java/build.xml2
-rw-r--r--qpid/java/management/client/src/main/java/org/apache/qpid/management/Protocol.java2
-rw-r--r--qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/SchemaResponseMessageHandler.java11
-rwxr-xr-xqpid/python/commands/qpid-config2
-rw-r--r--qpid/python/qmf/console.py743
-rw-r--r--qpid/python/qpid/management.py9
-rw-r--r--qpid/python/qpid/managementdata.py6
-rw-r--r--qpid/ruby/lib/qpid/qmf.rb14
54 files changed, 4461 insertions, 259 deletions
diff --git a/qpid/cpp/bindings/qmf/ruby/Makefile.am b/qpid/cpp/bindings/qmf/ruby/Makefile.am
index 8e10b418dc..4b5f42bae0 100644
--- a/qpid/cpp/bindings/qmf/ruby/Makefile.am
+++ b/qpid/cpp/bindings/qmf/ruby/Makefile.am
@@ -13,7 +13,7 @@ rubylibdir = $(RUBY_LIB)
dist_rubylib_DATA = qmf.rb
$(generated_file_list): $(srcdir)/ruby.i $(srcdir)/../qmfengine.i
- swig -ruby -c++ -Wall -I/usr/include $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -o qmfengine.cpp $(srcdir)/ruby.i
+ swig -ruby -c++ -Wall -I/usr/include $(INCLUDES) $(QPID_CXXFLAGS) -o qmfengine.cpp $(srcdir)/ruby.i
AM_CPPFLAGS = $(QPID_CXXFLAGS) $(INCLUDES) -I$(srcdir) -I$(RUBY_INC) -I$(RUBY_INC_ARCH)
AM_CXXFLAGS = $(QPID_CXXFLAGS)
diff --git a/qpid/cpp/examples/qmf-agent/Makefile b/qpid/cpp/examples/qmf-agent/Makefile
index 4c5daa6888..7e460bcd16 100644
--- a/qpid/cpp/examples/qmf-agent/Makefile
+++ b/qpid/cpp/examples/qmf-agent/Makefile
@@ -27,7 +27,7 @@ CC = gcc
LIB_DIR = $(QPID_DIR)/cpp/src/.libs
CC_INCLUDES = -I$(SRC_DIR) -I$(QPID_DIR)/cpp/src -I$(QPID_DIR)/cpp/src/gen -I$(GEN_DIR)
CC_FLAGS = -g -O3
-LD_FLAGS = -lqmfagent -L$(LIB_DIR)
+LD_FLAGS = -lqmfagent -lqmfcommon -L$(LIB_DIR)
SPEC_DIR = $(QPID_DIR)/specs
MGEN_DIR = $(QPID_DIR)/cpp/managementgen
MGEN = $(MGEN_DIR)/qmf-gen
diff --git a/qpid/cpp/managementgen/qmfgen/management-types.xml b/qpid/cpp/managementgen/qmfgen/management-types.xml
index 626880afb3..e235920447 100644
--- a/qpid/cpp/managementgen/qmfgen/management-types.xml
+++ b/qpid/cpp/managementgen/qmfgen/management-types.xml
@@ -36,7 +36,7 @@
<type name="float" base="FLOAT" cpp="float" encode="@.putFloat(#)" decode="# = @.getFloat()" accessor="direct" init="0."/>
<type name="double" base="DOUBLE" cpp="double" encode="@.putDouble(#)" decode="# = @.getDouble()" accessor="direct" init="0."/>
<type name="uuid" base="UUID" cpp="::qpid::framing::Uuid" encode="#.encode(@)" decode="#.decode(@)" accessor="direct" init="::qpid::framing::Uuid()" byRef="y"/>
-<type name="map" base="FTABLE" cpp="::qpid::framing::FieldTable" encode="#.encode(@)" decode="#.decode(@)" accessor="direct" init="::qpid::framing::FieldTable()" byRef="y"/>
+<type name="map" base="FTABLE" cpp="::qpid::framing::FieldTable" encode="#.qmfEncode(@)" decode="#.decode(@)" accessor="direct" init="::qpid::framing::FieldTable()" byRef="y"/>
<type name="hilo8" base="U8" cpp="uint8_t" encode="@.putOctet(#)" decode="# = @.getOctet()" style="wm" accessor="counter" init="0"/>
<type name="hilo16" base="U16" cpp="uint16_t" encode="@.putShort(#)" decode="# = @.getShort()" style="wm" accessor="counter" init="0"/>
diff --git a/qpid/cpp/managementgen/qmfgen/templates/Class.cpp b/qpid/cpp/managementgen/qmfgen/templates/Class.cpp
index 973d92586a..52ffce0eb4 100644
--- a/qpid/cpp/managementgen/qmfgen/templates/Class.cpp
+++ b/qpid/cpp/managementgen/qmfgen/templates/Class.cpp
@@ -98,6 +98,7 @@ void /*MGEN:Class.NameCap*/::writeSchema (Buffer& buf)
buf.putShortString (packageName); // Package Name
buf.putShortString (className); // Class Name
buf.putBin128 (md5Sum); // Schema Hash
+ buf.putOctet (0); // No Superclass
buf.putShort (/*MGEN:Class.ConfigCount*/); // Config Element Count
buf.putShort (/*MGEN:Class.InstCount*/); // Inst Element Count
buf.putShort (/*MGEN:Class.MethodCount*/); // Method Count
diff --git a/qpid/cpp/managementgen/qmfgen/templates/Event.cpp b/qpid/cpp/managementgen/qmfgen/templates/Event.cpp
index 2ffec8bcdf..a4fc28990d 100644
--- a/qpid/cpp/managementgen/qmfgen/templates/Event.cpp
+++ b/qpid/cpp/managementgen/qmfgen/templates/Event.cpp
@@ -65,6 +65,7 @@ void Event/*MGEN:Event.NameCap*/::writeSchema (Buffer& buf)
buf.putShortString (packageName); // Package Name
buf.putShortString (eventName); // Event Name
buf.putBin128 (md5Sum); // Schema Hash
+ buf.putOctet (0); // No Superclass
buf.putShort (/*MGEN:Event.ArgCount*/); // Argument Count
// Arguments
diff --git a/qpid/cpp/src/qmf/Agent.cpp b/qpid/cpp/src/qmf/Agent.cpp
index 1071e445c8..84f37c5bb4 100644
--- a/qpid/cpp/src/qmf/Agent.cpp
+++ b/qpid/cpp/src/qmf/Agent.cpp
@@ -484,7 +484,7 @@ void AgentImpl::encodeHeader(Buffer& buf, uint8_t opcode, uint32_t seq)
{
buf.putOctet('A');
buf.putOctet('M');
- buf.putOctet('2');
+ buf.putOctet('3');
buf.putOctet(opcode);
buf.putLong (seq);
}
@@ -501,7 +501,7 @@ bool AgentImpl::checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *seq)
*opcode = buf.getOctet();
*seq = buf.getLong();
- return h1 == 'A' && h2 == 'M' && h3 == '2';
+ return h1 == 'A' && h2 == 'M' && h3 == '3';
}
AgentEventImpl::Ptr AgentImpl::eventDeclareQueue(const string& name)
diff --git a/qpid/cpp/src/qmf/SchemaImpl.cpp b/qpid/cpp/src/qmf/SchemaImpl.cpp
index 57d6148cac..716c4db4f0 100644
--- a/qpid/cpp/src/qmf/SchemaImpl.cpp
+++ b/qpid/cpp/src/qmf/SchemaImpl.cpp
@@ -272,6 +272,7 @@ void SchemaObjectClassImpl::encode(Buffer& buffer) const
buffer.putShortString(package);
buffer.putShortString(name);
hash.encode(buffer);
+ buffer.putOctet(0); // No parent class
buffer.putShort((uint16_t) properties.size());
buffer.putShort((uint16_t) statistics.size());
buffer.putShort((uint16_t) methods.size());
diff --git a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
index 6c6fbdfe3c..c5e2682cba 100644
--- a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
+++ b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
@@ -565,7 +565,7 @@ void ManagementAgentImpl::encodeHeader(Buffer& buf, uint8_t opcode, uint32_t seq
{
buf.putOctet('A');
buf.putOctet('M');
- buf.putOctet('2');
+ buf.putOctet('3');
buf.putOctet(opcode);
buf.putLong (seq);
}
@@ -582,7 +582,7 @@ bool ManagementAgentImpl::checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *se
*opcode = buf.getOctet();
*seq = buf.getLong();
- return h1 == 'A' && h2 == 'M' && h3 == '2';
+ return h1 == 'A' && h2 == 'M' && h3 == '3';
}
ManagementAgentImpl::PackageMap::iterator ManagementAgentImpl::findOrAddPackage(const string& name)
diff --git a/qpid/cpp/src/qpid/console/Broker.cpp b/qpid/cpp/src/qpid/console/Broker.cpp
index 4f90afd39a..68279a4f8e 100644
--- a/qpid/cpp/src/qpid/console/Broker.cpp
+++ b/qpid/cpp/src/qpid/console/Broker.cpp
@@ -72,7 +72,7 @@ void Broker::encodeHeader(Buffer& buf, uint8_t opcode, uint32_t seq) const
{
buf.putOctet('A');
buf.putOctet('M');
- buf.putOctet('2');
+ buf.putOctet('3');
buf.putOctet(opcode);
buf.putLong (seq);
}
@@ -89,7 +89,7 @@ bool Broker::checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *seq) const
*opcode = buf.getOctet();
*seq = buf.getLong();
- return h1 == 'A' && h2 == 'M' && h3 == '2';
+ return h1 == 'A' && h2 == 'M' && h3 == '3';
}
void Broker::received(qpid::client::Message& msg)
diff --git a/qpid/cpp/src/qpid/console/Schema.cpp b/qpid/cpp/src/qpid/console/Schema.cpp
index 9b4312d11f..a248b2d09a 100644
--- a/qpid/cpp/src/qpid/console/Schema.cpp
+++ b/qpid/cpp/src/qpid/console/Schema.cpp
@@ -119,9 +119,18 @@ SchemaClass::SchemaClass(const uint8_t _kind, const ClassKey& _key, framing::Buf
kind(_kind), key(_key)
{
if (kind == KIND_TABLE) {
- uint16_t propCount = buffer.getShort();
- uint16_t statCount = buffer.getShort();
- uint16_t methodCount = buffer.getShort();
+ uint8_t hasSupertype = buffer.getOctet();
+ uint16_t propCount = buffer.getShort();
+ uint16_t statCount = buffer.getShort();
+ uint16_t methodCount = buffer.getShort();
+
+ if (hasSupertype) {
+ string unused;
+ buffer.getShortString(unused);
+ buffer.getShortString(unused);
+ buffer.getLongLong();
+ buffer.getLongLong();
+ }
for (uint16_t idx = 0; idx < propCount; idx++)
properties.push_back(new SchemaProperty(buffer));
diff --git a/qpid/cpp/src/qpid/console/Value.cpp b/qpid/cpp/src/qpid/console/Value.cpp
index 1a7f690baf..c557699f33 100644
--- a/qpid/cpp/src/qpid/console/Value.cpp
+++ b/qpid/cpp/src/qpid/console/Value.cpp
@@ -114,7 +114,7 @@ string MapValue::str() const
MapValue::MapValue(framing::Buffer& buffer)
{
- value.decode(buffer);
+ value.qmfDecode(buffer);
}
diff --git a/qpid/cpp/src/qpid/console/Value.h b/qpid/cpp/src/qpid/console/Value.h
index 5a0915c69b..fbbe0b6a58 100644
--- a/qpid/cpp/src/qpid/console/Value.h
+++ b/qpid/cpp/src/qpid/console/Value.h
@@ -98,6 +98,8 @@ namespace console {
std::string str() const;
bool isUint() const { return true; }
uint32_t asUint() const { return value; }
+ bool isUint64() const { return true; }
+ uint64_t asUint64() const { return (uint64_t) value; }
private:
uint32_t value;
};
@@ -108,6 +110,8 @@ namespace console {
std::string str() const;
bool isInt() const { return true; }
int32_t asInt() const { return value; }
+ bool isInt64() const { return true; }
+ int64_t asInt64() const { return (int64_t) value; }
private:
int32_t value;
};
@@ -160,6 +164,8 @@ namespace console {
std::string str() const;
bool isFloat() const { return true; }
float asFloat() const { return value; }
+ bool isDouble() const { return true; }
+ double asDouble() const { return (double) value; }
private:
float value;
};
diff --git a/qpid/cpp/src/qpid/framing/FieldTable.cpp b/qpid/cpp/src/qpid/framing/FieldTable.cpp
index 559aa8b013..3e0921fe8d 100644
--- a/qpid/cpp/src/qpid/framing/FieldTable.cpp
+++ b/qpid/cpp/src/qpid/framing/FieldTable.cpp
@@ -53,6 +53,23 @@ uint32_t FieldTable::encodedSize() const {
return len;
}
+uint32_t FieldTable::qmfEncodedSize() const {
+ uint32_t len(4/*size field*/ + 4/*count field*/);
+ for(ValueMap::const_iterator i = values.begin(); i != values.end(); ++i) {
+ // shortstr_len_byte + key size + typecode
+ len += 1 + (i->first).size() + 1;
+ ValuePtr value(i->second);
+ if (value->convertsTo<int>()) {
+ len += 4;
+ } else if (value->convertsTo<uint64_t>()) {
+ len += 8;
+ } else if (value->convertsTo<string>()) {
+ len += 2 + value->get<string>().size();
+ }
+ }
+ return len;
+}
+
int FieldTable::count() const {
return values.size();
}
@@ -191,7 +208,7 @@ bool FieldTable::getDouble(const std::string& name, double& value) const {
// return getValue<uint64_t>(name);
//}
-void FieldTable::encode(Buffer& buffer) const{
+void FieldTable::encode(Buffer& buffer) const {
buffer.putLong(encodedSize() - 4);
buffer.putLong(values.size());
for (ValueMap::const_iterator i = values.begin(); i!=values.end(); ++i) {
@@ -220,6 +237,122 @@ void FieldTable::decode(Buffer& buffer){
}
}
+#define QMF_TYPE_U8 1
+#define QMF_TYPE_U16 2
+#define QMF_TYPE_U32 3
+#define QMF_TYPE_U64 4
+#define QMF_TYPE_SSTR 6
+#define QMF_TYPE_LSTR 7
+#define QMF_TYPE_ABSTIME 8
+#define QMF_TYPE_DELTATIME 9
+#define QMF_TYPE_REF 10
+#define QMF_TYPE_BOOL 11
+#define QMF_TYPE_FLOAT 12
+#define QMF_TYPE_DOUBLE 13
+#define QMF_TYPE_UUID 14
+#define QMF_TYPE_S8 16
+#define QMF_TYPE_S16 17
+#define QMF_TYPE_S32 18
+#define QMF_TYPE_S64 19
+#define QMF_TYPE_OBJECT 20
+#define QMF_TYPE_MAP 15
+#define QMF_TYPE_LIST 21
+#define QMF_TYPE_ARRAY 22
+
+void FieldTable::qmfEncode(Buffer& buffer) const {
+ buffer.putLong(qmfEncodedSize() - 4);
+ buffer.putLong(values.size());
+ for (ValueMap::const_iterator i = values.begin(); i!=values.end(); ++i) {
+ ValuePtr value(i->second);
+ buffer.putShortString(i->first);
+ if (value->convertsTo<int>()) {
+ buffer.putOctet(QMF_TYPE_S32);
+ buffer.putLong(value->get<int>());
+ } else if (value->convertsTo<uint64_t>()) {
+ buffer.putOctet(QMF_TYPE_U64);
+ buffer.putLongLong(value->get<uint64_t>());
+ } else if (value->convertsTo<string>()) {
+ buffer.putOctet(QMF_TYPE_LSTR);
+ buffer.putMediumString(value->get<string>());
+ }
+ }
+}
+
+void FieldTable::qmfDecode(Buffer& buffer) {
+ clear();
+ uint32_t len = buffer.getLong();
+ if (len) {
+ uint32_t available = buffer.available();
+ if (available < len)
+ throw IllegalArgumentException(QPID_MSG("Not enough data for field table."));
+ uint32_t count = buffer.getLong();
+ uint32_t leftover = available - len;
+ while(buffer.available() > leftover && count--) {
+ std::string name;
+ std::string sstr;
+ std::string lstr;
+ buffer.getShortString(name);
+ uint8_t typecode = buffer.getOctet();
+ switch (typecode) {
+ case QMF_TYPE_U8:
+ values[name] = ValuePtr(new IntegerValue(buffer.getOctet()));
+ break;
+ case QMF_TYPE_U16:
+ values[name] = ValuePtr(new IntegerValue(buffer.getShort()));
+ break;
+ case QMF_TYPE_U32:
+ values[name] = ValuePtr(new IntegerValue(buffer.getLong()));
+ break;
+ case QMF_TYPE_U64:
+ values[name] = ValuePtr(new Unsigned64Value(buffer.getLongLong()));
+ break;
+ case QMF_TYPE_SSTR:
+ buffer.getShortString(sstr);
+ values[name] = ValuePtr(new Str16Value(sstr));
+ break;
+ case QMF_TYPE_LSTR:
+ buffer.getMediumString(lstr);
+ values[name] = ValuePtr(new Str16Value(lstr));
+ break;
+ case QMF_TYPE_ABSTIME:
+ values[name] = ValuePtr(new Unsigned64Value(buffer.getLongLong()));
+ break;
+ case QMF_TYPE_DELTATIME:
+ values[name] = ValuePtr(new Unsigned64Value(buffer.getLongLong()));
+ break;
+ case QMF_TYPE_BOOL:
+ values[name] = ValuePtr(new IntegerValue(buffer.getOctet()));
+ break;
+ case QMF_TYPE_FLOAT:
+ values[name] = ValuePtr(new FloatValue(buffer.getFloat()));
+ break;
+ case QMF_TYPE_DOUBLE:
+ values[name] = ValuePtr(new DoubleValue(buffer.getDouble()));
+ break;
+ case QMF_TYPE_S8:
+ values[name] = ValuePtr(new IntegerValue(buffer.getOctet()));
+ break;
+ case QMF_TYPE_S16:
+ values[name] = ValuePtr(new IntegerValue(buffer.getShort()));
+ break;
+ case QMF_TYPE_S32:
+ values[name] = ValuePtr(new IntegerValue(buffer.getLong()));
+ break;
+ case QMF_TYPE_S64:
+ values[name] = ValuePtr(new Unsigned64Value(buffer.getLongLong()));
+ break;
+ case QMF_TYPE_REF:
+ case QMF_TYPE_UUID:
+ case QMF_TYPE_OBJECT:
+ case QMF_TYPE_MAP:
+ case QMF_TYPE_LIST:
+ case QMF_TYPE_ARRAY:
+ break;
+ }
+ }
+ }
+}
+
bool FieldTable::operator==(const FieldTable& x) const {
if (values.size() != x.values.size()) return false;
diff --git a/qpid/cpp/src/qpid/framing/FieldTable.h b/qpid/cpp/src/qpid/framing/FieldTable.h
index a07568559f..dfadfebdcb 100644
--- a/qpid/cpp/src/qpid/framing/FieldTable.h
+++ b/qpid/cpp/src/qpid/framing/FieldTable.h
@@ -60,6 +60,10 @@ class FieldTable
QPID_COMMON_EXTERN void encode(Buffer& buffer) const;
QPID_COMMON_EXTERN void decode(Buffer& buffer);
+ QPID_COMMON_EXTERN uint32_t qmfEncodedSize() const;
+ QPID_COMMON_EXTERN void qmfEncode(Buffer& buffer) const;
+ QPID_COMMON_EXTERN void qmfDecode(Buffer& buffer);
+
QPID_COMMON_EXTERN int count() const;
QPID_COMMON_EXTERN void set(const std::string& name, const ValuePtr& value);
QPID_COMMON_EXTERN ValuePtr get(const std::string& name) const;
diff --git a/qpid/cpp/src/qpid/management/ManagementAgent.cpp b/qpid/cpp/src/qpid/management/ManagementAgent.cpp
index 8fcc5264e4..d0ad80902b 100644
--- a/qpid/cpp/src/qpid/management/ManagementAgent.cpp
+++ b/qpid/cpp/src/qpid/management/ManagementAgent.cpp
@@ -246,7 +246,7 @@ void ManagementAgent::encodeHeader (Buffer& buf, uint8_t opcode, uint32_t seq)
{
buf.putOctet ('A');
buf.putOctet ('M');
- buf.putOctet ('2');
+ buf.putOctet ('3');
buf.putOctet (opcode);
buf.putLong (seq);
}
@@ -260,7 +260,7 @@ bool ManagementAgent::checkHeader (Buffer& buf, uint8_t *opcode, uint32_t *seq)
*opcode = buf.getOctet();
*seq = buf.getLong();
- return h1 == 'A' && h2 == 'M' && h3 == '2';
+ return h1 == 'A' && h2 == 'M' && h3 == '3';
}
void ManagementAgent::sendBuffer(Buffer& buf,
@@ -1097,10 +1097,18 @@ size_t ManagementAgent::validateTableSchema(Buffer& inBuffer)
inBuffer.getShortString(text);
inBuffer.getBin128(hash);
+ uint8_t superType = inBuffer.getOctet();
+
uint16_t propCount = inBuffer.getShort();
uint16_t statCount = inBuffer.getShort();
uint16_t methCount = inBuffer.getShort();
+ if (superType == 1) {
+ inBuffer.getShortString(text);
+ inBuffer.getShortString(text);
+ inBuffer.getBin128(hash);
+ }
+
for (uint16_t idx = 0; idx < propCount + statCount; idx++) {
FieldTable ft;
ft.decode(inBuffer);
@@ -1142,9 +1150,16 @@ size_t ManagementAgent::validateEventSchema(Buffer& inBuffer)
inBuffer.getShortString(text);
inBuffer.getShortString(text);
inBuffer.getBin128(hash);
+
+ uint8_t superType = inBuffer.getOctet();
uint16_t argCount = inBuffer.getShort();
+ if (superType == 1) {
+ inBuffer.getShortString(text);
+ inBuffer.getShortString(text);
+ inBuffer.getBin128(hash);
+ }
for (uint16_t idx = 0; idx < argCount; idx++) {
FieldTable ft;
ft.decode(inBuffer);
diff --git a/qpid/java/agent/build.xml b/qpid/java/agent/build.xml
new file mode 100644
index 0000000000..7d83f009e9
--- /dev/null
+++ b/qpid/java/agent/build.xml
@@ -0,0 +1,41 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<project name="QMF Agent" default="build">
+
+ <property name="module.depends" value="common client jms"/>
+ <property name="module.main" value="org.apache.qpid.agent.Agent"/>
+
+ <import file="../module.xml"/>
+
+ <target name="copy-bin-release" description="copy dependencies into module release">
+ <copy todir="${module.release}/bin" failonerror="true">
+ <fileset dir="${module.bin}"/>
+ </copy>
+ <copy todir="${module.release}/bin" failonerror="true" flatten="true">
+ <fileset dir="${basedir}/../common/bin"/>
+ </copy>
+ <chmod dir="${module.release}/bin" perm="ugo+rx" includes="**/*"/>
+
+ </target>
+
+ <target name="release-bin" depends="release-bin-tasks"/>
+
+</project>
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/Agent.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/Agent.java
new file mode 100644
index 0000000000..fa80694017
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/Agent.java
@@ -0,0 +1,650 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import javax.jms.BytesMessage;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.agent.binding.BindingContext;
+import org.apache.qpid.agent.binding.BindingUtils;
+import org.apache.qpid.agent.binding.ClassBinding;
+import org.apache.qpid.agent.binding.BindingException;
+import org.apache.qpid.agent.binding.MethodBinding;
+import org.apache.qpid.agent.binding.ParameterBinding;
+import org.apache.qpid.agent.binding.PropertyBinding;
+import org.apache.qpid.agent.binding.TypeBinding;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.transport.codec.BBDecoder;
+import org.apache.qpid.transport.codec.BBEncoder;
+import org.apache.qpid.transport.codec.Decoder;
+
+/**
+ * Agent
+ *
+ */
+public class Agent implements MessageListener
+{
+ // The following are settings to configure the Agent
+ private AMQConnection connection;
+ private boolean sessionTransacted = false;
+ private int acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+ private String label;
+ private UUID systemId;
+ // this list holds the objects until the agent is started
+ private List managedObjects = new ArrayList();
+ private List registeredClasses = new ArrayList();
+ // The following instance variables are not
+ // able to be set by the end user.
+ private Session session;
+ private MessageProducer prod;
+ private MessageConsumer cons;
+ private Queue reply;
+ private BindingContext bctx = new BindingContext();
+ private Map<Long, ManagedObject> objects = new Hashtable<Long, ManagedObject>();
+ private long bbank;
+ private long abank;
+ private static Log log = LogFactory.getLog(Agent.class);
+ private volatile boolean inside = false;
+
+ public Agent()
+ {
+ systemId = UUID.randomUUID();
+ log.debug(String.format("Agent with uid %s created", systemId
+ .toString()));
+ }
+
+ public Agent(String label, UUID systemId)
+ {
+ this.systemId = systemId;
+ this.label = label;
+ log.debug(String.format("Agent with name %s and uid %s created", label,
+ systemId.toString()));
+ }
+
+ public void register(ManagedObject managedObject)
+ {
+ Class managedClass = managedObject.getObjectClass();
+ long id = managedObject.getId();
+ ClassBinding cb = bctx.register(managedClass);
+ managedObject.setManagedClassName(cb.getName());
+ managedObject.setManagedPackageName(cb.getPackage());
+ log.debug(String.format(
+ "Added managed object id '%d' for package '%s' class '%s'", id,
+ managedObject.getManagedPackageName(), managedObject
+ .getManagedClassName()));
+ objects.put(id, managedObject);
+ managedObjects.add(managedObject);
+ }
+
+ public void registerClass(Class cls)
+ {
+ bctx.register(cls);
+ if (!registeredClasses.contains(cls))
+ {
+ registeredClasses.add(cls);
+ }
+ }
+
+ public void start()
+ {
+ log.debug(String.format("Agent with uid %s and name %s starting",
+ systemId.toString(), label));
+ for (Object clsName : registeredClasses.toArray())
+ {
+ try
+ {
+ Class cls = Class.forName(clsName.toString());
+ this.registerClass(cls);
+ } catch (Exception e)
+ {
+ log.error("Could not register class " + clsName);
+ }
+ }
+ for (Object obj : managedObjects.toArray())
+ {
+ this.register((ManagedObject) obj);
+ }
+ try
+ {
+ session = connection.createSession(sessionTransacted,
+ acknowledgeMode);
+ reply = session.createQueue("direct://amq.direct//" + label);
+ cons = session.createConsumer(reply);
+ cons.setMessageListener(this);
+ prod = session.createProducer(null);
+ } catch (JMSException e)
+ {
+ throw new AgentException(e);
+ }
+ attachRequest(label, systemId);
+ try
+ {
+ connection.start();
+ } catch (JMSException e)
+ {
+ throw new AgentException(e);
+ }
+ }
+
+ public void raiseEvent(Object value, EventSeverity sev)
+ {
+ log.debug(String.format("Sending event of class %s with Severity %s",
+ value.getClass(), sev.ordinal()));
+ BBEncoder enc = this.init('e');
+ ClassBinding cb = bctx.getClassBinding(value.getClass());
+ String pkg = cb.getPackage();
+ String cls = cb.getName();
+ enc.writeStr8(pkg);
+ enc.writeStr8(cls);
+ enc.writeBin128(cb.getSchemaHash());
+ long now = System.currentTimeMillis() * 1000000;
+ enc.writeInt64(now);
+ enc.writeUint8((short) sev.ordinal());
+ for (PropertyBinding p : cb.getProperties())
+ {
+ p.getType().encode(enc, BindingUtils.get(p, value));
+ }
+ send(
+ String.format("console.event.%d.%d.%s.%s", bbank, abank, pkg,
+ cls), enc);
+ }
+
+ public void onMessage(Message message)
+ {
+ if (inside)
+ {
+ new Throwable().printStackTrace();
+ }
+ inside = true;
+ Decoder dec = readBody(message);
+ Destination replyTo;
+ try
+ {
+ replyTo = message.getJMSReplyTo();
+ } catch (JMSException e)
+ {
+ throw new AgentException(e);
+ }
+ byte[] magic = dec.readBytes(3);
+ if (magic[0] != 'A' || magic[1] != 'M' || magic[2] != '2')
+ {
+ throw new AgentException("bad magic: " + new String(magic));
+ }
+ short op = dec.readUint8();
+ long seq = dec.readUint32();
+ log.debug("Message recieved: " + (char) op);
+ switch (op)
+ {
+ case 'a':
+ this.handleAgentAttach(seq, replyTo, dec);
+ break;
+ case 'G':
+ this.handleGetQuery(seq, replyTo, dec);
+ break;
+ case 'M':
+ this.handleMethodRequest(seq, replyTo, dec);
+ break;
+ case 'S':
+ this.handleSchemaRequest(seq, replyTo, dec);
+ break;
+ case 'x':
+ // TODO
+ break;
+ default:
+ throw new IllegalArgumentException("opcode: " + ((char) op));
+ }
+ inside = false;
+ }
+
+ protected ClassBinding getClassBinding(ManagedObject mobj)
+ {
+ return bctx.getClassBinding(mobj.getObjectClass());
+ }
+
+ private byte[] ensure(int capacity, byte[] body, int size)
+ {
+ if (capacity > body.length)
+ {
+ byte[] copy = new byte[capacity];
+ System.arraycopy(body, 0, copy, 0, size);
+ body = copy;
+ }
+ return body;
+ }
+
+ private Decoder readBody(Message message)
+ {
+ BytesMessage msg = (BytesMessage) message;
+ BBDecoder dec = new BBDecoder();
+ byte[] buf = new byte[1024];
+ byte[] body = new byte[1024];
+ int size = 0;
+ int n;
+ try
+ {
+ while ((n = msg.readBytes(buf)) > 0)
+ {
+ body = ensure(size + n, body, size);
+ System.arraycopy(buf, 0, body, size, n);
+ size += n;
+ }
+ } catch (JMSException e)
+ {
+ throw new AgentException(e);
+ }
+ dec.init(ByteBuffer.wrap(body, 0, size));
+ return dec;
+ }
+
+ protected void handleAgentAttach(long seq, Destination replyTo, Decoder dec)
+ {
+ log.debug("Agent Attach Message");
+ bbank = dec.readUint32();
+ abank = dec.readUint32();
+ try
+ {
+ MessageConsumer mc = session
+ .createConsumer(session
+ .createQueue(String
+ .format(
+ "management://qpid.management//%s?routingkey='agent.%d.%d'",
+ label, bbank, abank)));
+ mc.setMessageListener(this);
+ } catch (JMSException e)
+ {
+ throw new AgentException(e);
+ }
+ for (String packageName : bctx.getPackages())
+ {
+ packageIndication(packageName);
+ }
+ for (ClassBinding cb : bctx.getAllBindings())
+ {
+ classIndication(cb);
+ }
+ for (ManagedObject mo : objects.values())
+ {
+ content('i', seq, null, mo);
+ }
+ }
+
+ protected void handleMethodRequest(long seq, Destination replyTo,
+ Decoder dec)
+ {
+ dec.readUint64(); // first part of object-id
+ long id = dec.readUint64();
+ ManagedObject mo = objects.get(id);
+ if (mo == null)
+ {
+ methodResponse(seq, replyTo, 1, String.format(
+ "no such object: 0x%x", id));
+ } else
+ {
+ dec.readStr8(); // pkg
+ dec.readStr8(); // cls
+ dec.readBin128(); // hash
+ String mname = dec.readStr8();
+ ClassBinding cls = getClassBinding(mo);
+ MethodBinding method = cls.getMethod(mname);
+ if (method == null)
+ {
+ methodResponse(seq, replyTo, 2, String.format(
+ "no such method: %s", mname));
+ } else
+ {
+ log.trace("Handle method: " + method.getName());
+ List<ParameterBinding> params = method.getInParameters();
+ Object[] args = new Object[params.size()];
+ int idx = 0;
+ for (ParameterBinding p : params)
+ {
+ TypeBinding typeBinding = p.getType();
+ log
+ .trace(String
+ .format(
+ "Decoding parameter with type %s ref package %s ref class %s ",
+ typeBinding.getCode(), typeBinding
+ .getRefPackage(),
+ typeBinding.getRefClass()));
+ args[idx++] = typeBinding.decode(dec);
+ log.trace("Done");
+ }
+ try
+ {
+ Object[] result = mo.invoke(method, args);
+ methodResponse(seq, replyTo, 0, null, method, result);
+ } catch (BindingException ex)
+ {
+ log
+ .error(String
+ .format(
+ "An exception occured invoking method %s. Stack trace sent to console.",
+ method.getName()));
+ StringWriter str = new StringWriter();
+ PrintWriter writer = new PrintWriter(str);
+ ex.printStackTrace(writer);
+ writer.flush();
+ methodResponse(seq, replyTo, 7, str.toString());
+ }
+ log.trace("Done with method: " + method.getName());
+ }
+ }
+ }
+
+ protected void handleGetQuery(long seq, Destination replyTo, Decoder dec)
+ {
+ Map<String, Object> data = dec.readMap();
+ if (data.containsKey("_objectid"))
+ {
+ long objId = (Long) data.get("_objectid");
+ log.debug("Get Request message for object id " + objId);
+ ManagedObject mo = objects.get(objId);
+ if (mo == null)
+ {
+ methodResponse(seq, replyTo, 1, String.format(
+ "no such object: 0x%x", objId));
+ } else
+ {
+ content('g', seq, replyTo, mo);
+ }
+ } else if (data.containsKey("_class"))
+ {
+ String className = (String) data.get("_class");
+ String packageName = (String) data.get("_package");
+ log.debug(String.format(
+ "Get Request message for package '%s' class '%s'",
+ packageName, className));
+ for (ManagedObject mo : objects.values())
+ {
+ if (mo.getManagedClassName().equals(className))
+ {
+ if ((packageName == null) || packageName.equals("")
+ || packageName.equals(mo.getManagedPackageName()))
+ {
+ content('g', seq, replyTo, mo);
+ }
+ }
+ }
+ } else
+ {
+ for (ManagedObject mo : objects.values())
+ {
+ content('g', seq, replyTo, mo);
+ }
+ }
+ complete(seq, replyTo);
+ }
+
+ protected void handleSchemaRequest(long seq, Destination replyTo,
+ Decoder dec)
+ {
+ String pkg = dec.readStr8();
+ String cls = dec.readStr8();
+ log.debug(String.format(
+ "SchemaRequest message for package '%s' class '%s'", pkg, cls));
+ ClassBinding cb = bctx.getClassBinding(pkg, cls);
+ if (cb == null)
+ {
+ throw new AgentException("no such class: " + pkg + ", " + cls);
+ }
+ schemaResponse(seq, cb);
+ }
+
+ protected BBEncoder init(char opcode)
+ {
+ return init(opcode, 0);
+ }
+
+ protected BBEncoder init(char opcode, long sequence)
+ {
+ BBEncoder enc = new BBEncoder(1024);
+ enc.init();
+ enc.writeUint8((short) 'A');
+ enc.writeUint8((short) 'M');
+ enc.writeUint8((short) '2');
+ enc.writeUint8((short) opcode);
+ enc.writeUint32(sequence);
+ return enc;
+ }
+
+ protected void send(BBEncoder enc)
+ {
+ send("broker", enc);
+ }
+
+ protected void send(Destination dest, BBEncoder enc)
+ {
+ try
+ {
+ byte[] buf = new byte[1024];
+ byte[] body = new byte[1024];
+ BytesMessage msg = session.createBytesMessage();
+ ByteBuffer slice = enc.segment();
+ while (slice.hasRemaining())
+ {
+ int n = Math.min(buf.length, slice.remaining());
+ slice.get(buf, 0, n);
+ msg.writeBytes(buf, 0, n);
+ }
+ msg.setJMSReplyTo(reply);
+ // ???: I assume this is thread safe.
+ prod.send(dest, msg);
+ } catch (JMSException e)
+ {
+ throw new AgentException(e);
+ }
+ }
+
+ protected void send(String routingKey, BBEncoder enc)
+ {
+ try
+ {
+ send(session
+ .createQueue("management://qpid.management//?routingkey='"
+ + routingKey + "'"), enc);
+ } catch (JMSException e)
+ {
+ throw new AgentException(e);
+ }
+ }
+
+ private void attachRequest(String label, UUID systemId)
+ {
+ BBEncoder enc = init('A');
+ enc.writeStr8(label);
+ enc.writeUuid(systemId);
+ enc.writeUint32(0);
+ enc.writeUint32(0);
+ send(enc);
+ }
+
+ private void packageIndication(String pkg)
+ {
+ BBEncoder enc = init('p');
+ enc.writeStr8(pkg);
+ send(enc);
+ }
+
+ private void classIndication(ClassBinding cb)
+ {
+ BBEncoder enc = init('q');
+ enc.writeUint8(cb.getKind());
+ enc.writeStr8(cb.getPackage());
+ enc.writeStr8(cb.getName());
+ enc.writeBin128(cb.getSchemaHash()); // schema hash?
+ send(enc);
+ }
+
+ private void schemaResponse(long seq, ClassBinding cb)
+ {
+ BBEncoder enc = init('s', seq);
+ cb.encode(enc);
+ send(enc);
+ }
+
+ private void content(char c, long seq, Destination dest, ManagedObject mo)
+ {
+ BBEncoder enc = init(c, seq);
+ ClassBinding cb = getClassBinding(mo);
+ String pkg = cb.getPackage();
+ String cls = cb.getName();
+ enc.writeStr8(pkg);
+ enc.writeStr8(cls);
+ enc.writeBin128(cb.getSchemaHash());
+ long now = System.currentTimeMillis() * 1000000;
+ enc.writeUint64(now);
+ enc.writeUint64(now);
+ enc.writeUint64(0);
+ enc.writeUint64(0x0000FFFFFFFFFFFFL & ((bbank << 28) | abank));
+ enc.writeUint64(mo.getId());
+ for (PropertyBinding p : cb.getProperties())
+ {
+ p.getType().encode(enc, mo.get(p));
+ }
+ if (dest == null)
+ {
+ send(String.format("console.obj.%d.%d.%s.%s", bbank, abank, pkg,
+ cls), enc);
+ } else
+ {
+ send(dest, enc);
+ }
+ }
+
+ private void complete(long seq, Destination dest)
+ {
+ BBEncoder enc = init('z', seq);
+ enc.writeUint32(0);
+ enc.writeStr8("");
+ send(dest, enc);
+ }
+
+ private void methodResponse(long seq, Destination dest, int status,
+ String text)
+ {
+ methodResponse(seq, dest, status, text, null, null);
+ }
+
+ private void methodResponse(long seq, Destination dest, int status,
+ String text, MethodBinding method, Object[] result)
+ {
+ BBEncoder enc = init('m', seq);
+ enc.writeUint32(status);
+ enc.writeStr16(text == null ? "" : text);
+ if (method != null)
+ {
+ int idx = 0;
+ for (ParameterBinding p : method.getOutParameters())
+ {
+ p.getType().encode(enc, result[idx++]);
+ }
+ }
+ send(dest, enc);
+ }
+
+ public String getLabel()
+ {
+ return label;
+ }
+
+ public void setLabel(String label)
+ {
+ this.label = label;
+ }
+
+ public AMQConnection getConnection()
+ {
+ return connection;
+ }
+
+ public void setConnection(AMQConnection connection)
+ {
+ this.connection = connection;
+ }
+
+ public boolean isSessionTransacted()
+ {
+ return sessionTransacted;
+ }
+
+ public void setSessionTransacted(boolean sessionTransacted)
+ {
+ this.sessionTransacted = sessionTransacted;
+ }
+
+ public void setManagedObjects(List objectList)
+ {
+ this.managedObjects = objectList;
+ }
+
+ public List getManagedObjects()
+ {
+ return managedObjects;
+ }
+
+ public void setRegisteredClasses(List objectList)
+ {
+ this.registeredClasses = objectList;
+ }
+
+ public List getRegisteredClasses()
+ {
+ return this.registeredClasses;
+ }
+
+ public static void main(String[] args) throws Exception
+ {
+ String broker = args[0];
+ String name = args[1];
+ String url = String.format(
+ "amqp://guest:guest@/?brokerlist='tcp://%s'", broker);
+ AMQConnection conn = new AMQConnection(url);
+ Agent agent = new Agent(name, UUID.randomUUID());
+ agent.setConnection(conn);
+ for (int i = 2; i < args.length; i++)
+ {
+ Class<?> cls = Class.forName(args[i]);
+ agent.register(new ManagedPOJO(cls.newInstance()));
+ }
+ agent.start();
+ while (true)
+ {
+ Thread.sleep(1000);
+ }
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/AgentException.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/AgentException.java
new file mode 100644
index 0000000000..ed189d2bc0
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/AgentException.java
@@ -0,0 +1,43 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent;
+
+/**
+ * AgentException
+ *
+ */
+public class AgentException extends RuntimeException
+{
+ public AgentException(String msg)
+ {
+ super(msg);
+ }
+
+ public AgentException(Throwable t)
+ {
+ super(t);
+ }
+
+ public AgentException(String msg, Throwable t)
+ {
+ super(msg, t);
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/EventSeverity.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/EventSeverity.java
new file mode 100644
index 0000000000..a3528d9804
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/EventSeverity.java
@@ -0,0 +1,6 @@
+package org.apache.qpid.agent;
+
+public enum EventSeverity
+{
+ EMERGENCY, ALERT, CRIT, ERROR, WARN, NOTICE, INFO, DEBUG
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedEJB.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedEJB.java
new file mode 100644
index 0000000000..c27ff7acc6
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedEJB.java
@@ -0,0 +1,104 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.apache.qpid.agent.binding.BindingUtils;
+import org.apache.qpid.agent.binding.MethodBinding;
+import org.apache.qpid.agent.binding.PropertyBinding;
+
+public class ManagedEJB extends ManagedObjectBase
+{
+ protected String className;
+ protected String jndiLocation;
+
+ protected Object getEJB()
+ {
+ try
+ {
+ InitialContext ctx = new InitialContext();
+ return ctx.lookup(jndiLocation);
+ } catch (NamingException e)
+ {
+ throw new AgentException("Error looking up EJB at " + jndiLocation,
+ e);
+ }
+ }
+
+ @Override
+ public Object get(PropertyBinding property)
+ {
+ return BindingUtils.get(property, this.getEJB());
+ }
+
+ @Override
+ public long getId()
+ {
+ return System.identityHashCode(this);
+ }
+
+ @Override
+ public Class getObjectClass()
+ {
+ try
+ {
+ return Class.forName(className);
+ } catch (ClassNotFoundException e)
+ {
+ throw new AgentException(String.format(
+ "No class named %s was found", className), e);
+ }
+ }
+
+ @Override
+ public Object[] invoke(MethodBinding method, Object... args)
+ {
+ return BindingUtils.invoke(method, this.getEJB(), args);
+ }
+
+ @Override
+ public void set(PropertyBinding property, Object value)
+ {
+ BindingUtils.set(property, value, this.getEJB());
+ }
+
+ public String getClassName()
+ {
+ return className;
+ }
+
+ public void setClassName(String className)
+ {
+ this.className = className;
+ }
+
+ public String getJndiLocation()
+ {
+ return jndiLocation;
+ }
+
+ public void setJndiLocation(String jndiLocation)
+ {
+ this.jndiLocation = jndiLocation;
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedObject.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedObject.java
new file mode 100644
index 0000000000..679ee81d76
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedObject.java
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent;
+
+import org.apache.qpid.agent.binding.MethodBinding;
+import org.apache.qpid.agent.binding.PropertyBinding;
+
+public interface ManagedObject
+{
+ public abstract long getId();
+
+ public abstract Class getObjectClass();
+
+ public abstract Object get(PropertyBinding property);
+
+ public abstract void set(PropertyBinding property, Object value);
+
+ public abstract Object[] invoke(MethodBinding method, Object... args);
+
+ public abstract String getName();
+
+ public abstract void setName(String name);
+
+ public String getManagedClassName();
+
+ public String getManagedPackageName();
+
+ public void setManagedClassName(String aName);
+
+ public void setManagedPackageName(String aName);
+} \ No newline at end of file
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedObjectBase.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedObjectBase.java
new file mode 100644
index 0000000000..51789ae11f
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedObjectBase.java
@@ -0,0 +1,72 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.agent.binding.MethodBinding;
+import org.apache.qpid.agent.binding.PropertyBinding;
+
+public abstract class ManagedObjectBase implements ManagedObject
+{
+ private static Log log = LogFactory.getLog(ManagedObjectBase.class);
+ protected String name;
+ protected String managedClassName;
+ protected String managedPackageName;
+
+ public abstract long getId();
+
+ public abstract Object get(PropertyBinding property);
+
+ public abstract void set(PropertyBinding property, Object value);
+
+ public abstract Object[] invoke(MethodBinding method, Object... args);
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public String getManagedClassName()
+ {
+ return managedClassName;
+ }
+
+ public void setManagedClassName(String managedClassName)
+ {
+ this.managedClassName = managedClassName;
+ }
+
+ public String getManagedPackageName()
+ {
+ return managedPackageName;
+ }
+
+ public void setManagedPackageName(String managedPackageName)
+ {
+ this.managedPackageName = managedPackageName;
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedPOJO.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedPOJO.java
new file mode 100644
index 0000000000..9a707fe09e
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/ManagedPOJO.java
@@ -0,0 +1,87 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.agent.binding.BindingUtils;
+import org.apache.qpid.agent.binding.MethodBinding;
+import org.apache.qpid.agent.binding.PropertyBinding;
+
+public class ManagedPOJO extends ManagedObjectBase implements ManagedObject
+{
+ private Log log = LogFactory.getLog(ManagedPOJO.class);
+ private Object managed;
+
+ public ManagedPOJO()
+ {
+ super();
+ }
+
+ public ManagedPOJO(Object managed)
+ {
+ super();
+ this.setManaged(managed);
+ }
+
+ @Override
+ public long getId()
+ {
+ if (managed == null)
+ {
+ throw new AgentException("The managed object is null");
+ }
+ return System.identityHashCode(managed);
+ }
+
+ public Class getObjectClass()
+ {
+ return managed.getClass();
+ }
+
+ public Object getManaged()
+ {
+ return managed;
+ }
+
+ public void setManaged(Object managed)
+ {
+ this.managed = managed;
+ }
+
+ @Override
+ public Object get(PropertyBinding property)
+ {
+ return BindingUtils.get(property, managed);
+ }
+
+ @Override
+ public Object[] invoke(MethodBinding method, Object... args)
+ {
+ return BindingUtils.invoke(method, managed, args);
+ }
+
+ @Override
+ public void set(PropertyBinding property, Object value)
+ {
+ BindingUtils.set(property, value, managed);
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFEvent.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFEvent.java
new file mode 100644
index 0000000000..06ef46c648
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFEvent.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Target(TYPE)
+@Retention(RUNTIME)
+@Documented
+public @interface QMFEvent
+{
+ String eventName();
+
+ String packageName();
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFHide.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFHide.java
new file mode 100644
index 0000000000..c173e701a5
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFHide.java
@@ -0,0 +1,35 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.annotations;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RUNTIME)
+@Documented
+public @interface QMFHide
+{
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFObject.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFObject.java
new file mode 100644
index 0000000000..c883051fda
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFObject.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Target(TYPE)
+@Retention(RUNTIME)
+@Documented
+public @interface QMFObject
+{
+ String className();
+
+ String packageName();
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFProperty.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFProperty.java
new file mode 100644
index 0000000000..82e1b3a1af
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFProperty.java
@@ -0,0 +1,36 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.annotations;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Target(ElementType.FIELD)
+@Retention(RUNTIME)
+@Documented
+public @interface QMFProperty
+{
+ boolean optional() default false;
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFSeeAlso.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFSeeAlso.java
new file mode 100644
index 0000000000..924e12a574
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFSeeAlso.java
@@ -0,0 +1,36 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Target(TYPE)
+@Retention(RUNTIME)
+@Documented
+public @interface QMFSeeAlso
+{
+ Class[] value();
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFType.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFType.java
new file mode 100644
index 0000000000..2b5aaa1983
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/annotations/QMFType.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Target(TYPE)
+@Retention(RUNTIME)
+@Documented
+public @interface QMFType
+{
+ String className();
+
+ String packageName();
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/BindingContext.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/BindingContext.java
new file mode 100644
index 0000000000..480d8b526c
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/BindingContext.java
@@ -0,0 +1,209 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.agent.annotations.QMFEvent;
+import org.apache.qpid.agent.annotations.QMFObject;
+import org.apache.qpid.agent.annotations.QMFSeeAlso;
+import org.apache.qpid.agent.annotations.QMFType;
+
+public class BindingContext
+{
+ private static Log log = LogFactory.getLog(BindingContext.class);
+ private Map<Key, ClassBinding> classes = new Hashtable<Key, ClassBinding>();
+ private ArrayList<String> packages = new ArrayList<String>();
+
+ static class Key
+ {
+ String packageName = "";
+ String className = "";
+ boolean object = false;
+
+ @Override
+ public int hashCode()
+ {
+ return (packageName + "." + className).hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ return ((obj.getClass() == Key.class)
+ && (((Key) obj).packageName.equals(packageName)) && (((Key) obj).className
+ .equals(className)));
+ }
+ }
+
+ public BindingContext()
+ {
+ Key key = new Key();
+ key.className = "Object";
+ key.packageName = "org.apache.qmf";
+ key.object = false;
+ ClassBinding cb = new ClassBinding("org.apache.qmf", "Object",
+ Object.class, false, this);
+ classes.put(key, cb);
+ packages.add("org.apache.qmf");
+ }
+
+ public ClassBinding getClassBinding(Class clazz)
+ {
+ return classes.get(getClassKey(clazz));
+ }
+
+ public ClassBinding getClassBinding(String packageName, String className)
+ {
+ Key key = new Key();
+ key.packageName = packageName;
+ key.className = className;
+ return classes.get(key);
+ }
+
+ public ClassBinding register(Class cls)
+ {
+ String name = cls.getName();
+ ClassBinding cb = getClassBinding(cls);
+ if (cb == null)
+ {
+ Key key = getClassKey(cls);
+ // Create and store the internal representations
+ if (cls.isEnum())
+ {
+ cb = new EnumBinding(key.packageName, key.className, cls,
+ key.object, this);
+ } else
+ {
+ cb = new ClassBinding(key.packageName, key.className, cls,
+ key.object, this);
+ }
+ log.debug(String.format(
+ "Added class binding '%s' in package %s for class %s'",
+ key.className, key.packageName, cls.getCanonicalName()));
+ classes.put(key, cb);
+ if (!packages.contains(key.packageName))
+ {
+ packages.add(key.packageName);
+ }
+ // Parse the methods after adding the class to avoid recursion
+ cb.parse();
+ // See if there are other classes which should be looked at
+ QMFSeeAlso seeAlso = (QMFSeeAlso) cls
+ .getAnnotation(QMFSeeAlso.class);
+ if (seeAlso != null)
+ {
+ for (Class seeAlsoCls : seeAlso.value())
+ {
+ this.register(seeAlsoCls);
+ }
+ }
+ }
+ return cb;
+ }
+
+ public TypeBinding getTypeBinding(Class cls)
+ {
+ // Look for a built in type
+ TypeBinding type = QMFTypeBinding.forClass(cls);
+ // Have we seen it before?
+ if (type == null)
+ {
+ type = this.getClassBinding(cls);
+ }
+ if ((type == null) && List.class.isAssignableFrom(cls))
+ {
+ type = new ListBinding(this, cls);
+ }
+ if ((type == null) && Map.class.isAssignableFrom(cls))
+ {
+ type = new MapBinding(this, cls);
+ }
+ // Add it, but since we have not seen it before do not expose methods
+ if (type == null)
+ {
+ type = this.register(cls);
+ }
+ return type;
+ }
+
+ // FIXME: Need to store these keys off so we dont create alot of objects
+ protected Key getClassKey(Class cls)
+ {
+ Key key = new Key();
+ QMFObject objAnnotation = (QMFObject) cls
+ .getAnnotation(QMFObject.class);
+ if (objAnnotation != null)
+ {
+ key.className = objAnnotation.className();
+ key.packageName = objAnnotation.packageName();
+ key.object = true;
+ } else
+ {
+ QMFType typeAnnotation = (QMFType) cls.getAnnotation(QMFType.class);
+ if (typeAnnotation != null)
+ {
+ key.className = typeAnnotation.className();
+ key.packageName = typeAnnotation.packageName();
+ } else
+ {
+ QMFEvent eventAnnotation = (QMFEvent) cls
+ .getAnnotation(QMFEvent.class);
+ if (eventAnnotation != null)
+ {
+ key.className = eventAnnotation.eventName();
+ key.packageName = eventAnnotation.packageName();
+ } else
+ {
+ // If this is Object, we return the fake
+ // object value
+ if (cls == Object.class)
+ {
+ key.className = "Object";
+ key.packageName = "org.apache.qmf";
+ } else
+ {
+ String name = cls.getName();
+ int lastDot = name.lastIndexOf('.');
+ key.className = name.substring(lastDot + 1);
+ key.packageName = name.substring(0, lastDot);
+ }
+ }
+ }
+ }
+ return key;
+ }
+
+ public ArrayList<String> getPackages()
+ {
+ return packages;
+ }
+
+ public Collection<ClassBinding> getAllBindings()
+ {
+ return classes.values();
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/BindingException.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/BindingException.java
new file mode 100644
index 0000000000..f8e436290c
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/BindingException.java
@@ -0,0 +1,50 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+/**
+ * ManagedException
+ *
+ */
+public class BindingException extends RuntimeException
+{
+ private static final long serialVersionUID = -7350845525748113340L;
+
+ public BindingException(Throwable t)
+ {
+ super(t);
+ }
+
+ public BindingException()
+ {
+ super();
+ }
+
+ public BindingException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+ public BindingException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/BindingUtils.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/BindingUtils.java
new file mode 100644
index 0000000000..14f3fda0f1
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/BindingUtils.java
@@ -0,0 +1,137 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class BindingUtils
+{
+ private static Log log = LogFactory.getLog(BindingUtils.class);
+
+ public static Object get(PropertyBinding property, Object managed)
+ {
+ String name = property.getName();
+ return get(name, managed);
+ }
+
+ public static void set(PropertyBinding property, Object value,
+ Object managed)
+ {
+ String name = property.getName();
+ TypeBinding type = property.getType();
+ try
+ {
+ Method meth = managed.getClass().getMethod(accessor("set", name),
+ type.getJavaClass());
+ meth.invoke(managed, value);
+ } catch (NoSuchMethodException e)
+ {
+ throw new BindingException(e);
+ } catch (IllegalAccessException e)
+ {
+ throw new BindingException(e);
+ } catch (InvocationTargetException e)
+ {
+ throw new BindingException(e.getTargetException());
+ }
+ }
+
+ public static Object[] invoke(MethodBinding method, Object managed,
+ Object... args)
+ {
+ log.debug(String.format("Invoking %s on %s", method.getName(), managed
+ .getClass()));
+ List<ParameterBinding> in = method.getInParameters();
+ List<ParameterBinding> out = method.getOutParameters();
+ Class<?>[] classes = new Class<?>[in.size()];
+ int idx = 0;
+ for (ParameterBinding p : in)
+ {
+ classes[idx++] = p.getType().getJavaClass();
+ }
+ Object result;
+ try
+ {
+ Method meth = managed.getClass().getMethod(method.getName(),
+ classes);
+ result = meth.invoke(managed, args);
+ } catch (NoSuchMethodException e)
+ {
+ throw new BindingException(e);
+ } catch (IllegalAccessException e)
+ {
+ throw new BindingException(e);
+ } catch (InvocationTargetException e)
+ {
+ throw new BindingException(e.getTargetException());
+ }
+ Object[] results = new Object[out.size()];
+ // XXX: need better way to distinguish this case
+ if (out.size() == 1 && out.get(0).getName().equals("result"))
+ {
+ results[0] = result;
+ } else
+ {
+ for (int i = 0; i < results.length; i++)
+ {
+ results[i] = get(out.get(i).getName(), result);
+ }
+ }
+ return results;
+ }
+
+ public static String accessor(String pfx, String property)
+ {
+ return pfx + Character.toUpperCase(property.charAt(0))
+ + property.substring(1);
+ }
+
+ public static Object get(String name, Object obj)
+ {
+ Object returnValue = null;
+ try
+ {
+ BeanInfo info = Introspector.getBeanInfo(obj.getClass());
+ PropertyDescriptor[] pds = info.getPropertyDescriptors();
+ for (PropertyDescriptor pd : pds)
+ {
+ if (pd.getName().equals(name))
+ {
+ Method getMethod = pd.getReadMethod();
+ returnValue = getMethod.invoke(obj);
+ break;
+ }
+ }
+ } catch (Exception e)
+ {
+ throw new BindingException(e);
+ }
+ return returnValue;
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/ClassBinding.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/ClassBinding.java
new file mode 100644
index 0000000000..d1ad04adef
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/ClassBinding.java
@@ -0,0 +1,599 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.agent.annotations.QMFEvent;
+import org.apache.qpid.agent.annotations.QMFObject;
+import org.apache.qpid.agent.annotations.QMFProperty;
+import org.apache.qpid.agent.annotations.QMFSeeAlso;
+import org.apache.qpid.agent.annotations.QMFType;
+import org.apache.qpid.agent.annotations.QMFHide;
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class ClassBinding implements TypeBinding
+{
+ private static Log log = LogFactory.getLog(ClassBinding.class);
+
+ private static enum MethodType
+ {
+ READ_ONLY, READ_WRITE, METHOD, IGNORE
+ }
+
+ protected boolean exposeBehaviour = true;
+ protected String pkg;
+ protected BindingContext bctx;
+ protected String name;
+ protected ArrayList<PropertyBinding> properties = new ArrayList<PropertyBinding>();
+ protected ArrayList<MethodBinding> methods = new ArrayList<MethodBinding>();
+ protected Map<String, MethodBinding> methodsByName = new HashMap<String, MethodBinding>();
+ protected Class javaClass;
+ protected short kind = 1;
+ protected byte hash[] = null;
+ protected ClassBinding superType = null;
+
+ public ClassBinding(String pkg, String name, Class cls,
+ boolean exposeBehaviour, BindingContext bctx)
+ {
+ this.pkg = pkg;
+ this.name = name;
+ this.bctx = bctx;
+ this.javaClass = cls;
+ this.exposeBehaviour = exposeBehaviour;
+ }
+
+ protected MethodType classify(Class<?> cls, Method m)
+ {
+ String name = m.getName();
+ MethodType returnValue = MethodType.METHOD;
+ String propPrefixes[] =
+ { "get", "is" };
+ for (String prefix : propPrefixes)
+ {
+ if (name.startsWith(prefix) && m.getParameterTypes().length == 0)
+ {
+ try
+ {
+ Class<?> type = m.getReturnType();
+ Method setter = cls.getMethod("set"
+ + name.substring(prefix.length()), type);
+ returnValue = MethodType.READ_WRITE;
+ } catch (NoSuchMethodException e)
+ {
+ returnValue = MethodType.READ_ONLY;
+ }
+ break;
+ }
+ }
+ return returnValue;
+ }
+
+ protected String property(Method m)
+ {
+ String name = m.getName();
+ String propPrefixes[] =
+ { "get", "is" };
+ for (String prefix : propPrefixes)
+ {
+ if (name.startsWith(prefix) && m.getParameterTypes().length == 0)
+ {
+ String sfx = name.substring(prefix.length());
+ return Character.toLowerCase(sfx.charAt(0)) + sfx.substring(1);
+ }
+ }
+ // If we got here, it is n invalid property
+ throw new IllegalArgumentException("" + m);
+ }
+
+ protected ArrayList<Method> getMethods(Class cls)
+ {
+ ArrayList returnValue = new ArrayList();
+ ArrayList nameList = new ArrayList();
+ if ((cls != null) && (!cls.equals(Object.class)))
+ {
+ for (Method m : cls.getDeclaredMethods())
+ {
+ if (m.getAnnotation(QMFHide.class) == null)
+ // && (!Modifier.isAbstract(m.getModifiers())))
+ {
+ returnValue.add(m);
+ nameList.add(m.getName());
+ }
+ }
+ // Look at the superclass, if it is also a
+ // QMF object then stop.
+ Class superType = cls.getSuperclass();
+ if (!this.hasQMFSupertype(cls))
+ {
+ for (Method m : this.getMethods(cls.getSuperclass()))
+ {
+ if (!nameList.contains(m.getName()))
+ {
+ returnValue.add(m);
+ nameList.add(m.getName());
+ }
+ }
+ }
+ }
+ return returnValue;
+ }
+
+ protected boolean hasQMFSupertype(Class cls)
+ {
+ boolean returnValue = false;
+ Class superType = cls.getSuperclass();
+ if (superType != null)
+ {
+ if ((superType.getAnnotation(QMFObject.class) != null)
+ || (superType.getAnnotation(QMFType.class) != null)
+ || (superType.getAnnotation(QMFSeeAlso.class) != null)
+ || (superType.getAnnotation(QMFEvent.class) != null))
+ {
+ returnValue = true;
+ }
+ }
+ return returnValue;
+ }
+
+ protected boolean isOptional(Method m, TypeBinding type)
+ {
+ boolean returnValue = false;
+ // Look for the annotaiton first
+ QMFProperty ann = m.getAnnotation(QMFProperty.class);
+ if (ann != null)
+ {
+ returnValue = ann.optional();
+ } else
+ {
+ returnValue = type.optionalDefault();
+ }
+ return returnValue;
+ }
+
+ public ClassBinding parse()
+ {
+ log.debug(String.format(
+ "Parsing class binding '%s' for package '%s' from class %s",
+ name, pkg, javaClass.getName()));
+ for (Method m : this.getMethods(javaClass))
+ {
+ String mname = m.getName();
+ Class<?> type = m.getReturnType();
+ switch (classify(javaClass, m))
+ {
+ case READ_ONLY:
+ TypeBinding tb = bctx.getTypeBinding(type);
+ boolean optional = isOptional(m, tb);
+ properties.add(new PropertyBinding(property(m), tb,
+ PropertyBinding.READ_ONLY, optional));
+ break;
+ case READ_WRITE:
+ TypeBinding tbnd = bctx.getTypeBinding(type);
+ boolean opt = isOptional(m, tbnd);
+ properties.add(new PropertyBinding(property(m), tbnd,
+ PropertyBinding.READ_WRITE, opt));
+ break;
+ case METHOD:
+ // Only expose methods if told to
+ if (exposeBehaviour)
+ {
+ List<ParameterBinding> params = new ArrayList<ParameterBinding>();
+ int arg = 0;
+ for (Class pcls : m.getParameterTypes())
+ {
+ params.add(new ParameterBinding("arg" + arg++, bctx
+ .getTypeBinding(pcls), true, false));
+ }
+ if (type != void.class)
+ {
+ params.add(new ParameterBinding("result", bctx
+ .getTypeBinding(type), false, true));
+ }
+ methods.add(new MethodBinding(mname, params));
+ }
+ break;
+ case IGNORE:
+ break;
+ }
+ }
+ for (MethodBinding m : methods)
+ {
+ methodsByName.put(m.getName(), m);
+ }
+ QMFEvent eventAnnotation = (QMFEvent) javaClass
+ .getAnnotation(QMFEvent.class);
+ if (eventAnnotation != null)
+ {
+ kind = 2; // Event Type
+ }
+ // if (this.hasQMFSupertype(javaClass)) {
+ if ((javaClass.getSuperclass() != Object.class)
+ && (javaClass.getSuperclass() != null))
+ {
+ superType = bctx.register(javaClass.getSuperclass());
+ }
+ return this;
+ }
+
+ public String getPackage()
+ {
+ return pkg;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public List<PropertyBinding> getProperties()
+ {
+ return properties;
+ }
+
+ public List<PropertyBinding> getAllProperties()
+ {
+ if (this.superType == null)
+ {
+ return properties;
+ } else
+ {
+ List<PropertyBinding> newList = new ArrayList<PropertyBinding>(
+ properties);
+ for (PropertyBinding p : superType.getAllProperties())
+ {
+ if (!newList.contains(p))
+ {
+ newList.add(p);
+ }
+ }
+ return newList;
+ }
+ }
+
+ public List<MethodBinding> getMethods()
+ {
+ return methods;
+ }
+
+ public MethodBinding getMethod(String name)
+ {
+ return methodsByName.get(name);
+ }
+
+ // Use this format
+ // bytes value
+ // 0-3 package name
+ // 4-7 class name
+ // 8-11 property signature hash
+ // 12-15 method signature hash
+ // FIXME: Hash codes seem to mess things up
+ public byte[] getSchemaHash()
+ {
+ if (null == hash)
+ {
+ hash = new byte[16];
+ StringBuilder blder = new StringBuilder();
+ int packageHash = pkg.hashCode();
+ int classHash = name.hashCode();
+ int propertyHash = 0;
+ int methodHash = 0;
+ for (PropertyBinding p : properties)
+ {
+ blder.append(p.getName()).append(":").append(
+ p.getType().getCode()).append(":")
+ .append(p.getAccess()).append(":").append(
+ p.isOptional());
+ }
+ propertyHash = blder.toString().hashCode();
+ blder = new StringBuilder();
+ for (MethodBinding m : methods)
+ {
+ blder.append(m.getName());
+ for (ParameterBinding p : m.getParameters())
+ {
+ String direction = p.isIn() ? "in" : "out";
+ blder.append(":").append(p.getName()).append(":").append(
+ direction).append(":")
+ .append(p.getType().getCode());
+ }
+ }
+ methodHash = blder.toString().hashCode();
+ hash[0] = (byte) (packageHash >> 24);
+ hash[1] = (byte) (packageHash >> 16);
+ hash[2] = (byte) (packageHash >> 8);
+ hash[3] = (byte) (packageHash);
+ hash[4] = (byte) (classHash >> 24);
+ hash[5] = (byte) (classHash >> 16);
+ hash[6] = (byte) (classHash >> 8);
+ hash[7] = (byte) (classHash);
+ hash[8] = (byte) (propertyHash >> 24);
+ hash[9] = (byte) (propertyHash >> 16);
+ hash[10] = (byte) (propertyHash >> 8);
+ hash[11] = (byte) (propertyHash);
+ hash[12] = (byte) (methodHash >> 24);
+ hash[13] = (byte) (methodHash >> 16);
+ hash[14] = (byte) (methodHash >> 8);
+ hash[15] = (byte) (methodHash);
+ }
+ return hash;
+ }
+
+ public void encode(Encoder enc)
+ {
+ log.debug(String.format("encoding %s %s with superclass %s", this
+ .getRefClass(), this.getRefPackage(), superType));
+ enc.writeUint8(kind); // kind
+ enc.writeStr8(pkg);
+ enc.writeStr8(name);
+ enc.writeBin128(this.getSchemaHash()); // schema hash
+ // Send true (1) if we have a super-type
+ if (superType == null)
+ {
+ enc.writeUint8((short) 0);
+ } else
+ {
+ enc.writeUint8((short) 1);
+ }
+ enc.writeUint16(properties.size());
+ // Events do not have the method size sent
+ if (kind == 1)
+ {
+ enc.writeUint16(0);
+ enc.writeUint16(methods.size());
+ }
+ // Add the super type information if we have it
+ if (superType != null)
+ {
+ enc.writeStr8(superType.pkg);
+ enc.writeStr8(superType.name);
+ enc.writeBin128(superType.getSchemaHash()); // schema hash
+ }
+ for (PropertyBinding p : properties)
+ {
+ log.trace("encoding property " + p.getName());
+ p.encode(enc);
+ }
+ for (MethodBinding m : methods)
+ {
+ m.encode(enc);
+ }
+ }
+
+ // Type Binding functions
+ public short getCode()
+ {
+ return (short) 20;
+ }
+
+ public Class<?> getJavaClass()
+ {
+ return javaClass;
+ }
+
+ public Object decode(Decoder dec)
+ {
+ // FIXME This only works with POJOs
+ short typeCode = dec.readUint8();
+ log.trace("Type code: " + typeCode);
+ if (typeCode == 20)
+ {
+ String packageName = dec.readStr8();
+ String className = dec.readStr8();
+ log
+ .debug(String
+ .format(
+ "Decoding an object for package %s class %s with bindings for %s %s",
+ packageName, className, this.pkg, this.name));
+ byte schemaHash[] = dec.readBin128();
+ // Check to see that this is me, and not a subclass
+ if (packageName.equals(this.pkg) && className.equals(this.name))
+ {
+ return decodeWithNoHeaders(dec);
+ } else
+ {
+ ClassBinding mcls = bctx
+ .getClassBinding(packageName, className);
+ return mcls.decodeWithNoHeaders(dec);
+ }
+ } else
+ {
+ TypeBinding tb = QMFTypeBinding.getType(typeCode);
+ return tb.decode(dec);
+ }
+ }
+
+ protected Object decodeWithNoHeaders(Decoder dec)
+ {
+ Object instance = null;
+ try
+ {
+ log.trace("Creating a new instance of " + this.javaClass.getName());
+ instance = this.javaClass.newInstance();
+ } catch (Exception e)
+ {
+ log.error("Could not instantiate object of class"
+ + this.javaClass.getName());
+ throw new BindingException(e);
+ }
+ List<String> excludes = this.processPresenceMasks(dec);
+ for (PropertyBinding p : getAllProperties())
+ {
+ if (!excludes.contains(p.getName()))
+ {
+ Object value = p.getType().decode(dec);
+ BindingUtils.set(p, value, instance);
+ }
+ }
+ return instance;
+ }
+
+ protected List<String> processPresenceMasks(Decoder dec)
+ {
+ List<String> excludes = new ArrayList<String>();
+ short bit = 0;
+ short mask = 0;
+ for (PropertyBinding prop : properties)
+ {
+ if (prop.isOptional())
+ {
+ if (bit == 0)
+ {
+ mask = dec.readUint8();
+ bit = 1;
+ }
+ if ((mask & bit) == 0)
+ {
+ log.trace("Going in exlude " + prop.getName());
+ excludes.add(prop.getName());
+ }
+ bit *= 2;
+ if (bit == 256)
+ {
+ bit = 0;
+ }
+ }
+ }
+ return excludes;
+ }
+
+ public void encode(Encoder enc, Object value)
+ {
+ // if the object is null, assume this is the
+ // correct class
+ if (value == null || (value.getClass().equals(this.javaClass)))
+ {
+ String pkg = getPackage();
+ String cls = getName();
+ log.debug(String.format("Encoding class %s:%s", pkg, cls));
+ enc.writeUint8(this.getCode());
+ enc.writeStr8(pkg);
+ enc.writeStr8(cls);
+ enc.writeBin128(this.getSchemaHash());
+ short bit = 0;
+ short mask = 0;
+ if (value != null)
+ {
+ // Encode the property presence masks first.
+ // if this is not an event
+ if (!isEvent())
+ {
+ for (PropertyBinding p : getAllProperties())
+ {
+ if (p.isOptional())
+ {
+ Object pValue = BindingUtils.get(p, value);
+ if (bit == 0)
+ bit = 1;
+ if (pValue != null)
+ {
+ mask |= bit;
+ }
+ if (bit == 128)
+ {
+ enc.writeUint8(mask);
+ bit = 0;
+ mask = 0;
+ } else
+ {
+ bit = (short) (bit << 1);
+ }
+ }
+ }
+ if (bit != 0)
+ {
+ enc.writeUint8(mask);
+ }
+ }
+ // Now put the actual properties
+ for (PropertyBinding p : getAllProperties())
+ {
+ Object pValue = BindingUtils.get(p, value);
+ if (!p.isOptional() || !(pValue == null))
+ {
+ log.trace(String.format("Encoding property %s", p
+ .getName()));
+ p.getType().encode(enc, pValue);
+ }
+ }
+ }
+ log.debug(String.format("Done with %s:%s", pkg, cls));
+ } else
+ {
+ TypeBinding tb = bctx.getTypeBinding(value.getClass());
+ if (tb == null)
+ {
+ throw new BindingException(String.format(
+ "No class named %s defined for this context ", value
+ .getClass()));
+ } else
+ {
+ if (tb.isNative())
+ {
+ enc.writeUint8(tb.getCode());
+ }
+ tb.encode(enc, value);
+ }
+ }
+ }
+
+ public boolean isNative()
+ {
+ return false;
+ }
+
+ public boolean optionalDefault()
+ {
+ return true;
+ }
+
+ public String getRefClass()
+ {
+ return this.name;
+ }
+
+ public String getRefPackage()
+ {
+ return this.pkg;
+ }
+
+ public short getKind()
+ {
+ return kind;
+ }
+
+ public boolean isEvent()
+ {
+ return kind == 2;
+ }
+
+ public void setKind(short kind)
+ {
+ this.kind = kind;
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/EnumBinding.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/EnumBinding.java
new file mode 100644
index 0000000000..37d20341d9
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/EnumBinding.java
@@ -0,0 +1,99 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class EnumBinding extends ClassBinding
+{
+ private static Log log = LogFactory.getLog(EnumBinding.class);
+
+ public EnumBinding(String pkg, String name, Class cls,
+ boolean exposeBehaviour, BindingContext bctx)
+ {
+ super(pkg, name, cls, exposeBehaviour, bctx);
+ }
+
+ @Override
+ public void encode(Encoder enc)
+ {
+ enc.writeUint8((short) 1); // kind
+ enc.writeStr8(pkg);
+ enc.writeStr8(name);
+ enc.writeBin128(new byte[16]); // schema hash
+ // FIXME Is there a way to send the valid types?
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ if (value != null)
+ {
+ enc.writeStr16(value.toString());
+ } else
+ {
+ enc.writeStr16("");
+ }
+ }
+
+ @Override
+ public Object decode(Decoder dec)
+ {
+ // FIXME This only works with POJOs
+ Object instance = null;
+ try
+ {
+ String value = dec.readStr16();
+ instance = Enum.valueOf((Class<Enum>) this.getJavaClass(), value);
+ } catch (Exception e)
+ {
+ log.error("Could not create an enum of type "
+ + this.javaClass.getName());
+ throw new BindingException(e);
+ }
+ return instance;
+ }
+
+ // Make this look like a String
+ @Override
+ public short getCode()
+ {
+ return (short) 7;
+ }
+
+ @Override
+ public EnumBinding parse()
+ {
+ log.debug(String.format(
+ "Parsing enum binding '%s' for package '%s' from class %s",
+ name, pkg, javaClass.getName()));
+ return this;
+ }
+
+ @Override
+ public boolean optionalDefault()
+ {
+ return false;
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/ListBinding.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/ListBinding.java
new file mode 100644
index 0000000000..fcdd20a0c1
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/ListBinding.java
@@ -0,0 +1,122 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.transport.codec.BBDecoder;
+import org.apache.qpid.transport.codec.BBEncoder;
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class ListBinding implements TypeBinding
+{
+ private static Log log = LogFactory.getLog(ListBinding.class);
+ protected BindingContext bctx;
+ protected Class javaClass;
+
+ public ListBinding(BindingContext bctx, Class javaClass)
+ {
+ this.bctx = bctx;
+ this.javaClass = javaClass;
+ }
+
+ public void encode(Encoder enc, Object value)
+ {
+ List list = (List) value;
+ BBEncoder newEncoder = new BBEncoder(10);
+ newEncoder.writeUint32(list.size());
+ for (Object obj : list)
+ {
+ TypeBinding type = bctx.getTypeBinding(obj.getClass());
+ newEncoder.writeUint8(type.getCode());
+ type.encode(newEncoder, obj);
+ }
+ enc.writeVbin32(newEncoder.buffer().array());
+ }
+
+ public Object decode(Decoder dec)
+ {
+ List list = null;
+ try
+ {
+ list = (List) javaClass.newInstance();
+ } catch (Exception e)
+ {
+ throw new BindingException(
+ "Could not create a List implementation for "
+ + javaClass.getName(), e);
+ }
+ BBDecoder newDecoder = new BBDecoder();
+ newDecoder.init(ByteBuffer.wrap(dec.readVbin32()));
+ long count = newDecoder.readUint32();
+ while (count > 0)
+ {
+ short typeCode = newDecoder.readUint8();
+ TypeBinding type = QMFTypeBinding.getType(typeCode);
+ if (type == null)
+ {
+ type = bctx.getTypeBinding(Object.class);
+ }
+ list.add(type.decode(newDecoder));
+ count -= 1;
+ }
+ return list;
+ }
+
+ // QMF List Type
+ public short getCode()
+ {
+ return (short) 21;
+ }
+
+ @Override
+ public Class<?> getJavaClass()
+ {
+ return javaClass;
+ }
+
+ @Override
+ public String getRefClass()
+ {
+ return null;
+ }
+
+ @Override
+ public String getRefPackage()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isNative()
+ {
+ return true;
+ }
+
+ public boolean optionalDefault()
+ {
+ return false;
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/MapBinding.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/MapBinding.java
new file mode 100644
index 0000000000..8b0df57e89
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/MapBinding.java
@@ -0,0 +1,133 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.transport.codec.BBDecoder;
+import org.apache.qpid.transport.codec.BBEncoder;
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class MapBinding implements TypeBinding
+{
+ private static Log log = LogFactory.getLog(MapBinding.class);
+ protected BindingContext bctx;
+ protected Class javaClass;
+
+ public MapBinding(BindingContext bctx, Class javaClass)
+ {
+ this.bctx = bctx;
+ this.javaClass = javaClass;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void encode(Encoder enc, Object value)
+ {
+ Map map = (Map) value;
+ BBEncoder newEncoder = new BBEncoder(10);
+ newEncoder.writeUint32(map.size());
+ for (Object key : map.keySet())
+ {
+ String keyString = key.toString();
+ Object mapValue = map.get(key);
+ TypeBinding binding = bctx.getTypeBinding(mapValue.getClass());
+ newEncoder.writeStr8(keyString);
+ newEncoder.writeUint8(binding.getCode());
+ binding.encode(newEncoder, mapValue);
+ }
+ enc.writeVbin32(newEncoder.buffer().array());
+ }
+
+ public Object decode(Decoder dec)
+ {
+ Map map = null;
+ try
+ {
+ if (javaClass.isInterface())
+ {
+ map = new HashMap();
+ } else
+ {
+ map = (Map) javaClass.newInstance();
+ }
+ } catch (Exception e)
+ {
+ throw new BindingException(
+ "Could not create a Map implementation for "
+ + javaClass.getName(), e);
+ }
+ BBDecoder newDecoder = new BBDecoder();
+ newDecoder.init(ByteBuffer.wrap(dec.readVbin32()));
+ long count = newDecoder.readUint32();
+ while (count > 0)
+ {
+ String key = newDecoder.readStr8();
+ short typeCode = newDecoder.readUint8();
+ TypeBinding type = QMFTypeBinding.getType(typeCode);
+ if (type == null)
+ {
+ type = bctx.getTypeBinding(Object.class);
+ }
+ map.put(key, type.decode(newDecoder));
+ count -= 1;
+ }
+ return map;
+ }
+
+ // QMF List Type
+ public short getCode()
+ {
+ return (short) 15;
+ }
+
+ @Override
+ public Class<?> getJavaClass()
+ {
+ return javaClass;
+ }
+
+ @Override
+ public String getRefClass()
+ {
+ return null;
+ }
+
+ @Override
+ public String getRefPackage()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isNative()
+ {
+ return true;
+ }
+
+ public boolean optionalDefault()
+ {
+ return false;
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/MethodBinding.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/MethodBinding.java
new file mode 100644
index 0000000000..d6dec92b13
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/MethodBinding.java
@@ -0,0 +1,88 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class MethodBinding
+{
+ private final String name;
+ private final List<ParameterBinding> parameters;
+ private final List<ParameterBinding> inParameters = new ArrayList<ParameterBinding>();
+ private final List<ParameterBinding> outParameters = new ArrayList<ParameterBinding>();
+ private Log log = LogFactory.getLog(MethodBinding.class);
+
+ public MethodBinding(String name, List<ParameterBinding> parameters)
+ {
+ this.name = name;
+ this.parameters = parameters;
+ for (ParameterBinding p : parameters)
+ {
+ if (p.isIn())
+ {
+ inParameters.add(p);
+ }
+ if (p.isOut())
+ {
+ outParameters.add(p);
+ }
+ }
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public List<ParameterBinding> getParameters()
+ {
+ return parameters;
+ }
+
+ public List<ParameterBinding> getInParameters()
+ {
+ return inParameters;
+ }
+
+ public List<ParameterBinding> getOutParameters()
+ {
+ return outParameters;
+ }
+
+ void encode(Encoder enc)
+ {
+ Map map = new HashMap();
+ map.put("name", name);
+ map.put("argCount", parameters.size());
+ enc.writeMap(map);
+ for (ParameterBinding p : parameters)
+ {
+ p.encode(enc);
+ }
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/ParameterBinding.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/ParameterBinding.java
new file mode 100644
index 0000000000..3c707dc9cb
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/ParameterBinding.java
@@ -0,0 +1,118 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.transport.codec.Encoder;
+
+public class ParameterBinding
+{
+ private final String name;
+ private final TypeBinding type;
+ private final boolean in;
+ private final boolean out;
+
+ public ParameterBinding(String name, TypeBinding type, boolean in,
+ boolean out)
+ {
+ this.name = name;
+ this.type = type;
+ this.in = in;
+ this.out = out;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public TypeBinding getType()
+ {
+ return type;
+ }
+
+ public boolean isIn()
+ {
+ return in;
+ }
+
+ public boolean isOut()
+ {
+ return out;
+ }
+
+ void encode(Encoder enc)
+ {
+ Map map = new HashMap();
+ map.put("name", name);
+ map.put("type", type.getCode());
+ map.put("dir", (in ? "I" : "") + (out ? "O" : ""));
+ if (!type.isNative())
+ {
+ map.put("refClass", type.getRefClass());
+ map.put("refPackage", type.getRefPackage());
+ }
+ enc.writeMap(map);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (in ? 1231 : 1237);
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + (out ? 1231 : 1237);
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ParameterBinding other = (ParameterBinding) obj;
+ if (in != other.in)
+ return false;
+ if (name == null)
+ {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (out != other.out)
+ return false;
+ if (type == null)
+ {
+ if (other.type != null)
+ return false;
+ } else if (!type.equals(other.type))
+ return false;
+ return true;
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/PropertyBinding.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/PropertyBinding.java
new file mode 100644
index 0000000000..6c94dc5b17
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/PropertyBinding.java
@@ -0,0 +1,128 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class PropertyBinding
+{
+ private static Log log = LogFactory.getLog(PropertyBinding.class);
+ public final static int READ_CREATE = 1;
+ public final static int READ_WRITE = 2;
+ public final static int READ_ONLY = 3;
+ private String name;
+ private TypeBinding type;
+ private int accessType;
+ private boolean optional;
+
+ public PropertyBinding(String name, TypeBinding type, int accessType,
+ boolean optional)
+ {
+ this.name = name;
+ this.type = type;
+ this.accessType = accessType;
+ this.optional = optional;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + accessType;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ PropertyBinding other = (PropertyBinding) obj;
+ if (accessType != other.accessType)
+ return false;
+ if (name == null)
+ {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (type == null)
+ {
+ if (other.type != null)
+ return false;
+ } else if (!type.equals(other.type))
+ return false;
+ return true;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public TypeBinding getType()
+ {
+ return type;
+ }
+
+ public int getAccess()
+ {
+ return accessType;
+ }
+
+ public boolean isIndex()
+ {
+ return false;
+ }
+
+ public boolean isOptional()
+ {
+ return optional;
+ }
+
+ void encode(Encoder enc)
+ {
+ Map map = new HashMap();
+ map.put("name", name);
+ map.put("type", type.getCode());
+ map.put("access", getAccess());
+ map.put("index", isIndex() ? 1 : 0);
+ map.put("optional", isOptional() ? 1 : 0);
+ if (!type.isNative())
+ {
+ map.put("refClass", type.getRefClass());
+ map.put("refPackage", type.getRefPackage());
+ }
+ enc.writeMap(map);
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/QMFTypeBinding.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/QMFTypeBinding.java
new file mode 100644
index 0000000000..9d86f27c1a
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/QMFTypeBinding.java
@@ -0,0 +1,462 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public abstract class QMFTypeBinding implements TypeBinding
+{
+ private static final Map<Class<?>, QMFTypeBinding> TYPES = new HashMap<Class<?>, QMFTypeBinding>();
+ private static final Map<Short, QMFTypeBinding> TYPES_BY_CODE = new HashMap<Short, QMFTypeBinding>();
+ static
+ {
+ new QMFTypeBinding(null, (short) 1)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Short.valueOf(dec.readUint8());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeUint8(((Number) value).shortValue());
+ }
+ };
+ new QMFTypeBinding(null, (short) 2)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Integer.valueOf(dec.readUint16());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeUint16(((Number) value).intValue());
+ }
+ };
+ new QMFTypeBinding(null, (short) 3)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Long.valueOf(dec.readUint32());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeUint32(((Number) value).longValue());
+ }
+ };
+ new QMFTypeBinding(null, (short) 4)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Long.valueOf(dec.readUint64());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeUint64(((Number) value).longValue());
+ }
+ };
+ new QMFTypeBinding(null, (short) 6) // short string
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readStr8();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ if (null == value)
+ value = "";
+ enc.writeStr8((String) value);
+ }
+ };
+ new QMFTypeBinding(String.class, (short) 7) // long string
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readStr16();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ if (null == value)
+ value = "";
+ enc.writeStr16((String) value);
+ }
+ };
+ new QMFTypeBinding(Date.class, (short) 8)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return new Date(dec.readDatetime());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeDatetime(((Date) value).getTime());
+ }
+ };
+ new QMFTypeBinding(Boolean.class, (short) 11)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Boolean.valueOf(dec.readUint8() != 0);
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ if (((Boolean) value).booleanValue())
+ {
+ enc.writeUint8((short) 1);
+ } else
+ {
+ enc.writeUint8((short) 0);
+ }
+ }
+
+ @Override
+ public short[] alternateTypes()
+ {
+ short[] types =
+ { 5 };
+ return types;
+ }
+ };
+ new QMFTypeBinding(boolean.class, (short) 11)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readUint8() != 0;
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ if (((Boolean) value).booleanValue())
+ {
+ enc.writeUint8((short) 1);
+ } else
+ {
+ enc.writeUint8((short) 0);
+ }
+ }
+ };
+ new QMFTypeBinding(Float.class, (short) 12)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Float.valueOf(dec.readFloat());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeFloat(((Number) value).floatValue());
+ }
+ };
+ new QMFTypeBinding(float.class, (short) 12)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readFloat();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeFloat(((Number) value).floatValue());
+ }
+ };
+ new QMFTypeBinding(Double.class, (short) 13)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Double.valueOf(dec.readDouble());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeDouble(((Number) value).doubleValue());
+ }
+ };
+ new QMFTypeBinding(double.class, (short) 13)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readDouble();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeDouble(((Number) value).doubleValue());
+ }
+ };
+ new QMFTypeBinding(UUID.class, (short) 14)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readUuid();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeUuid((UUID) value);
+ }
+ };
+ new QMFTypeBinding(byte.class, (short) 16)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readInt8();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeInt8(((Number) value).byteValue());
+ }
+ };
+ new QMFTypeBinding(Short.class, (short) 17)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Short.valueOf(dec.readInt16());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeInt16(((Number) value).shortValue());
+ }
+ };
+ new QMFTypeBinding(short.class, (short) 17)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readInt16();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeInt16(((Number) value).shortValue());
+ }
+ };
+ new QMFTypeBinding(Integer.class, (short) 18)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Integer.valueOf(dec.readInt32());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeInt32(((Number) value).intValue());
+ }
+ };
+ new QMFTypeBinding(int.class, (short) 18)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readInt32();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeInt32(((Number) value).intValue());
+ }
+ };
+ new QMFTypeBinding(Long.class, (short) 19)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Long.valueOf(dec.readInt64());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeInt64(((Number) value).longValue());
+ }
+ };
+ new QMFTypeBinding(long.class, (short) 19)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readInt64();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeInt64(((Number) value).longValue());
+ }
+ };
+ }
+
+ public static final QMFTypeBinding forClass(Class<?> cls)
+ {
+ QMFTypeBinding t = TYPES.get(cls);
+ return t;
+ }
+
+ public static final boolean isBound(Class<?> cls)
+ {
+ return TYPES.containsKey(cls);
+ }
+
+ public static QMFTypeBinding getType(short code)
+ {
+ return TYPES_BY_CODE.get(code);
+ }
+
+ private final Class<?> cls;
+ private final short code;
+
+ private QMFTypeBinding(Class<?> cls, short code)
+ {
+ this.cls = cls;
+ this.code = code;
+ if (cls != null)
+ {
+ TYPES.put(cls, this);
+ }
+ TYPES_BY_CODE.put(code, this);
+ for (short type : this.alternateTypes())
+ {
+ TYPES_BY_CODE.put(type, this);
+ }
+ }
+
+ public Class<?> getJavaClass()
+ {
+ return cls;
+ }
+
+ public short getCode()
+ {
+ return code;
+ }
+
+ public boolean isNative()
+ {
+ return true;
+ }
+
+ public boolean optionalDefault()
+ {
+ return false;
+ }
+
+ public String getRefClass()
+ {
+ return null;
+ }
+
+ public String getRefPackage()
+ {
+ return null;
+ }
+
+ public abstract Object decode(Decoder dec);
+
+ public abstract void encode(Encoder enc, Object value);
+
+ public short[] alternateTypes()
+ {
+ short[] types =
+ {};
+ return types;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((cls == null) ? 0 : cls.hashCode());
+ result = prime * result + code;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ QMFTypeBinding other = (QMFTypeBinding) obj;
+ if (cls == null)
+ {
+ if (other.cls != null)
+ return false;
+ } else if (!cls.equals(other.cls))
+ return false;
+ if (code != other.code)
+ return false;
+ return true;
+ }
+}
diff --git a/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/TypeBinding.java b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/TypeBinding.java
new file mode 100644
index 0000000000..492e533fdc
--- /dev/null
+++ b/qpid/java/agent/src/main/java/org/apache/qpid/agent/binding/TypeBinding.java
@@ -0,0 +1,43 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public interface TypeBinding
+{
+ public Object decode(Decoder dec);
+
+ public void encode(Encoder enc, Object value);
+
+ public Class<?> getJavaClass();
+
+ public short getCode();
+
+ public boolean isNative();
+
+ public String getRefClass();
+
+ public String getRefPackage();
+
+ public boolean optionalDefault();
+}
diff --git a/qpid/java/agent/src/test/java/org/apache/qpid/agent/Crumpet.java b/qpid/java/agent/src/test/java/org/apache/qpid/agent/Crumpet.java
new file mode 100644
index 0000000000..67095c809b
--- /dev/null
+++ b/qpid/java/agent/src/test/java/org/apache/qpid/agent/Crumpet.java
@@ -0,0 +1,70 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent;
+
+import java.util.ArrayList;
+
+import org.apache.qpid.agent.annotations.QMFSeeAlso;
+import org.apache.qpid.agent.annotations.QMFType;
+
+/**
+ * Crumpet
+ *
+ */
+@QMFType(className = "Crumpet", packageName = "org.apache.test")
+@QMFSeeAlso(
+{ Pikelet.class })
+public class Crumpet
+{
+ private String foo = "fooValue";
+ private String bar = "barValue";
+ private ArrayList<String> ingredients = new ArrayList<String>();
+
+ public String getFoo()
+ {
+ return foo;
+ }
+
+ public void setFoo(String foo)
+ {
+ this.foo = foo;
+ }
+
+ public String getBar()
+ {
+ return bar;
+ }
+
+ public void setBar(String bar)
+ {
+ this.bar = bar;
+ }
+
+ public ArrayList<String> getIngredients()
+ {
+ return ingredients;
+ }
+
+ public void setIngredients(ArrayList<String> ingredients)
+ {
+ this.ingredients = ingredients;
+ }
+}
diff --git a/qpid/java/agent/src/test/java/org/apache/qpid/agent/Muppet.java b/qpid/java/agent/src/test/java/org/apache/qpid/agent/Muppet.java
new file mode 100644
index 0000000000..f039ab9baa
--- /dev/null
+++ b/qpid/java/agent/src/test/java/org/apache/qpid/agent/Muppet.java
@@ -0,0 +1,113 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.agent.annotations.QMFObject;
+
+@QMFObject(className = "Muppet", packageName = "org.apache.test")
+public class Muppet extends Puppet
+{
+ private Log log = LogFactory.getLog(Muppet.class);
+
+ public String getSomething()
+ {
+ return "something";
+ }
+
+ public void doSomething(String str)
+ {
+ log.debug(String.format("doSomething: %s", str));
+ }
+
+ public String returnSomething()
+ {
+ log.debug("returning something");
+ return "asdf";
+ }
+
+ public Crumpet gimmieCrumpet(String asdf, int n, float f, Map foo)
+ {
+ log.debug(String
+ .format("mmm, crumpet: %s, %s, %s, %s", asdf, n, f, foo));
+ Crumpet crumpet = new Crumpet();
+ crumpet.getIngredients().add("Butter");
+ crumpet.getIngredients().add("Salt");
+ crumpet.getIngredients().add("Flour");
+ return crumpet;
+ }
+
+ public Crumpet gimmieCrumpet2()
+ {
+ Pikelet pik = new Pikelet();
+ pik.getIngredients().add("Butter");
+ pik.getIngredients().add("Salt");
+ pik.getIngredients().add("Eggs");
+ pik.getCrumpets().put("Crumpet1",
+ this.gimmieCrumpet("2121", 1, 1, null));
+ return pik;
+ }
+
+ public List gimmeLotsOfCrumpets()
+ {
+ log.debug("Asking for lots of Crumpets");
+ ArrayList<Crumpet> returnValue = new ArrayList<Crumpet>();
+ Crumpet crumpet = new Crumpet();
+ crumpet.getIngredients().add("Chocolate");
+ returnValue.add(crumpet);
+ crumpet = new Crumpet();
+ crumpet.getIngredients().add("Pecans");
+ returnValue.add(crumpet);
+ crumpet = new Pikelet();
+ crumpet.getIngredients().add("Poached Eggs");
+ returnValue.add(crumpet);
+ return returnValue;
+ }
+
+ public int divideByZero()
+ {
+ return 1 / 0;
+ }
+
+ public Crumpet takeCrumpet(Crumpet newCrumpet)
+ {
+ log.debug(String.format("I gots me a crumpet: foo: '%s' bar: '%s'",
+ newCrumpet.getFoo(), newCrumpet.getBar()));
+ log.debug("My crumpet's class is " + newCrumpet.getClass().getName());
+ for (String ingredient : newCrumpet.getIngredients())
+ {
+ log.debug("My crumpet is made of " + ingredient);
+ }
+ return newCrumpet;
+ }
+
+ public Object takeSomething(Object obj)
+ {
+ log.debug(String.format("I gots me a something: '%s'", obj.getClass()
+ .getName()));
+ return obj;
+ }
+}
diff --git a/qpid/java/agent/src/test/java/org/apache/qpid/agent/Pikelet.java b/qpid/java/agent/src/test/java/org/apache/qpid/agent/Pikelet.java
new file mode 100644
index 0000000000..f820fa6258
--- /dev/null
+++ b/qpid/java/agent/src/test/java/org/apache/qpid/agent/Pikelet.java
@@ -0,0 +1,52 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent;
+
+import java.util.HashMap;
+
+import org.apache.qpid.agent.annotations.QMFType;
+
+@QMFType(className = "Pikelet", packageName = "org.apache.test")
+public class Pikelet extends Crumpet
+{
+ protected String shape;
+ HashMap<String, Crumpet> crumpets = new HashMap<String, Crumpet>();
+
+ public String getShape()
+ {
+ return shape;
+ }
+
+ public void setShape(String shape)
+ {
+ this.shape = shape;
+ }
+
+ public HashMap<String, Crumpet> getCrumpets()
+ {
+ return crumpets;
+ }
+
+ public void setCrumpets(HashMap<String, Crumpet> crumpets)
+ {
+ this.crumpets = crumpets;
+ }
+}
diff --git a/qpid/java/agent/src/test/java/org/apache/qpid/agent/Puppet.java b/qpid/java/agent/src/test/java/org/apache/qpid/agent/Puppet.java
new file mode 100644
index 0000000000..bfd34840f8
--- /dev/null
+++ b/qpid/java/agent/src/test/java/org/apache/qpid/agent/Puppet.java
@@ -0,0 +1,29 @@
+/*
+ *
+ * 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.
+ *
+ */
+package org.apache.qpid.agent;
+
+public class Puppet
+{
+ public int countStrings()
+ {
+ return 4;
+ }
+}
diff --git a/qpid/java/build.deps b/qpid/java/build.deps
index 6bb9bfa09e..275f3e3776 100644
--- a/qpid/java/build.deps
+++ b/qpid/java/build.deps
@@ -55,7 +55,7 @@ javassist=lib/javassist.jar
jetty=lib/jetty-6.1.14.jar
jetty-util=lib/jetty-util-6.1.14.jar
jetty-bootstrap=lib/start.jar
-
+jms=lib/jms-1.1.jar
jsp-api=lib/jsp-api-2.1.jar
jsp-impl=lib/jsp-2.1.jar
core-lib=lib/core-3.1.1.jar
@@ -86,6 +86,8 @@ broker.libs=${common.libs} ${commons-cli} ${commons-logging} ${log4j} \
broker-plugins.libs=${common.libs} ${felix.libs}
management-client.libs=${jsp.libs} ${log4j} ${slf4j-log4j} ${slf4j-api} ${commons-pool} ${geronimo-servlet} ${muse.libs} ${javassist} ${xalan} ${mina-core} ${mina-filter-ssl}
+agent.libs=${jms}
+
junit-toolkit.libs=${log4j} ${junit} ${slf4j-api}
test.libs=${slf4j-log4j} ${junit-toolkit.libs}
systests.libs=${client.libs} ${test.libs} ${broker.libs}
diff --git a/qpid/java/build.xml b/qpid/java/build.xml
index 3b70707e61..530d220d54 100644
--- a/qpid/java/build.xml
+++ b/qpid/java/build.xml
@@ -22,7 +22,7 @@
<import file="common.xml"/>
- <property name="modules.core" value="junit-toolkit common broker client tools"/>
+ <property name="modules.core" value="junit-toolkit common broker client tools agent"/>
<property name="modules.examples" value="client/example"/>
<property name="modules.tests" value="systests perftests integrationtests testkit"/>
<property name="modules.management" value="management/common management/client management/eclipse-plugin"/>
diff --git a/qpid/java/management/client/src/main/java/org/apache/qpid/management/Protocol.java b/qpid/java/management/client/src/main/java/org/apache/qpid/management/Protocol.java
index c1b1ceb5b4..48ef10f60a 100644
--- a/qpid/java/management/client/src/main/java/org/apache/qpid/management/Protocol.java
+++ b/qpid/java/management/client/src/main/java/org/apache/qpid/management/Protocol.java
@@ -27,7 +27,7 @@ package org.apache.qpid.management;
*/
public interface Protocol
{
- String MAGIC_NUMBER = "AM2";
+ String MAGIC_NUMBER = "AM3";
char SCHEMA_REQUEST_OPCODE = 'S';
char SCHEMA_RESPONSE_OPCODE = Character.toLowerCase(SCHEMA_REQUEST_OPCODE);
diff --git a/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/SchemaResponseMessageHandler.java b/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/SchemaResponseMessageHandler.java
index ee5efe2af6..e05bcee820 100644
--- a/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/SchemaResponseMessageHandler.java
+++ b/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/SchemaResponseMessageHandler.java
@@ -68,11 +68,18 @@ public class SchemaResponseMessageHandler extends BaseMessageHandler
String className = decoder.readStr8();
Binary schemaHash = new Binary(decoder.readBin128());
-
+
+ int hasSuperclass = decoder.readUint8();
int howManyProperties = decoder.readUint16();
int howManyStatistics = decoder.readUint16();
int howManyMethods = decoder.readUint16();
+ if (hasSuperclass != 0) {
+ String parentPackageName = decoder.readStr8();
+ String parentClassName = decoder.readStr8();
+ Binary parentHash = new Binary(decoder.readBin128());
+ }
+
_domainModel.addSchema(
packageName,
className,
@@ -214,4 +221,4 @@ public class SchemaResponseMessageHandler extends BaseMessageHandler
}
return result;
}
- } \ No newline at end of file
+ }
diff --git a/qpid/python/commands/qpid-config b/qpid/python/commands/qpid-config
index 838e9f340f..59145620cd 100755
--- a/qpid/python/commands/qpid-config
+++ b/qpid/python/commands/qpid-config
@@ -473,7 +473,7 @@ try:
except KeyboardInterrupt:
print
except Exception,e:
- print "Failed:", e.args
+ print "Failed: %s: %s" % (e.__class__.__name__, e)
sys.exit(1)
bm.Disconnect()
diff --git a/qpid/python/qmf/console.py b/qpid/python/qmf/console.py
index de8df06adc..36553562f7 100644
--- a/qpid/python/qmf/console.py
+++ b/qpid/python/qmf/console.py
@@ -25,10 +25,13 @@ import qpid
import struct
import socket
import re
+from qpid.datatypes import UUID
+from qpid.datatypes import timestamp
+from qpid.datatypes import datetime
from qpid.peer import Closed
from qpid.session import SessionDetached
-from qpid.connection import Connection, ConnectionFailed
-from qpid.datatypes import Message, RangedSet
+from qpid.connection import Connection, ConnectionFailed, Timeout
+from qpid.datatypes import Message, RangedSet, UUID
from qpid.util import connect, ssl, URL
from qpid.codec010 import StringCodec as Codec
from threading import Lock, Condition, Thread
@@ -107,6 +110,289 @@ class BrokerURL(URL):
def match(self, host, port):
return socket.gethostbyname(self.host) == socket.gethostbyname(host) and self.port == port
+class Object(object):
+ """ This class defines a 'proxy' object representing a real managed object on an agent.
+ Actions taken on this proxy are remotely affected on the real managed object.
+ """
+ def __init__(self, session, broker, schema, codec, prop, stat, managed=True, kwargs={}):
+ self._session = session
+ self._broker = broker
+ self._schema = schema
+ self._managed = managed
+ if self._managed:
+ self._currentTime = codec.read_uint64()
+ self._createTime = codec.read_uint64()
+ self._deleteTime = codec.read_uint64()
+ self._objectId = ObjectId(codec)
+ else:
+ self._currentTime = None
+ self._createTime = None
+ self._deleteTime = None
+ self._objectId = None
+ self._properties = []
+ self._statistics = []
+ if codec:
+ if prop:
+ notPresent = self._parsePresenceMasks(codec, schema)
+ for property in schema.getProperties():
+ if property.name in notPresent:
+ self._properties.append((property, None))
+ else:
+ self._properties.append((property, self._session._decodeValue(codec, property.type, broker)))
+ if stat:
+ for statistic in schema.getStatistics():
+ self._statistics.append((statistic, self._session._decodeValue(codec, statistic.type, broker)))
+ else:
+ for property in schema.getProperties():
+ if property.optional:
+ self._properties.append((property, None))
+ else:
+ self._properties.append((property, self._session._defaultValue(property, broker, kwargs)))
+ for statistic in schema.getStatistics():
+ self._statistics.append((statistic, self._session._defaultValue(statistic, broker, kwargs)))
+
+ def getBroker(self):
+ """ Return the broker from which this object was sent """
+ return self._broker
+
+ def getObjectId(self):
+ """ Return the object identifier for this object """
+ return self._objectId
+
+ def getClassKey(self):
+ """ Return the class-key that references the schema describing this object. """
+ return self._schema.getKey()
+
+ def getSchema(self):
+ """ Return the schema that describes this object. """
+ return self._schema
+
+ def getMethods(self):
+ """ Return a list of methods available for this object. """
+ return self._schema.getMethods()
+
+ def getTimestamps(self):
+ """ Return the current, creation, and deletion times for this object. """
+ return self._currentTime, self._createTime, self._deleteTime
+
+ def isDeleted(self):
+ """ Return True iff this object has been deleted. """
+ return self._deleteTime != 0
+
+ def isManaged(self):
+ """ Return True iff this object is a proxy for a managed object on an agent. """
+ return self._managed
+
+ def getIndex(self):
+ """ Return a string describing this object's primary key. """
+ result = u""
+ for property, value in self._properties:
+ if property.index:
+ if result != u"":
+ result += u":"
+ try:
+ valstr = unicode(self._session._displayValue(value, property.type))
+ except:
+ valstr = u"<undecodable>"
+ result += valstr
+ return result
+
+ def getProperties(self):
+ """ Return a list of object properties """
+ return self._properties
+
+ def getStatistics(self):
+ """ Return a list of object statistics """
+ return self._statistics
+
+ def mergeUpdate(self, newer):
+ """ Replace properties and/or statistics with a newly received update """
+ if not self.isManaged():
+ raise Exception("Object is not managed")
+ if self._objectId != newer._objectId:
+ raise Exception("Objects with different object-ids")
+ if len(newer.getProperties()) > 0:
+ self._properties = newer.getProperties()
+ if len(newer.getStatistics()) > 0:
+ self._statistics = newer.getStatistics()
+
+ def update(self):
+ """ Contact the agent and retrieve the lastest property and statistic values for this object. """
+ if not self.isManaged():
+ raise Exception("Object is not managed")
+ obj = self._session.getObjects(_objectId = self._objectId, _broker=self._broker)
+ if obj:
+ self.mergeUpdate(obj[0])
+ else:
+ raise Exception("Underlying object no longer exists")
+
+ def __repr__(self):
+ if self.isManaged():
+ id = self.getObjectId().__repr__()
+ else:
+ id = "unmanaged"
+ key = self.getClassKey()
+ return key.getPackageName() + ":" + key.getClassName() +\
+ "[" + id + "] " + self.getIndex().encode("utf8")
+
+ def __getattr__(self, name):
+ for method in self._schema.getMethods():
+ if name == method.name:
+ return lambda *args, **kwargs : self._invoke(name, args, kwargs)
+ for property, value in self._properties:
+ if name == property.name:
+ return value
+ if name == "_" + property.name + "_" and property.type == 10: # Dereference references
+ deref = self._session.getObjects(_objectId=value, _broker=self._broker)
+ if len(deref) != 1:
+ return None
+ else:
+ return deref[0]
+ for statistic, value in self._statistics:
+ if name == statistic.name:
+ return value
+ raise Exception("Type Object has no attribute '%s'" % name)
+
+ def __setattr__(self, name, value):
+ if name[0] == '_':
+ super.__setattr__(self, name, value)
+ return
+
+ for prop, unusedValue in self._properties:
+ if name == prop.name:
+ newprop = (prop, value)
+ newlist = []
+ for old, val in self._properties:
+ if name == old.name:
+ newlist.append(newprop)
+ else:
+ newlist.append((old, val))
+ self._properties = newlist
+ return
+ super.__setattr__(self, name, value)
+
+ def _sendMethodRequest(self, name, args, kwargs, synchronous=False, timeWait=None):
+ for method in self._schema.getMethods():
+ if name == method.name:
+ aIdx = 0
+ sendCodec = Codec(self._broker.conn.spec)
+ seq = self._session.seqMgr._reserve((method, synchronous))
+ self._broker._setHeader(sendCodec, 'M', seq)
+ self._objectId.encode(sendCodec)
+ self._schema.getKey().encode(sendCodec)
+ sendCodec.write_str8(name)
+
+ count = 0
+ for arg in method.arguments:
+ if arg.dir.find("I") != -1:
+ count += 1
+ if count != len(args):
+ raise Exception("Incorrect number of arguments: expected %d, got %d" % (count, len(args)))
+
+ for arg in method.arguments:
+ if arg.dir.find("I") != -1:
+ self._session._encodeValue(sendCodec, args[aIdx], arg.type)
+ aIdx += 1
+ if timeWait:
+ ttl = timeWait * 1000
+ else:
+ ttl = None
+ smsg = self._broker._message(sendCodec.encoded, "agent.%d.%d" %
+ (self._objectId.getBrokerBank(), self._objectId.getAgentBank()),
+ ttl=ttl)
+ if synchronous:
+ try:
+ self._broker.cv.acquire()
+ self._broker.syncInFlight = True
+ finally:
+ self._broker.cv.release()
+ self._broker._send(smsg)
+ return seq
+ return None
+
+ def _invoke(self, name, args, kwargs):
+ if not self.isManaged():
+ raise Exception("Object is not managed")
+ if "_timeout" in kwargs:
+ timeout = kwargs["_timeout"]
+ else:
+ timeout = self._broker.SYNC_TIME
+
+ if "_async" in kwargs and kwargs["_async"]:
+ sync = False
+ if "_timeout" not in kwargs:
+ timeout = None
+ else:
+ sync = True
+
+ seq = self._sendMethodRequest(name, args, kwargs, sync, timeout)
+ if seq:
+ if not sync:
+ return seq
+ try:
+ self._broker.cv.acquire()
+ starttime = time()
+ while self._broker.syncInFlight and self._broker.error == None:
+ self._broker.cv.wait(timeout)
+ if time() - starttime > timeout:
+ self._session.seqMgr._release(seq)
+ raise RuntimeError("Timed out waiting for method to respond")
+ finally:
+ self._broker.cv.release()
+ if self._broker.error != None:
+ errorText = self._broker.error
+ self._broker.error = None
+ raise Exception(errorText)
+ return self._broker.syncResult
+ raise Exception("Invalid Method (software defect) [%s]" % name)
+
+ def _encodeUnmanaged(self, codec):
+ # emit presence masks for optional properties
+ mask = 0
+ bit = 0
+ for prop, value in self._properties:
+ if prop.optional:
+ if bit == 0:
+ bit = 1
+ if value:
+ mask |= bit
+ bit = bit << 1
+ if bit == 256:
+ bit = 0
+ codec.write_uint8(mask)
+ mask = 0
+ if bit != 0:
+ codec.write_uint8(mask)
+
+ codec.write_uint8(20)
+ codec.write_str8(self._schema.getKey().getPackageName())
+ codec.write_str8(self._schema.getKey().getClassName())
+ codec.write_bin128(self._schema.getKey().getHash())
+
+ # encode properties
+ for prop, value in self._properties:
+ if value != None:
+ self._session._encodeValue(codec, value, prop.type)
+
+ # encode statistics
+ for stat, value in self._statistics:
+ self._session._encodeValue(codec, value, stat.type)
+
+ def _parsePresenceMasks(self, codec, schema):
+ excludeList = []
+ bit = 0
+ for property in schema.getProperties():
+ if property.optional:
+ if bit == 0:
+ mask = codec.read_uint8()
+ bit = 1
+ if (mask & bit) == 0:
+ excludeList.append(property.name)
+ bit *= 2
+ if bit == 256:
+ bit = 0
+ return excludeList
+
class Session:
"""
An instance of the Session class represents a console session running
@@ -119,6 +405,18 @@ class Session:
DEFAULT_GET_WAIT_TIME = 60
+ ENCODINGS = {
+ str: 7,
+ timestamp: 8,
+ datetime: 8,
+ int: 9,
+ long: 9,
+ float: 13,
+ UUID: 14,
+ Object: 20,
+ list: 21
+ }
+
def __init__(self, console=None, rcvObjects=True, rcvEvents=True, rcvHeartbeats=True,
manageConnections=False, userBindings=False):
"""
@@ -265,6 +563,13 @@ class Session:
agentList.append(a)
return agentList
+ def makeObject(self, classKey, broker=None, **kwargs):
+ """ Create a new, unmanaged object of the schema indicated by classKey """
+ schema = self.getSchema(classKey)
+ if schema == None:
+ raise Exception("Schema not found for classKey")
+ return Object(self, broker, schema, None, True, True, False, kwargs)
+
def getObjects(self, **kwargs):
""" Get a list of objects from QMF agents.
All arguments are passed by name(keyword).
@@ -521,7 +826,7 @@ class Session:
if code == 0:
for arg in method.arguments:
if arg.dir.find("O") != -1:
- outArgs[arg.name] = self._decodeValue(codec, arg.type)
+ outArgs[arg.name] = self._decodeValue(codec, arg.type, broker)
result = MethodResult(code, text, outArgs)
if synchronous:
try:
@@ -559,7 +864,7 @@ class Session:
def _handleSchemaResp(self, broker, codec, seq):
kind = codec.read_uint8()
classKey = ClassKey(codec)
- _class = SchemaClass(kind, classKey, codec)
+ _class = SchemaClass(kind, classKey, codec, self)
try:
self.cv.acquire()
self.packages[classKey.getPackageName()][classKey.getPackageKey()] = _class
@@ -605,9 +910,10 @@ class Session:
self.console.objectStats(broker, object)
def _handleError(self, error):
- self.error = error
try:
self.cv.acquire()
+ if len(self.syncSequenceList) > 0:
+ self.error = error
self.syncSequenceList = []
self.cv.notify()
finally:
@@ -621,7 +927,7 @@ class Session:
return False
return True
- def _decodeValue(self, codec, typecode):
+ def _decodeValue(self, codec, typecode, broker=None):
""" Decode, from the codec, a value based on its typecode. """
if typecode == 1: data = codec.read_uint8() # U8
elif typecode == 2: data = codec.read_uint16() # U16
@@ -636,11 +942,59 @@ class Session:
elif typecode == 12: data = codec.read_float() # FLOAT
elif typecode == 13: data = codec.read_double() # DOUBLE
elif typecode == 14: data = codec.read_uuid() # UUID
- elif typecode == 15: data = codec.read_map() # FTABLE
elif typecode == 16: data = codec.read_int8() # S8
elif typecode == 17: data = codec.read_int16() # S16
elif typecode == 18: data = codec.read_int32() # S32
elif typecode == 19: data = codec.read_int64() # S63
+ elif typecode == 15: # FTABLE
+ data = {}
+ sc = Codec(codec.spec, codec.read_vbin32())
+ if sc.encoded:
+ count = sc.read_uint32()
+ while count > 0:
+ k = sc.read_str8()
+ code = sc.read_uint8()
+ v = self._decodeValue(sc, code, broker)
+ data[k] = v
+ count -= 1
+ elif typecode == 20: # OBJECT
+ # Peek at the type, and if it is still 20 pull it decode. If
+ # Not, call back into self.
+ inner_type_code = codec.read_uint8()
+ if inner_type_code == 20:
+ classKey = ClassKey(codec)
+ try:
+ self.cv.acquire()
+ pname = classKey.getPackageName()
+ if pname not in self.packages:
+ return None
+ pkey = classKey.getPackageKey()
+ if pkey not in self.packages[pname]:
+ return None
+ schema = self.packages[pname][pkey]
+ finally:
+ self.cv.release()
+ data = Object(self, broker, schema, codec, True, True, False)
+ else:
+ data = self._decodeValue(codec, inner_type_code, broker)
+ elif typecode == 21: # List
+ #taken from codec10.read_list
+ sc = Codec(codec.spec, codec.read_vbin32())
+ count = sc.read_uint32()
+ data = []
+ while count > 0:
+ type = sc.read_uint8()
+ data.append(self._decodeValue(sc,type,broker))
+ count -= 1
+ elif typecode == 22: #Array
+ #taken from codec10.read_array
+ sc = Codec(codec.spec, codec.read_vbin32())
+ count = sc.read_uint32()
+ type = sc.read_uint8()
+ data = []
+ while count > 0:
+ data.append(self._decodeValue(sc,type,broker))
+ count -= 1
else:
raise ValueError("Invalid type code: %d" % typecode)
return data
@@ -660,14 +1014,54 @@ class Session:
elif typecode == 12: codec.write_float (float(value)) # FLOAT
elif typecode == 13: codec.write_double (float(value)) # DOUBLE
elif typecode == 14: codec.write_uuid (value.bytes) # UUID
- elif typecode == 15: codec.write_map (value) # FTABLE
elif typecode == 16: codec.write_int8 (int(value)) # S8
elif typecode == 17: codec.write_int16 (int(value)) # S16
elif typecode == 18: codec.write_int32 (int(value)) # S32
elif typecode == 19: codec.write_int64 (int(value)) # S64
+ elif typecode == 20: value._encodeUnmanaged(codec) # OBJECT
+ elif typecode == 15: # FTABLE
+ sc = Codec(codec.spec)
+ if value is not None:
+ sc.write_uint32(len(value))
+ for k, v in value.items():
+ mtype = self.encoding(v)
+ sc.write_str8(k)
+ sc.write_uint8(mtype)
+ self._encodeValue(sc, v, mtype)
+ else:
+ sc.write_uint32(0)
+ codec.write_vbin32(sc.encoded)
+ elif typecode == 21: # List
+ sc = Codec(codec.spec)
+ self._encodeValue(sc, len(value), 3)
+ for o in value:
+ ltype=self.encoding(o)
+ self._encodeValue(sc,ltype,1)
+ self._encodeValue(sc, o, ltype)
+ codec.write_vbin32(sc.encoded)
+ elif typecode == 22: # Array
+ sc = Codec(codec.spec)
+ self._encodeValue(sc, len(value), 3)
+ if len(value) > 0:
+ ltype = self.encoding(value[0])
+ self._encodeValue(sc,ltype,1)
+ for o in value:
+ self._encodeValue(sc, o, ltype)
+ codec.write_vbin32(sc.encoded)
else:
raise ValueError ("Invalid type code: %d" % typecode)
+ def encoding(self, value):
+ return self._encoding(value.__class__)
+
+ def _encoding(self, klass):
+ if Session.ENCODINGS.has_key(klass):
+ return self.ENCODINGS[klass]
+ for base in klass.__bases__:
+ result = self._encoding(base, obj)
+ if result != None:
+ return result
+
def _displayValue(self, value, typecode):
""" """
if typecode == 1: return unicode(value)
@@ -690,8 +1084,64 @@ class Session:
elif typecode == 17: return unicode(value)
elif typecode == 18: return unicode(value)
elif typecode == 19: return unicode(value)
+ elif typecode == 20: return unicode(value.__repr__())
+ elif typecode == 21: return unicode(value.__repr__())
+ elif typecode == 22: return unicode(value.__repr__())
+ else:
+ raise ValueError ("Invalid type code: %d" % typecode)
+
+ def _defaultValue(self, stype, broker=None, kwargs={}):
+ """ """
+ typecode = stype.type
+ if typecode == 1: return 0
+ elif typecode == 2: return 0
+ elif typecode == 3: return 0
+ elif typecode == 4: return 0
+ elif typecode == 6: return ""
+ elif typecode == 7: return ""
+ elif typecode == 8: return 0
+ elif typecode == 9: return 0
+ elif typecode == 10: return ObjectId(None)
+ elif typecode == 11: return False
+ elif typecode == 12: return 0.0
+ elif typecode == 13: return 0.0
+ elif typecode == 14: return UUID([0 for i in range(16)])
+ elif typecode == 15: return {}
+ elif typecode == 16: return 0
+ elif typecode == 17: return 0
+ elif typecode == 18: return 0
+ elif typecode == 19: return 0
+ elif typecode == 21: return []
+ elif typecode == 22: return []
+ elif typecode == 20:
+ try:
+ if "classKeys" in kwargs:
+ keyList = kwargs["classKeys"]
+ else:
+ keyList = None
+ classKey = self._bestClassKey(stype.refPackage, stype.refClass, keyList)
+ if classKey:
+ return self.makeObject(classKey, broker, kwargs)
+ except:
+ pass
+ return None
else:
raise ValueError ("Invalid type code: %d" % typecode)
+
+ def _bestClassKey(self, pname, cname, preferredList):
+ """ """
+ if pname == None or cname == None:
+ if len(preferredList) == 0:
+ return None
+ return preferredList[0]
+ for p in preferredList:
+ if p.getPackageName() == pname and p.getClassName() == cname:
+ return p
+ clist = self.getClasses(pname)
+ for c in clist:
+ if c.getClassName() == cname:
+ return c
+ return None
def _sendMethodRequest(self, broker, schemaKey, objectId, name, argList):
""" This function can be used to send a method request to an object given only the
@@ -783,18 +1233,24 @@ class SchemaClass:
CLASS_KIND_TABLE = 1
CLASS_KIND_EVENT = 2
- def __init__(self, kind, key, codec):
+ def __init__(self, kind, key, codec, session):
self.kind = kind
self.classKey = key
self.properties = []
self.statistics = []
self.methods = []
self.arguments = []
+ self.session = session
+ hasSupertype = codec.read_uint8()
if self.kind == self.CLASS_KIND_TABLE:
propCount = codec.read_uint16()
statCount = codec.read_uint16()
methodCount = codec.read_uint16()
+ if hasSupertype == 1:
+ self.superTypeKey = ClassKey(codec)
+ else:
+ self.superTypeKey = None ;
for idx in range(propCount):
self.properties.append(SchemaProperty(codec))
for idx in range(statCount):
@@ -804,6 +1260,10 @@ class SchemaClass:
elif self.kind == self.CLASS_KIND_EVENT:
argCount = codec.read_uint16()
+ if (hasSupertype):
+ self.superTypeKey = ClassKey(codec)
+ else:
+ self.superTypeKey = None ;
for idx in range(argCount):
self.arguments.append(SchemaArgument(codec, methodArg=False))
@@ -823,19 +1283,32 @@ class SchemaClass:
def getProperties(self):
""" Return the list of properties for the class. """
- return self.properties
+ if (self.superTypeKey == None):
+ return self.properties
+ else:
+ return self.properties + self.session.getSchema(self.superTypeKey).getProperties()
def getStatistics(self):
""" Return the list of statistics for the class. """
- return self.statistics
+ if (self.superTypeKey == None):
+ return self.statistics
+ else:
+ return self.statistics + self.session.getSchema(self.superTypeKey).getStatistics()
def getMethods(self):
""" Return the list of methods for the class. """
- return self.methods
+ if (self.superTypeKey == None):
+ return self.methods
+ else:
+ return self.methods + self.session.getSchema(self.superTypeKey).getMethods()
def getArguments(self):
""" Return the list of events for the class. """
- return self.arguments
+ """ Return the list of methods for the class. """
+ if (self.superTypeKey == None):
+ return self.arguments
+ else:
+ return self.arguments + self.session.getSchema(self.superTypeKey).getArguments()
class SchemaProperty:
""" """
@@ -846,18 +1319,22 @@ class SchemaProperty:
self.access = str(map["access"])
self.index = map["index"] != 0
self.optional = map["optional"] != 0
- self.unit = None
- self.min = None
- self.max = None
- self.maxlen = None
- self.desc = None
+ self.refPackage = None
+ self.refClass = None
+ self.unit = None
+ self.min = None
+ self.max = None
+ self.maxlen = None
+ self.desc = None
for key, value in map.items():
- if key == "unit" : self.unit = value
- elif key == "min" : self.min = value
- elif key == "max" : self.max = value
- elif key == "maxlen" : self.maxlen = value
- elif key == "desc" : self.desc = value
+ if key == "unit" : self.unit = value
+ elif key == "min" : self.min = value
+ elif key == "max" : self.max = value
+ elif key == "maxlen" : self.maxlen = value
+ elif key == "desc" : self.desc = value
+ elif key == "refPackage" : self.refPackage = value
+ elif key == "refClass" : self.refClass = value
def __repr__(self):
return self.name
@@ -920,6 +1397,8 @@ class SchemaArgument:
self.maxlen = None
self.desc = None
self.default = None
+ self.refPackage = None
+ self.refClass = None
for key, value in map.items():
if key == "unit" : self.unit = value
@@ -928,6 +1407,8 @@ class SchemaArgument:
elif key == "maxlen" : self.maxlen = value
elif key == "desc" : self.desc = value
elif key == "default" : self.default = value
+ elif key == "refPackage" : self.refPackage = value
+ elif key == "refClass" : self.refClass = value
class ObjectId:
""" Object that represents QMF object identifiers """
@@ -987,209 +1468,6 @@ class ObjectId:
def __eq__(self, other):
return (self.first, self.second).__eq__(other)
-class Object(object):
- """ This class defines a 'proxy' object representing a real managed object on an agent.
- Actions taken on this proxy are remotely affected on the real managed object.
- """
- def __init__(self, session, broker, schema, codec, prop, stat):
- self._session = session
- self._broker = broker
- self._schema = schema
- self._currentTime = codec.read_uint64()
- self._createTime = codec.read_uint64()
- self._deleteTime = codec.read_uint64()
- self._objectId = ObjectId(codec)
- self._properties = []
- self._statistics = []
- if prop:
- notPresent = self._parsePresenceMasks(codec, schema)
- for property in schema.getProperties():
- if property.name in notPresent:
- self._properties.append((property, None))
- else:
- self._properties.append((property, self._session._decodeValue(codec, property.type)))
- if stat:
- for statistic in schema.getStatistics():
- self._statistics.append((statistic, self._session._decodeValue(codec, statistic.type)))
-
- def getBroker(self):
- """ Return the broker from which this object was sent """
- return self._broker
-
- def getObjectId(self):
- """ Return the object identifier for this object """
- return self._objectId
-
- def getClassKey(self):
- """ Return the class-key that references the schema describing this object. """
- return self._schema.getKey()
-
- def getSchema(self):
- """ Return the schema that describes this object. """
- return self._schema
-
- def getMethods(self):
- """ Return a list of methods available for this object. """
- return self._schema.getMethods()
-
- def getTimestamps(self):
- """ Return the current, creation, and deletion times for this object. """
- return self._currentTime, self._createTime, self._deleteTime
-
- def isDeleted(self):
- """ Return True iff this object has been deleted. """
- return self._deleteTime != 0
-
- def getIndex(self):
- """ Return a string describing this object's primary key. """
- result = u""
- for property, value in self._properties:
- if property.index:
- if result != u"":
- result += u":"
- try:
- valstr = unicode(self._session._displayValue(value, property.type))
- except:
- valstr = u"<undecodable>"
- result += valstr
- return result
-
- def getProperties(self):
- """ Return a list of object properties """
- return self._properties
-
- def getStatistics(self):
- """ Return a list of object statistics """
- return self._statistics
-
- def mergeUpdate(self, newer):
- """ Replace properties and/or statistics with a newly received update """
- if self._objectId != newer._objectId:
- raise Exception("Objects with different object-ids")
- if len(newer.getProperties()) > 0:
- self._properties = newer.getProperties()
- if len(newer.getStatistics()) > 0:
- self._statistics = newer.getStatistics()
-
- def update(self):
- """ Contact the agent and retrieve the lastest property and statistic values for this object. """
- obj = self._session.getObjects(_objectId = self._objectId, _broker=self._broker)
- if obj:
- self.mergeUpdate(obj[0])
- else:
- raise Exception("Underlying object no longer exists")
-
- def __repr__(self):
- key = self.getClassKey()
- return key.getPackageName() + ":" + key.getClassName() +\
- "[" + self.getObjectId().__repr__() + "] " + self.getIndex().encode("utf8")
-
- def __getattr__(self, name):
- for method in self._schema.getMethods():
- if name == method.name:
- return lambda *args, **kwargs : self._invoke(name, args, kwargs)
- for property, value in self._properties:
- if name == property.name:
- return value
- if name == "_" + property.name + "_" and property.type == 10: # Dereference references
- deref = self._session.getObjects(_objectId=value, _broker=self._broker)
- if len(deref) != 1:
- return None
- else:
- return deref[0]
- for statistic, value in self._statistics:
- if name == statistic.name:
- return value
- raise Exception("Type Object has no attribute '%s'" % name)
-
- def _sendMethodRequest(self, name, args, kwargs, synchronous=False, timeWait=None):
- for method in self._schema.getMethods():
- if name == method.name:
- aIdx = 0
- sendCodec = Codec(self._broker.conn.spec)
- seq = self._session.seqMgr._reserve((method, synchronous))
- self._broker._setHeader(sendCodec, 'M', seq)
- self._objectId.encode(sendCodec)
- self._schema.getKey().encode(sendCodec)
- sendCodec.write_str8(name)
-
- count = 0
- for arg in method.arguments:
- if arg.dir.find("I") != -1:
- count += 1
- if count != len(args):
- raise Exception("Incorrect number of arguments: expected %d, got %d" % (count, len(args)))
-
- for arg in method.arguments:
- if arg.dir.find("I") != -1:
- self._session._encodeValue(sendCodec, args[aIdx], arg.type)
- aIdx += 1
- if timeWait:
- ttl = timeWait * 1000
- else:
- ttl = None
- smsg = self._broker._message(sendCodec.encoded, "agent.%d.%d" %
- (self._objectId.getBrokerBank(), self._objectId.getAgentBank()),
- ttl=ttl)
- if synchronous:
- try:
- self._broker.cv.acquire()
- self._broker.syncInFlight = True
- finally:
- self._broker.cv.release()
- self._broker._send(smsg)
- return seq
- return None
-
- def _invoke(self, name, args, kwargs):
- if "_timeout" in kwargs:
- timeout = kwargs["_timeout"]
- else:
- timeout = self._broker.SYNC_TIME
-
- if "_async" in kwargs and kwargs["_async"]:
- sync = False
- if "_timeout" not in kwargs:
- timeout = None
- else:
- sync = True
-
- seq = self._sendMethodRequest(name, args, kwargs, sync, timeout)
- if seq:
- if not sync:
- return seq
- try:
- self._broker.cv.acquire()
- starttime = time()
- while self._broker.syncInFlight and self._broker.error == None:
- self._broker.cv.wait(timeout)
- if time() - starttime > timeout:
- self._session.seqMgr._release(seq)
- raise RuntimeError("Timed out waiting for method to respond")
- finally:
- self._broker.cv.release()
- if self._broker.error != None:
- errorText = self._broker.error
- self._broker.error = None
- raise Exception(errorText)
- return self._broker.syncResult
- raise Exception("Invalid Method (software defect) [%s]" % name)
-
- def _parsePresenceMasks(self, codec, schema):
- excludeList = []
- bit = 0
- for property in schema.getProperties():
- if property.optional:
- if bit == 0:
- mask = codec.read_uint8()
- bit = 1
- if (mask & bit) == 0:
- excludeList.append(property.name)
- bit *= 2
- if bit == 256:
- bit = 0
- return excludeList
-
class MethodResult(object):
""" """
def __init__(self, status, text, outArgs):
@@ -1361,9 +1639,13 @@ class Broker:
self.reqsOutstanding = 1
sock = connect(self.host, self.port)
+ sock.settimeout(5)
if self.ssl:
sock = ssl(sock)
- self.conn = Connection(sock, username=self.authUser, password=self.authPass)
+ self.conn = Connection(sock, username=self.authUser, password=self.authPass, heartbeat=2)
+ def aborted():
+ raise Timeout("read timed out")
+ self.conn.aborted = aborted
self.conn.start()
self.replyName = "reply-%s" % self.amqpSessionId
self.amqpSession = self.conn.session(self.amqpSessionId)
@@ -1424,7 +1706,7 @@ class Broker:
""" Compose the header of a management message. """
codec.write_uint8(ord('A'))
codec.write_uint8(ord('M'))
- codec.write_uint8(ord('2'))
+ codec.write_uint8(ord('3'))
codec.write_uint8(ord(opcode))
codec.write_uint32(seq)
@@ -1438,7 +1720,7 @@ class Broker:
if octet != 'M':
return None, None
octet = chr(codec.read_uint8())
- if octet != '2':
+ if octet != '3':
return None, None
opcode = chr(codec.read_uint8())
seq = codec.read_uint32()
@@ -1453,6 +1735,7 @@ class Broker:
dp.ttl = ttl
mp = self.amqpSession.message_properties()
mp.content_type = "x-application/qmf"
+ mp.user_id = self.authUser
mp.reply_to = self.amqpSession.reply_to("amq.direct", self.replyName)
return Message(dp, mp, body)
@@ -1576,7 +1859,7 @@ class Event:
self.schema = session.packages[pname][pkey]
self.arguments = {}
for arg in self.schema.arguments:
- self.arguments[arg.name] = session._decodeValue(codec, arg.type)
+ self.arguments[arg.name] = session._decodeValue(codec, arg.type, broker)
def __repr__(self):
if self.schema == None:
diff --git a/qpid/python/qpid/management.py b/qpid/python/qpid/management.py
index 546e68ae8e..b97709d367 100644
--- a/qpid/python/qpid/management.py
+++ b/qpid/python/qpid/management.py
@@ -401,7 +401,7 @@ class managementClient:
""" Compose the header of a management message. """
codec.write_uint8 (ord ('A'))
codec.write_uint8 (ord ('M'))
- codec.write_uint8 (ord ('2'))
+ codec.write_uint8 (ord ('3'))
codec.write_uint8 (opcode)
codec.write_uint32 (seq)
@@ -415,7 +415,7 @@ class managementClient:
if octet != 'M':
return None
octet = chr (codec.read_uint8 ())
- if octet != '2':
+ if octet != '3':
return None
opcode = chr (codec.read_uint8 ())
seq = codec.read_uint32 ()
@@ -672,9 +672,14 @@ class managementClient:
packageName = codec.read_str8 ()
className = codec.read_str8 ()
hash = codec.read_bin128 ()
+ hasSupertype = codec.read_uint8()
configCount = codec.read_uint16 ()
instCount = codec.read_uint16 ()
methodCount = codec.read_uint16 ()
+ if hasSupertype != 0:
+ supertypePackage = codec.read_str8()
+ supertypeClass = codec.read_str8()
+ supertypeHash = codec.read_bin128()
if packageName not in self.packages:
return
diff --git a/qpid/python/qpid/managementdata.py b/qpid/python/qpid/managementdata.py
index e1fd8d54eb..84eb9c3ff8 100644
--- a/qpid/python/qpid/managementdata.py
+++ b/qpid/python/qpid/managementdata.py
@@ -360,6 +360,12 @@ class ManagementData:
return "int32"
elif typecode == 19:
return "int64"
+ elif typecode == 20:
+ return "object"
+ elif typecode == 21:
+ return "list"
+ elif typecode == 22:
+ return "array"
else:
raise ValueError ("Invalid type code: %d" % typecode)
diff --git a/qpid/ruby/lib/qpid/qmf.rb b/qpid/ruby/lib/qpid/qmf.rb
index b7309155c3..56037fff62 100644
--- a/qpid/ruby/lib/qpid/qmf.rb
+++ b/qpid/ruby/lib/qpid/qmf.rb
@@ -773,10 +773,16 @@ module Qpid::Qmf
@methods = []
@arguments = []
+ has_supertype = codec.read_uint8
if @kind == CLASS_KIND_TABLE
prop_count = codec.read_uint16
stat_count = codec.read_uint16
method_count = codec.read_uint16
+ if has_supertype == 1
+ codec.read_str8
+ codec.read_str8
+ codec.read_bin128
+ end
prop_count.times { |idx|
@properties << SchemaProperty.new(codec) }
stat_count.times { |idx|
@@ -1111,13 +1117,11 @@ module Qpid::Qmf
def invoke(method, name, args)
kwargs = args[args.size - 1]
sync = true
- timeout = nil
+ timeout = DEFAULT_METHOD_WAIT_TIME
if kwargs.class == Hash
if kwargs.include?(:timeout)
timeout = kwargs[:timeout]
- else
- timeout = DEFAULT_METHOD_WAIT_TIME
end
if kwargs.include?(:async)
@@ -1343,7 +1347,7 @@ module Qpid::Qmf
def set_header(codec, opcode, seq=0)
codec.write_uint8(?A)
codec.write_uint8(?M)
- codec.write_uint8(?2)
+ codec.write_uint8(?3)
codec.write_uint8(opcode)
codec.write_uint32(seq)
end
@@ -1508,7 +1512,7 @@ module Qpid::Qmf
begin
return [nil, nil] unless codec.read_uint8 == ?A
return [nil, nil] unless codec.read_uint8 == ?M
- return [nil, nil] unless codec.read_uint8 == ?2
+ return [nil, nil] unless codec.read_uint8 == ?3
opcode = codec.read_uint8
seq = codec.read_uint32
return [opcode, seq]