diff options
| author | Ted Ross <tross@apache.org> | 2009-06-16 21:03:24 +0000 |
|---|---|---|
| committer | Ted Ross <tross@apache.org> | 2009-06-16 21:03:24 +0000 |
| commit | f5e98a6dfb8c4defe22755340f440e6f16c2559a (patch) | |
| tree | e442af3ec60520a7bab88cab2e07e1b83f9b5468 /java/management/agent | |
| parent | e79f8a1242e5e626db2784ae48ef31a433e7a7d4 (diff) | |
| download | qpid-python-f5e98a6dfb8c4defe22755340f440e6f16c2559a.tar.gz | |
QPID-1905 - Moved qmf agent code to java/management/agent where it belongs.
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk/qpid@785400 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/management/agent')
30 files changed, 3795 insertions, 0 deletions
diff --git a/java/management/agent/build.xml b/java/management/agent/build.xml new file mode 100644 index 0000000000..a410c74c1f --- /dev/null +++ b/java/management/agent/build.xml @@ -0,0 +1,27 @@ +<!-- + - + - 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"/> + + <import file="../../module.xml"/> + +</project> diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/Agent.java b/java/management/agent/src/main/java/org/apache/qpid/agent/Agent.java new file mode 100644 index 0000000000..80348c52d9 --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/Agent.java @@ -0,0 +1,659 @@ +/* + * + * 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; + +/** + * The main class for interacting with the QMF bus. Objects which are + * to be managed can be registered with the agent, as can classes + * to be exposed via the schema. + */ +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); + } + } + + /** + * Starts up the agent. Many bean containers may call this by + * default which aids in deployment + */ + 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); + } + } + + /** + * Send an event object to the bus + */ + 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] != '3') + { + 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) '3'); + 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/java/management/agent/src/main/java/org/apache/qpid/agent/AgentException.java b/java/management/agent/src/main/java/org/apache/qpid/agent/AgentException.java new file mode 100644 index 0000000000..ed189d2bc0 --- /dev/null +++ b/java/management/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/java/management/agent/src/main/java/org/apache/qpid/agent/EventSeverity.java b/java/management/agent/src/main/java/org/apache/qpid/agent/EventSeverity.java new file mode 100644 index 0000000000..a3528d9804 --- /dev/null +++ b/java/management/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/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedEJB.java b/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedEJB.java new file mode 100644 index 0000000000..4c5bc594d3 --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedEJB.java @@ -0,0 +1,109 @@ +/* + * + * 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; + +/** + * Wrapper classe for adding EJBS which are to be + * managed by the QMF Agent. The jndi location and the + * public interface to exposed are used to generate the schema. + */ +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/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedObject.java b/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedObject.java new file mode 100644 index 0000000000..aa3bbf3894 --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedObject.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 org.apache.qpid.agent.binding.MethodBinding; +import org.apache.qpid.agent.binding.PropertyBinding; + +/** + * Objects which are to be managed and controlled by the QMF Agent. + */ +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); +} diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedObjectBase.java b/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedObjectBase.java new file mode 100644 index 0000000000..51789ae11f --- /dev/null +++ b/java/management/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/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedPOJO.java b/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedPOJO.java new file mode 100644 index 0000000000..061334b252 --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedPOJO.java @@ -0,0 +1,91 @@ +/* + * + * 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; + +/** + * Wrapper classe for adding POJOS which are to be + * managed by the QMF Agent. + */ +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/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFEvent.java b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFEvent.java new file mode 100644 index 0000000000..319c471445 --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFEvent.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.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; + +/** + * Tells the QMF Agent that this object will be passed as a + * QMF event. This will cause only properties to be sent across + * the wire. + */ +@Target(TYPE) +@Retention(RUNTIME) +@Documented +public @interface QMFEvent +{ + String eventName(); + + String packageName(); +} diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFHide.java b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFHide.java new file mode 100644 index 0000000000..f3824ff228 --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFHide.java @@ -0,0 +1,39 @@ +/* + * + * 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; + +/** + * Causes the property which is annotated to not be added to the + * QMF schema when it is built. + */ +@Target(ElementType.METHOD) +@Retention(RUNTIME) +@Documented +public @interface QMFHide +{ +} diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFObject.java b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFObject.java new file mode 100644 index 0000000000..d737dbb852 --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFObject.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.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; + +/** + * Tells the QMF Agent that this object will be a managed + * object. This will allow users to query for it, as well as + * invoke methods on it. + */ +@Target(TYPE) +@Retention(RUNTIME) +@Documented +public @interface QMFObject +{ + String className(); + + String packageName(); +} diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFProperty.java b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFProperty.java new file mode 100644 index 0000000000..f309fa95b5 --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFProperty.java @@ -0,0 +1,39 @@ +/* + * + * 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; + +/** + * Controls the QMF schema which is generated for this property. + */ +@Target(ElementType.FIELD) +@Retention(RUNTIME) +@Documented +public @interface QMFProperty +{ + boolean optional() default false; +} diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFSeeAlso.java b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFSeeAlso.java new file mode 100644 index 0000000000..c14ea11ca4 --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFSeeAlso.java @@ -0,0 +1,40 @@ +/* + * + * 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; + +/** + * Augements the schema generation process to look for known + * subclasses of a type. Modeled after the JAXB @XMLSeeAlso. + */ +@Target(TYPE) +@Retention(RUNTIME) +@Documented +public @interface QMFSeeAlso +{ + Class[] value(); +} diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFType.java b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFType.java new file mode 100644 index 0000000000..5d43276a55 --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFType.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.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; + +/** + * Tells the QMF Agent that this object will be a type only + * This will cause only properties to be sent across + * the wire. + */ +@Target(TYPE) +@Retention(RUNTIME) +@Documented +public @interface QMFType +{ + String className(); + + String packageName(); +} diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingContext.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingContext.java new file mode 100644 index 0000000000..aa84b9dd54 --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingContext.java @@ -0,0 +1,213 @@ +/* + * + * 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; + +/** + * Contains the mappings from java classes to QMF schema and back. + * There is one context per agent, and it contains all the metadata. + */ +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/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingException.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingException.java new file mode 100644 index 0000000000..f8e436290c --- /dev/null +++ b/java/management/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/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingUtils.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingUtils.java new file mode 100644 index 0000000000..14f3fda0f1 --- /dev/null +++ b/java/management/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/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ClassBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ClassBinding.java new file mode 100644 index 0000000000..3de978e34b --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ClassBinding.java @@ -0,0 +1,602 @@ +/* + * + * 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; + +/** + * Binding information from a custom java class to a QMF schema + */ +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/java/management/agent/src/main/java/org/apache/qpid/agent/binding/EnumBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/EnumBinding.java new file mode 100644 index 0000000000..ef4abc743b --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/EnumBinding.java @@ -0,0 +1,102 @@ +/* + * + * 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; + +/** + * Binding information from a java enum to a QMF schema + */ +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/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ListBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ListBinding.java new file mode 100644 index 0000000000..0de8a07107 --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ListBinding.java @@ -0,0 +1,130 @@ +/* + * + * 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; + +/** + * Binding information from a java list to a QMF schema. + */ +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); + if (list != null) { + newEncoder.writeUint32(list.size()); + for (Object obj : list) + { + TypeBinding type = bctx.getTypeBinding(obj.getClass()); + newEncoder.writeUint8(type.getCode()); + type.encode(newEncoder, obj); + } + } + else { + newEncoder.writeUint32(0) ; + } + 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/java/management/agent/src/main/java/org/apache/qpid/agent/binding/MapBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/MapBinding.java new file mode 100644 index 0000000000..80889f3b4e --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/MapBinding.java @@ -0,0 +1,136 @@ +/* + * + * 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; + +/** + * Binding information from a java Map to a QMF schema. + */ +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/java/management/agent/src/main/java/org/apache/qpid/agent/binding/MethodBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/MethodBinding.java new file mode 100644 index 0000000000..fc05c7393a --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/MethodBinding.java @@ -0,0 +1,91 @@ +/* + * + * 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; + +/** + * Metadata for mapping a method to a QMF schema + */ +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/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ParameterBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ParameterBinding.java new file mode 100644 index 0000000000..7362976e0e --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ParameterBinding.java @@ -0,0 +1,121 @@ +/* + * + * 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; + +/** + * Metadata for mapping a method argument to a QMF schema + */ +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/java/management/agent/src/main/java/org/apache/qpid/agent/binding/PropertyBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/PropertyBinding.java new file mode 100644 index 0000000000..22ad8cd8e4 --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/PropertyBinding.java @@ -0,0 +1,132 @@ +/* + * + * 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; + + +/** + * Metadata for mapping a java property (getter/setter) to a QMF schema + */ +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/java/management/agent/src/main/java/org/apache/qpid/agent/binding/QMFTypeBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/QMFTypeBinding.java new file mode 100644 index 0000000000..11ccf1b1a7 --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/QMFTypeBinding.java @@ -0,0 +1,465 @@ +/* + * + * 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; + +/** + * Basic type mappings for QMF schema + */ +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/java/management/agent/src/main/java/org/apache/qpid/agent/binding/TypeBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/TypeBinding.java new file mode 100644 index 0000000000..97ec943bfd --- /dev/null +++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/TypeBinding.java @@ -0,0 +1,46 @@ +/* + * + * 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; + +/** + * Binding between Java Type and QMF type + */ +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/java/management/agent/src/test/java/org/apache/qpid/agent/Crumpet.java b/java/management/agent/src/test/java/org/apache/qpid/agent/Crumpet.java new file mode 100644 index 0000000000..67095c809b --- /dev/null +++ b/java/management/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/java/management/agent/src/test/java/org/apache/qpid/agent/Muppet.java b/java/management/agent/src/test/java/org/apache/qpid/agent/Muppet.java new file mode 100644 index 0000000000..f039ab9baa --- /dev/null +++ b/java/management/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/java/management/agent/src/test/java/org/apache/qpid/agent/Pikelet.java b/java/management/agent/src/test/java/org/apache/qpid/agent/Pikelet.java new file mode 100644 index 0000000000..f820fa6258 --- /dev/null +++ b/java/management/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/java/management/agent/src/test/java/org/apache/qpid/agent/Puppet.java b/java/management/agent/src/test/java/org/apache/qpid/agent/Puppet.java new file mode 100644 index 0000000000..bfd34840f8 --- /dev/null +++ b/java/management/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; + } +} |
