From d38d0aedd98086b89f9f74afe76a7cc7bcbab37d Mon Sep 17 00:00:00 2001 From: Andrea Gazzarini Date: Fri, 23 Jan 2009 20:44:48 +0000 Subject: QPID-1579 : WS-DM unit tests and method invocation improvements git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk/qpid@737182 13f79535-47bb-0310-9956-ffa450edef68 --- java/management/client/build.xml | 123 +-- java/management/client/src/main/java/muse.xml | 10 +- .../java/org/apache/qpid/management/Messages.java | 8 + .../java/org/apache/qpid/management/Names.java | 3 +- .../domain/handler/impl/InvocationResult.java | 2 +- .../domain/handler/impl/QpidDomainObject.java | 307 ++++++ .../domain/handler/impl/QpidDomainObjectMBean.java | 227 +++++ .../qpid/management/domain/model/QpidClass.java | 7 +- .../java/org/apache/qpid/management/wsdm/QEmu.java | 124 +++ .../qpid/management/wsdm/QEmuInitializer.java | 92 ++ .../org/apache/qpid/management/wsdm/QEmuMBean.java | 48 + .../wsdm/capabilities/DummyCapabilityBuilder.java | 61 ++ .../wsdm/capabilities/MBeanCapability.java | 144 +-- .../wsdm/capabilities/MBeanCapabilityBuilder.java | 361 ++++--- .../wsdm/capabilities/QManAdapterCapability.java | 3 +- .../wsdm/capabilities/QManMessageHandler.java | 103 ++ .../management/wsdm/capabilities/RmdBuilder.java | 6 +- .../management/wsdm/capabilities/WsArtifacts.java | 45 +- .../wsdm/capabilities/WsArtifactsFactory.java | 3 +- .../management/wsdm/capabilities/WsdlBuilder.java | 171 ++-- .../wsdm/muse/engine/WSDMAdapterEnvironment.java | 11 +- .../wsdm/muse/resources/QManWsResource.java | 25 +- .../wsdm/muse/serializer/DateSerializer.java | 75 ++ .../serializer/InvocationResultSerializer.java | 1 - .../wsdm/muse/serializer/MapSerializer.java | 24 +- .../wsdm/muse/serializer/ObjectSerializer.java | 65 +- .../org/apache/qpid/qman/debug/WsdlDebugger.java | 49 + java/management/client/src/test/java/log4j.xml | 23 + .../org/apache/qpid/management/TestConstants.java | 5 +- .../wsdm/EnhancedReflectionProxyHandler.java | 67 ++ .../apache/qpid/management/wsdm/ServerThread.java | 82 ++ .../wsdm/WebApplicationLifeCycleListener.java | 52 + .../qpid/management/wsdm/WsDmAdapterTest.java | 1026 ++++++++++++++++++++ .../capabilities/MBeanCapabilityBuilderTest.java | 278 ++++++ .../wsdm/capabilities/MBeanCapabilityTest.java | 204 ++++ .../wsdm/capabilities/RmdBuilderTest.java | 110 +++ .../java/org/apache/qpid/management/wsdm/web.xml | 11 + 37 files changed, 3553 insertions(+), 403 deletions(-) create mode 100644 java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObject.java create mode 100644 java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObjectMBean.java create mode 100644 java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmu.java create mode 100644 java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuInitializer.java create mode 100644 java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuMBean.java create mode 100644 java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/DummyCapabilityBuilder.java create mode 100644 java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManMessageHandler.java create mode 100644 java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/DateSerializer.java create mode 100644 java/management/client/src/main/java/org/apache/qpid/qman/debug/WsdlDebugger.java create mode 100644 java/management/client/src/test/java/log4j.xml create mode 100644 java/management/client/src/test/java/org/apache/qpid/management/wsdm/EnhancedReflectionProxyHandler.java create mode 100644 java/management/client/src/test/java/org/apache/qpid/management/wsdm/ServerThread.java create mode 100644 java/management/client/src/test/java/org/apache/qpid/management/wsdm/WebApplicationLifeCycleListener.java create mode 100644 java/management/client/src/test/java/org/apache/qpid/management/wsdm/WsDmAdapterTest.java create mode 100644 java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilderTest.java create mode 100644 java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityTest.java create mode 100644 java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilderTest.java create mode 100644 java/management/client/src/test/java/org/apache/qpid/management/wsdm/web.xml (limited to 'java/management') diff --git a/java/management/client/build.xml b/java/management/client/build.xml index aa215bbc24..4e595c69bf 100644 --- a/java/management/client/build.xml +++ b/java/management/client/build.xml @@ -20,22 +20,22 @@ --> - + + + - - - + + + - - @@ -46,38 +46,29 @@ - - - + - - - - - + - - - - - - - + + + + - - + + - + @@ -89,45 +80,69 @@ - - - + + + - - - - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + - - - - - + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/management/client/src/main/java/muse.xml b/java/management/client/src/main/java/muse.xml index aa1ece3404..cf4ec4000a 100644 --- a/java/management/client/src/main/java/muse.xml +++ b/java/management/client/src/main/java/muse.xml @@ -12,6 +12,10 @@ java.util.Map org.apache.qpid.management.wsdm.muse.serializer.MapSerializer + + java.util.HashMap + org.apache.qpid.management.wsdm.muse.serializer.MapSerializer + java.util.UUID org.apache.qpid.management.wsdm.muse.serializer.UUIDSerializer @@ -20,11 +24,15 @@ org.apache.qpid.management.wsdm.capabilities.Result org.apache.qpid.management.wsdm.muse.serializer.InvocationResultSerializer + + java.util.Date + org.apache.qpid.management.wsdm.muse.serializer.DateSerializer + org.apache.muse.core.routing.SimpleResourceRouter log/muse.log - FINE + SEVERE org.apache.muse.core.routing.RouterFilePersistence diff --git a/java/management/client/src/main/java/org/apache/qpid/management/Messages.java b/java/management/client/src/main/java/org/apache/qpid/management/Messages.java index 6acc83cd1a..c0b43d0c29 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/Messages.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/Messages.java @@ -108,6 +108,8 @@ public interface Messages String QMAN_200040_WS_ARTIFACTS_CACHED = " : WS Artifacts has been stored on cache with the following id : %s"; String QMAN_200041_INCOMING_OBJECT_NAME_AND_DERIVED_KEY = " : Incoming object name : %s, derived search key : %s"; String QMAN_200042_REMOVING_RESOURCE = " : WS-Resource %s is going to be removed"; + String QMAN_200043_GENERATED_ACCESSOR_METHOD = " : Generated accessor method for %s : %s"; + String QMAN_200044_GENERATED_METHOD = " : Generated method for %s : %s"; // WARNING String QMAN_300001_MESSAGE_DISCARDED = " : No handler has been configured for processing messages with \"%s\" as opcode. Message will be discarded."; @@ -150,4 +152,10 @@ public interface Messages String QMAN_100032_WS_RESOURCE_NOT_YET_INITIALIZED = " : Bad request has been received on this WS-Resource : Shutdown is not possible because the resource hasn't yet been initialized."; String QMAN_100033_WS_RESOURCE_ALREADY_SHUTDOWN = " : Bad request has been received on this WS-Resource : Shutdown is not possible because the resource has already been shutdown."; String QMAN_100034_WSDL_SCHEMA_SECTION_NOT_FOUND = " : Unable to get via XPath the schema section in WSDL."; + String QMAN_100035_RESOURCE_CAPABILITY_INVOCATION_FAILURE = " : Resource thrown a failure while invoking a capability operation."; + + // NEW + String QMAN_100035_GET_ATTRIBUTE_FAILURE = " : Get Attribute invocation failure for attribute %s, resource %s."; + String QMAN_100036_SET_ATTRIBUTE_FAILURE = " : Set Attribute invocation failure for attribute %s, resource %s."; + String QMAN_100037_INVOKE_OPERATION_FAILURE = " : Operation Invocation failure for operation."; } \ No newline at end of file diff --git a/java/management/client/src/main/java/org/apache/qpid/management/Names.java b/java/management/client/src/main/java/org/apache/qpid/management/Names.java index db3cdf7abe..4b723ee5fe 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/Names.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/Names.java @@ -141,5 +141,6 @@ public abstract class Names public final static String TYPE = "type"; public final static String XSI_TYPE = "xsi:"+TYPE; - public final static String ADAPTER_PORT= "qman.port"; + public final static String ADAPTER_HOST_PROPERTY_NAME = "qman.host"; + public final static String ADAPTER_PORT_PROPERTY_NAME = "qman.port"; } \ No newline at end of file diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InvocationResult.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InvocationResult.java index 6dd213aa8c..019fce5a50 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InvocationResult.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InvocationResult.java @@ -36,7 +36,7 @@ import org.apache.qpid.management.domain.services.MethodInvocationException; public class InvocationResult implements Serializable { private static final long serialVersionUID = 2062662997326399693L; - + private final long _returnCode; private final String _statusText; private final byte [] _outputAndBidirectionalArgumentValues; diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObject.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObject.java new file mode 100644 index 0000000000..4026f6102b --- /dev/null +++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObject.java @@ -0,0 +1,307 @@ +/* + * + * 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.management.domain.handler.impl; + +import java.net.URI; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.management.domain.services.MethodInvocationException; + +/** + * This is a sample entity used on QMan test case. + * + * @author Andrea Gazzarini + */ +public class QpidDomainObject implements QpidDomainObjectMBean +{ + private UUID _vhostRef; + private String _name; + private Boolean _durable; + private Map _arguments; + private Long _msgTotalEnqueues; + private Integer _consumerCount; + private Short _mgmtPubInterval; + private Date _expireTime; + private String _type; + + /** + * Builds a new QpidDomainObject with default values for + * its properties. + */ + public QpidDomainObject() + { + _vhostRef = UUID.randomUUID(); + _name = "Initial Name"; + _durable = Boolean.TRUE; + _arguments = new HashMap(); + _arguments.put("Key1", "aStringValue"); + _arguments.put("Key2", Long.MIN_VALUE); + _arguments.put("Key3", Integer.MAX_VALUE); + _arguments.put("Key4", Double.MIN_VALUE); + _arguments.put("Key4", Float.MAX_VALUE); + + _msgTotalEnqueues = Long.MAX_VALUE-10; + _consumerCount = Integer.MIN_VALUE+10; + _mgmtPubInterval = Short.MAX_VALUE; + _expireTime = new Date(Long.MAX_VALUE); + } + + /** + * A method that is throwing an exception, everytime. + * + * @throws Exception each time the method is called. + */ + public void throwsException() throws Exception + { + throw new MethodInvocationException(-1,"KO"); + } + + /** + * Sample echo method that return an empty result object. + * That is, an object with only status code / text valorized + * (no output parameters). + * + * @return an empty result object. + */ + public InvocationResult voidWithoutArguments() + { + return new InvocationResult(0,"OK,null",null); + } + + /** + * Echo method that accepts and returns primitive type arrays. + * + * @param longs an array of long. + * @param booleans an array of boolean. + * @param doubles an array of double. + * @param floats an array of float. + * @param integers an array of int. + * @param shorts an array of short. + * @return a result object with the same input parameters (as output parameters). + */ + public InvocationResult echoWithSimpleTypeArrays( + long [] longs, + boolean [] booleans, + double [] doubles, + float [] floats, + int [] integers, + short [] shorts) + { + InvocationResult result = new InvocationResult(0,"OK",null); + Map outputParameters = new HashMap(); + outputParameters.put(long.class.getName(), longs); + outputParameters.put(boolean.class.getName(), booleans); + outputParameters.put(double.class.getName(), doubles); + outputParameters.put(float.class.getName(), floats); + outputParameters.put(int.class.getName(), integers); + outputParameters.put(short.class.getName(), shorts); + result.setOutputSection(outputParameters); + return result; + } + + /** + * Echo method that accepts and returns wrapper types. + * + * @param aLong a java.lang.Long + * @param aBoolean a java.lang.Boolean + * @param aDouble a java.lang.Double + * @param aFloat a java.lang.Float + * @param anInteger a java.lang.Integer + * @param aShort a java.lang.Short + * @param aString a java.lang.String + * @param anURI a java.net.URI + * @param aDate a java.util.Date + * @return a result object with the same given parameters (as output parameters) + */ + public InvocationResult echoWithSimpleTypes( + Long aLong, + Boolean aBoolean, + Double aDouble, + Float aFloat, + Integer anInteger, + Short aShort, + String aString, + URI anURI, + Date aDate) + { + InvocationResult result = new InvocationResult(0,"OK",null); + Map outputParameters = new HashMap(); + outputParameters.put("p1", aLong); + outputParameters.put("p2", aBoolean); + outputParameters.put("p3", aDouble); + outputParameters.put("p4", aFloat); + outputParameters.put("p5", anInteger); + outputParameters.put("p6", aShort); + outputParameters.put("p7", aString); + outputParameters.put("p8", anURI); + outputParameters.put("p9", aDate); + result.setOutputSection(outputParameters); + return result; + } + + /** + * Echo method that accepts and returns wrapper type arrays . + * + * @param longs an array of java.lang.Long + * @param booleans an array of java.lang.Boolean + * @param doubles an array of java.lang.Double + * @param floats an array of java.lang.Float + * @param integers an array of java.lang.Integer + * @param shorts an array of java.lang.Short + * @param strings an array of java.lang.String + * @param uris an array of java.net.URI + * @param dates an array of java.util.Date + * @return a result object with the same input parameters (as output parameters). + */ + public InvocationResult echoWithArrays( + Long [] longs, + Boolean [] booleans, + Double [] doubles, + Float [] floats, + Integer [] integers, + Short [] shorts, + String [] strings, + URI [] uris, + Date [] dates) + { + InvocationResult result = new InvocationResult(0,"OK",null); + Map outputParameters = new HashMap(); + outputParameters.put(Long.class.getName(), longs); + outputParameters.put(Boolean.class.getName(), booleans); + outputParameters.put(Double.class.getName(), doubles); + outputParameters.put(Float.class.getName(), floats); + outputParameters.put(Integer.class.getName(), integers); + outputParameters.put(Short.class.getName(), shorts); + outputParameters.put(String.class.getName(), strings); + outputParameters.put(URI.class.getName(), uris); + outputParameters.put(Date.class.getName(), dates); + result.setOutputSection(outputParameters); + return result; + } + + /** + * Echo method that accepts and returns a byte array. + * + * @param byteArray a byte array + * @return a result containing the input byte array (as output parameter) + */ + public InvocationResult echoWithByteArray(byte [] byteArray) + { + InvocationResult result = new InvocationResult(0,"OK",null); + Map outputParameters = new HashMap(); + outputParameters.put(byte[].class.getName(),byteArray); + result.setOutputSection(outputParameters); + return result; + } + + /** + * Echo method that accepts and returns an UUID. + * + * @param uuid a java.util.UUID. + * @return a result containing the input UUID (as output parameter) + */ + public InvocationResult echoWithUUID(UUID uuid) + { + InvocationResult result = new InvocationResult(0,"OK",null); + Map outputParameters = new HashMap(); + outputParameters.put("uuid",uuid); + result.setOutputSection(outputParameters); + return result; + } + + /** + * Echo method that accepts and returns a Map. + * + * @param map a java.util.Map. + * @return a result containing the input Map (as output parameter) + */ + public InvocationResult echoWithMap(Map map) + { + InvocationResult result = new InvocationResult(0,"OK",null); + Map outputParameters = new HashMap(); + outputParameters.put("map",map); + result.setOutputSection(outputParameters); + return result; + } + + public UUID getVhostRef() + { + return _vhostRef; + } + + public String getName() + { + return _name; + } + + public Boolean getDurable() + { + return _durable; + } + + public Map getArguments() + { + return _arguments; + } + + public Long getMsgTotalEnqueues() + { + return _msgTotalEnqueues; + } + + public Integer getConsumerCount() + { + return _consumerCount; + } + + public Date getExpireTime() + { + return _expireTime; + } + + public Short getMgmtPubInterval() + { + return _mgmtPubInterval; + } + + public void setExpireTime(Date expireTime) + { + this._expireTime = expireTime; + } + + public void setMgmtPubInterval(Short value) + { + this._mgmtPubInterval = value; + } + + public void setType(String type) + { + this._type = type; + } + + public String getType() + { + return _type; + } +} \ No newline at end of file diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObjectMBean.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObjectMBean.java new file mode 100644 index 0000000000..8a383505c7 --- /dev/null +++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObjectMBean.java @@ -0,0 +1,227 @@ +/* + * + * 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.management.domain.handler.impl; + +import java.net.URI; +import java.util.Date; +import java.util.Map; +import java.util.UUID; + +/** + * Management interface for Qpid domain object. + * + * @author Andrea Gazzarini + */ +public interface QpidDomainObjectMBean +{ + /** + * A method that is throwing an exception, everytime. + * + * @throws Exception each time the method is called. + */ + void throwsException() throws Exception; + + /** + * Sample echo method that return an empty result object. + * That is, an object with only status code / text valorized + * (no output parameters). + * + * @return an empty result object. + */ + InvocationResult voidWithoutArguments(); + + /** + * Echo method that accepts and returns wrapper types. + * + * @param aLong a java.lang.Long + * @param aBoolean a java.lang.Boolean + * @param aDouble a java.lang.Double + * @param aFloat a java.lang.Float + * @param anInteger a java.lang.Integer + * @param aShort a java.lang.Short + * @param aString a java.lang.String + * @param anURI a java.net.URI + * @param aDate a java.util.Date + * @return a result object with the same given parameters (as output parameters) + */ + InvocationResult echoWithSimpleTypes( + Long aLong, + Boolean aBoolean, + Double aDouble, + Float aFloat, + Integer anInteger, + Short aShort, + String aString, + URI anURI, + Date aDate); + + /** + * Echo method that accepts and returns wrapper type arrays . + * + * @param longs an array of java.lang.Long + * @param booleans an array of java.lang.Boolean + * @param doubles an array of java.lang.Double + * @param floats an array of java.lang.Float + * @param integers an array of java.lang.Integer + * @param shorts an array of java.lang.Short + * @param strings an array of java.lang.String + * @param uris an array of java.net.URI + * @param dates an array of java.util.Date + * @return a result object with the same input parameters (as output parameters). + */ + InvocationResult echoWithArrays( + Long [] longs, + Boolean [] booleans, + Double [] doubles, + Float [] floats, + Integer [] integers, + Short [] shorts, + String [] strings, + URI [] uris, + Date [] dates); + + /** + * Echo method that accepts and returns primitive type arrays. + * + * @param longs an array of long. + * @param booleans an array of boolean. + * @param doubles an array of double. + * @param floats an array of float. + * @param integers an array of int. + * @param shorts an array of short. + * @return a result object with the same input parameters (as output parameters). + */ + InvocationResult echoWithSimpleTypeArrays( + long [] longs, + boolean [] booleans, + double [] doubles, + float [] floats, + int [] integers, + short [] shorts); + + /** + * Echo method that accepts and returns a byte array. + * + * @param byteArray a byte array + * @return a result containing the input byte array (as output parameter) + */ + InvocationResult echoWithByteArray(byte [] byteArray); + + /** + * Echo method that accepts and returns an UUID. + * + * @param uuid a java.util.UUID. + * @return a result containing the input UUID (as output parameter) + */ + InvocationResult echoWithUUID(UUID uuid); + + /** + * Echo method that accepts and returns a Map. + * + * @param map a java.util.Map. + * @return a result containing the input Map (as output parameter) + */ + InvocationResult echoWithMap(Map map); + + /** + * Returns the VHostRef property value. + * + * @return the VHostRef property value. + */ + UUID getVhostRef(); + + /** + * Returns the name property value. + * + * @return the name property value. + */ + String getName(); + + /** + * Returns the durable property value. + * + * @return the durable property value. + */ + Boolean getDurable(); + + /** + * Returns the arguments property value. + * + * @return the arguments property value. + */ + Map getArguments(); + + /** + * Returns the msgTotalEnqueues property value. + * + * @return the msgTotalEnqueues property value. + */ + Long getMsgTotalEnqueues(); + + /** + * Returns the consumerCount property value. + * + * @return the consumerCount property value. + */ + Integer getConsumerCount(); + + /** + * Returns the mgmtPubInterval property value. + * + * @return the mgmtPubInterval property value. + */ + Short getMgmtPubInterval(); + + /** + * Sets the mgmtPubInterval property value. + * + * @param the mgmtPubInterval property value. + */ + void setMgmtPubInterval(Short mgmtPubInterval); + + /** + * Returns the expireTime property value. + * + * @return the expireTime property value. + */ + Date getExpireTime(); + + /** + * Sets the expireTime property value. + * + * @return the expireTime property value. + */ + void setExpireTime(Date expireTime); + + /** + * Returns the type property value. + * + * @return the type property value. + */ + void setType(String type); + + /** + * Sets the type property value. + * + * @return the type property value. + */ + String getType(); +} \ No newline at end of file diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidClass.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidClass.java index 359b276081..40868752fe 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidClass.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidClass.java @@ -368,7 +368,6 @@ class QpidClass extends QpidEntity implements QpidClassMBean OperationHasBeenInvokedNotification notification = null; try { - // TODO : Overloaded methods QpidMethod method = _methods.get(actionName); if (method != null) { @@ -384,12 +383,14 @@ class QpidClass extends QpidEntity implements QpidClassMBean notification = new OperationHasBeenInvokedNotification(actionName,params,signature,exception); throw exception; } - } else { + } else + { ReflectionException exception = new ReflectionException(new NoSuchMethodException(actionName)); notification = new OperationHasBeenInvokedNotification(actionName,params,signature,exception); throw exception; } - }finally { + } finally + { sendNotification(notification); } } diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmu.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmu.java new file mode 100644 index 0000000000..2067bc9164 --- /dev/null +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmu.java @@ -0,0 +1,124 @@ +/* + * + * 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.management.wsdm; + +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.NotificationBroadcasterSupport; +import javax.management.ObjectName; + +import org.apache.qpid.management.Names; +import org.apache.qpid.management.domain.handler.impl.QpidDomainObject; +import org.apache.qpid.management.domain.handler.impl.QpidDomainObjectMBean; +import org.apache.qpid.management.jmx.EntityLifecycleNotification; + +/** + * QEmu is basically an instance creator that is installed separately + * as part of QMan test cases & examples. + * Reason for that is to emulate object creation (queues, exchanges, etc...) without having Qpid broker + * connected and therefore controlling the total number of the instances that are created. + * + * @author Andrea Gazzarini + */ +public class QEmu extends NotificationBroadcasterSupport implements QEmuMBean, MBeanRegistration{ + + private MBeanServer _mxServer; + private final static String PACKAGE_NAME= "org.apache.qpid"; + private final static String QUEUE = "queue"; + + /** + * Unregisters a Queue MBean with MBeanServer. + * + * @param objectName the name of the MBean that must unregistered. + * @throws Exception when the creation or the registration fails. + */ + public void unregister(ObjectName objectName) throws Exception + { + _mxServer.unregisterMBean(objectName); + sendNotification(EntityLifecycleNotification.INSTANCE_REMOVED,objectName); + } + + /** + * Creates and registers a Queue MBean with MBeanServer. + * + * @param objectName the name of the queue MBean. + * @throws Exception when the creation or the registration fails. + */ + public void createQueue(ObjectName objectName) throws Exception + { + QpidDomainObjectMBean queue = new QpidDomainObject(); + _mxServer.registerMBean(queue, objectName); + + sendNotification(EntityLifecycleNotification.INSTANCE_ADDED,objectName); + } + + /** + * Sends a notification about a lifecycle event of the mbean associated + * with the given object. + * + * @param type the event (notification) type. + * @param name the name of the event source. + */ + private void sendNotification(String type,ObjectName name) + { + sendNotification( + new EntityLifecycleNotification( + type, + PACKAGE_NAME, + QUEUE, + Names.CLASS, + name)); + } + + /** + * Not implemented for this class. + */ + public void postDeregister() + { + // N.A. + } + + /** + * Not implemented for this class. + */ + public void postRegister(Boolean registrationDone) + { + // N.A. + } + + /** + * Not implemented for this class. + */ + public void preDeregister() + { + // N.A. + } + + /** + * MBean server callback. + * Stores the value of the owner MBeanServer. + */ + public ObjectName preRegister(MBeanServer server, ObjectName name) + { + this._mxServer = server; + return name; + } +} \ No newline at end of file diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuInitializer.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuInitializer.java new file mode 100644 index 0000000000..9a0e2c3955 --- /dev/null +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuInitializer.java @@ -0,0 +1,92 @@ +/* + * + * 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.management.wsdm; + +import java.lang.management.ManagementFactory; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.qpid.management.Messages; +import org.apache.qpid.management.Names; +import org.apache.qpid.transport.util.Logger; + +/** + * QPid Emulator Initializer. + * This component is basically responsible to create and initialize an emulator module used + * for simulate object instances creation. + * + * @author Andrea Gazzarini + */ +public class QEmuInitializer extends HttpServlet +{ + private static final long serialVersionUID = 6149614872902682208L; + private final static Logger LOGGER = Logger.get(QEmuInitializer.class); + + /** + * QEmu initialization method. + * + * @throws ServletException when the module cannot be initialized. + */ + public void init() throws ServletException + { + try + { + ManagementFactory.getPlatformMBeanServer().registerMBean( + new QEmu(), + Names.QPID_EMULATOR_OBJECT_NAME); + } catch(Exception exception) + { + LOGGER.warn(exception,Messages.QMAN_300005_QEMU_INITIALIZATION_FAILURE); + throw new ServletException(exception); + } + } + + /** + * This is a startup module only so an override of the default servlet + * behaviour must be done in order to prevent incoming http requests processing. + * + * @param request the http request. + * @param response the http response. + * @throws ServletException each time this method is called. + */ + @Override + public void service(HttpServletRequest request,HttpServletResponse response) throws ServletException + { + throw new ServletException(); + } + + /** + * Unregister QPid emulator. + */ + public void destroy() + { + try + { + ManagementFactory.getPlatformMBeanServer() + .unregisterMBean(Names.QPID_EMULATOR_OBJECT_NAME); + } catch (Exception exception) + { + } + } +} \ No newline at end of file diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuMBean.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuMBean.java new file mode 100644 index 0000000000..f22e7ff12d --- /dev/null +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuMBean.java @@ -0,0 +1,48 @@ +/* + * + * 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.management.wsdm; + +import javax.management.ObjectName; + +/** + * Management interface for QEmu. + * + * @author Andrea Gazzarini + * @see QEmu + */ +public interface QEmuMBean +{ + /** + * Creates and registers a Queue MBean with MBeanServer. + * + * @param objectName the name of the queue MBean. + * @throws Exception when the creation or the registration fails. + */ + void createQueue(ObjectName name) throws Exception; + + /** + * Unregisters a Queue MBean with MBeanServer. + * + * @param objectName the name of the MBean that must unregistered. + * @throws Exception when the creation or the registration fails. + */ + void unregister(ObjectName name) throws Exception; +} \ No newline at end of file diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/DummyCapabilityBuilder.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/DummyCapabilityBuilder.java new file mode 100644 index 0000000000..0676b4ac49 --- /dev/null +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/DummyCapabilityBuilder.java @@ -0,0 +1,61 @@ +/* + * + * 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.management.wsdm.capabilities; + +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanOperationInfo; +import javax.management.ObjectName; + +import org.apache.muse.core.Environment; + +/** + * Dummy capability builder used for avoid duplicated builds for the + * same class. + * + * @author Andrea Gazzarini + */ +public class DummyCapabilityBuilder implements IArtifactBuilder +{ + + public void begin(ObjectName objectName) throws BuilderException + { + } + + public void endAttributes() throws BuilderException + { + } + + public void endOperations() throws BuilderException + { + } + + public void onAttribute(MBeanAttributeInfo attributeMetadata) throws BuilderException + { + } + + public void onOperation(MBeanOperationInfo operationMetadata) throws BuilderException + { + } + + public void setEnvironment(Environment environment) + { + } +} \ No newline at end of file diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapability.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapability.java index 1942e8809e..312315cdf1 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapability.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapability.java @@ -21,7 +21,6 @@ package org.apache.qpid.management.wsdm.capabilities; import java.lang.management.ManagementFactory; -import java.lang.reflect.Array; import javax.management.Attribute; import javax.management.AttributeNotFoundException; @@ -29,25 +28,16 @@ import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.MBeanServer; import javax.management.ObjectName; -import javax.xml.namespace.QName; -import org.apache.muse.core.serializer.Serializer; -import org.apache.muse.core.serializer.SerializerRegistry; -import org.apache.muse.util.ReflectUtils; -import org.apache.muse.util.xml.XmlUtils; -import org.apache.muse.ws.addressing.soap.SoapFault; -import org.apache.muse.ws.resource.basefaults.BaseFault; -import org.apache.muse.ws.resource.basefaults.WsbfUtils; import org.apache.muse.ws.resource.impl.AbstractWsResourceCapability; -import org.apache.muse.ws.resource.properties.ResourcePropertyCollection; +import org.apache.qpid.management.Messages; import org.apache.qpid.management.domain.handler.impl.InvocationResult; import org.apache.qpid.management.domain.services.MethodInvocationException; import org.apache.qpid.management.wsdm.common.EntityInstanceNotFoundFault; import org.apache.qpid.management.wsdm.common.MethodInvocationFault; import org.apache.qpid.management.wsdm.common.NoSuchAttributeFault; import org.apache.qpid.management.wsdm.common.QManFault; -import org.apache.qpid.management.wsdm.muse.serializer.ByteArraySerializer; -import org.w3c.dom.Element; +import org.apache.qpid.transport.util.Logger; /** * Abstract capability used for centralize common behaviour of the QMan @@ -57,11 +47,11 @@ import org.w3c.dom.Element; */ public abstract class MBeanCapability extends AbstractWsResourceCapability { - private static final Element[] _NO_VALUES = new Element[0]; + private static final Logger LOGGER = Logger.get(MBeanCapability.class); protected final MBeanServer _mxServer; protected ObjectName _objectName; - + /** * Builds a new capability related to the given object name. * @@ -93,7 +83,7 @@ public abstract class MBeanCapability extends AbstractWsResourceCapability * be found. * @throws QManFault in case of internal system failure. */ - Object getAttribute(String attributeName) throws QManFault + Object getAttribute(String attributeName) throws NoSuchAttributeFault,EntityInstanceNotFoundFault,QManFault { try { @@ -110,6 +100,10 @@ public abstract class MBeanCapability extends AbstractWsResourceCapability _objectName); } catch (Exception exception) { + LOGGER.error( + Messages.QMAN_100035_GET_ATTRIBUTE_FAILURE, + attributeName, + _objectName); throw new QManFault( getWsResource().getEndpointReference(), exception); @@ -134,7 +128,7 @@ public abstract class MBeanCapability extends AbstractWsResourceCapability * @throws QManFault * in case of internal system failure. */ - void setAttribute(String attributeName, Object value) throws QManFault + void setAttribute(String attributeName, Object value) throws NoSuchAttributeFault,EntityInstanceNotFoundFault,QManFault { try { @@ -151,6 +145,10 @@ public abstract class MBeanCapability extends AbstractWsResourceCapability _objectName); } catch (Exception exception) { + LOGGER.error( + Messages.QMAN_100036_SET_ATTRIBUTE_FAILURE, + attributeName, + _objectName); throw new QManFault( getWsResource().getEndpointReference(), exception); @@ -163,16 +161,31 @@ public abstract class MBeanCapability extends AbstractWsResourceCapability * @param operationName the name of the operation to be invoked. * @param params parameters used for operation invocation. * @param signature the operation / method signature. - * @throws QManFault when invocation fails. + * @throws EntityInstanceNotFoundFault + * when the target MBean doesn't exist on Management server. + * @throws MethodInvocationFault + * when the invocation of the requested operation raises an exception. + * @throws QManFault + * in case of not-well known failure. */ - Result invoke(String operationName, Object [] params, String [] signature) throws QManFault + Result invoke(String operationName, Object [] params, String [] signature) throws EntityInstanceNotFoundFault, MethodInvocationFault,QManFault { try { - InvocationResult output = (InvocationResult) _mxServer.invoke(_objectName, operationName, params, signature); - Result result = new Result(output.getReturnCode(),output.getStatusText(),output.getOutputSection()); + InvocationResult output = (InvocationResult) _mxServer + .invoke( + _objectName, + operationName, + params, + signature); + + Result result = new Result( + output.getReturnCode(), + output.getStatusText(), + output.getOutputSection()); + return result; - } catch (InstanceNotFoundException e) + } catch (InstanceNotFoundException exception) { throw new EntityInstanceNotFoundFault( getWsResource().getEndpointReference(), @@ -188,96 +201,23 @@ public abstract class MBeanCapability extends AbstractWsResourceCapability failure.getStatusText(), failure.getReturnCode()); } else { + LOGGER.error( + Messages.QMAN_100037_INVOKE_OPERATION_FAILURE, + operationName, + _objectName); throw new QManFault( getWsResource().getEndpointReference(), exception); } }catch(Exception exception) { + LOGGER.error( + Messages.QMAN_100037_INVOKE_OPERATION_FAILURE, + operationName, + _objectName); throw new QManFault( getWsResource().getEndpointReference(), exception); } } - - /** - * - * @param name - * @param value - * TODO : Vedi che poi fà co 'sto metodo che è un pò una monnezza!!! - * @return The XML representation of the resource property value(s). - * - */ - @SuppressWarnings("unchecked") - protected Element[] getPropertyElements(QName name, Object value) throws BaseFault { - // - // in this case, we have to determine if there IS a property - // and it's null, or there is no property - // - if (value == null) { - ResourcePropertyCollection props = getWsResource().getPropertyCollection(); - - // - // property is nillable - we say it exists. not 100% accurate, - // but as close as we're going to get - // - if (props.getSchema().isNillable(name)) - return new Element[] { XmlUtils.createElement(name) }; - - // - // not nillable - must not exist - // - return _NO_VALUES; - } - - // - // in all other cases, we determine the type of the property - // values and use that to serialize into XML - // - Object valuesArray = null; - Class type = null; - // TODO - if (value.getClass().isArray()) { - if (value.getClass() == byte[].class) { - Serializer serializer = new ByteArraySerializer(); - try { - return new Element[] { serializer.toXML(value, name) }; - } catch (SoapFault e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - valuesArray = value; - type = ReflectUtils.getClassFromArrayClass(value.getClass()); - } - - else { - valuesArray = new Object[] { value }; - type = value.getClass(); - } - - int length = Array.getLength(valuesArray); - Element[] properties = new Element[length]; - - SerializerRegistry registry = SerializerRegistry.getInstance(); - Serializer ser = registry.getSerializer(type); - - for (int n = 0; n < length; ++n) - { - properties[n] = serializeValue(ser, Array.get(valuesArray, n), name); - } - return properties; - } - - private Element serializeValue(Serializer ser, Object value, QName name) throws BaseFault - { - try - { - return ser.toXML(value, name); - } catch (SoapFault exception) - { - throw WsbfUtils.convertToFault(exception); - } - } } \ No newline at end of file diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilder.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilder.java index 01d8c07e55..334114f4b0 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilder.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilder.java @@ -35,14 +35,20 @@ import javax.management.ObjectName; import javax.xml.namespace.QName; import org.apache.muse.core.Environment; +import org.apache.qpid.management.Messages; import org.apache.qpid.management.Names; +import org.apache.qpid.management.wsdm.common.EntityInstanceNotFoundFault; +import org.apache.qpid.management.wsdm.common.MethodInvocationFault; +import org.apache.qpid.management.wsdm.common.NoSuchAttributeFault; import org.apache.qpid.management.wsdm.common.QManFault; +import org.apache.qpid.transport.util.Logger; public class MBeanCapabilityBuilder implements IArtifactBuilder{ private final static String GET_PROPERTY_NAMES_METHOD_COMMON_PART = "public QName[] getPropertyNames() { return "; private final static String GET_PROPERTY_NAMES_METHOD_WITH_ARRAY = GET_PROPERTY_NAMES_METHOD_COMMON_PART+" PROPERTIES;}"; private final static String GET_PROPERTY_NAMES_METHOD_WITH_EMPTY_ARRAY = GET_PROPERTY_NAMES_METHOD_COMMON_PART+" new QName[0];}"; + private final static Logger LOGGER = Logger.get(MBeanCapabilityBuilder.class); /** * Handler interface definining operation needed to be peformed (by a concrete @@ -67,7 +73,7 @@ public class MBeanCapabilityBuilder implements IArtifactBuilder{ * that is activated when this builder detects the presence of at least one property on the * capability class. */ - private final EndAttributesHandler _atLeastThereIsOneProperty = new EndAttributesHandler() { + final EndAttributesHandler _atLeastThereIsOneProperty = new EndAttributesHandler() { /** * Creates the QName array instance member and the corresponding @@ -81,7 +87,7 @@ public class MBeanCapabilityBuilder implements IArtifactBuilder{ { _properties.deleteCharAt(_properties.length()-1); _properties.append("};"); - + CtField properties = CtField.make(_properties.toString(), _capabilityClassDefinition); _capabilityClassDefinition.addField(properties); @@ -102,7 +108,7 @@ public class MBeanCapabilityBuilder implements IArtifactBuilder{ * that is activated when this builder detects that there are no properties defined for * the capability class. */ - private final EndAttributesHandler _noPropertyHasBeenDefined= new EndAttributesHandler() + final EndAttributesHandler _noPropertyHasBeenDefined= new EndAttributesHandler() { /** * Creates the getPropertyNames() that simply returns an empty QName array. @@ -124,10 +130,192 @@ public class MBeanCapabilityBuilder implements IArtifactBuilder{ } }; - private StringBuilder _properties = new StringBuilder("private static final QName[] PROPERTIES = new QName[]{ "); - private CtClass _capabilityClassDefinition; + /** + * This is the active state for this builder when the requested class has never been + * built. + */ + IArtifactBuilder _classNotAvailable = new IArtifactBuilder() + { + + /** + * Build process begins. + * The given object name is used to build a minimal definition of the product class. + * + * @param objectName the name of the JMX entity. + * @throws BuilderException when the initial definiton of the capability cannot be created. + */ + public void begin(ObjectName objectName) throws BuilderException + { + String className = objectName.getKeyProperty(Names.CLASS); + ClassPool pool = ClassPool.getDefault(); + pool.insertClassPath(new ClassClassPath(MBeanCapabilityBuilder.class)); + pool.importPackage(QName.class.getPackage().getName()); + pool.importPackage(ObjectName.class.getPackage().getName()); + pool.importPackage(QManFault.class.getPackage().getName()); + pool.importPackage(Names.class.getPackage().getName()); + pool.importPackage(Result.class.getPackage().getName()); + pool.importPackage(NoSuchAttributeFault.class.getPackage().getName()); + pool.importPackage(EntityInstanceNotFoundFault.class.getPackage().getName()); + pool.importPackage(MethodInvocationFault.class.getPackage().getName()); + + _capabilityClassDefinition = pool.makeClass("org.apache.qpid.management.wsdm.capabilities."+className); + try + { + _capabilityClassDefinition.setSuperclass(pool.get(MBeanCapability.class.getName())); + } catch(Exception exception) + { + throw new BuilderException(exception); + } + } + + public void endAttributes() throws BuilderException + { + _endAttributeHandler.endAttributes(); + } + + @SuppressWarnings("unchecked") + public void endOperations() throws BuilderException + { + try + { + _capabilityClass = _capabilityClassDefinition.toClass( + QManAdapterCapability.class.getClassLoader(), + QManAdapterCapability.class.getProtectionDomain()); + } catch (Exception exception) + { + throw new BuilderException(exception); + } + } + + /** + * Director callback. + * Attrbute metadata notification. With this callback the director informs this builder that the + * currently processed MBean has an attribute with the given metadata. + * This builder uses this information in order to add a property and the corresponding accessors + * to the capability class that is going to be built. + * + * @throws BuilderException bytecode manipulation / creation failure. + */ + public void onAttribute(MBeanAttributeInfo attribute) throws BuilderException + { + String name = attribute.getName(); + String type = attribute.getType(); + + try + { + type = Class.forName(type).getCanonicalName(); + + addPropertyMemberInstance(type, name); + + String nameForAccessors = getNameForAccessors(name); + + if (attribute.isReadable()) + { + String accessor = generateGetter(type, nameForAccessors); + CtMethod getter = CtNewMethod.make(accessor,_capabilityClassDefinition); + _capabilityClassDefinition.addMethod(getter); + appendToPropertiesArray(name); + + LOGGER.debug( + Messages.QMAN_200043_GENERATED_ACCESSOR_METHOD, + _objectName, + accessor); + } + + if (attribute.isWritable()) + { + String accessor = generateSetter(type, nameForAccessors); + CtMethod setter = CtNewMethod.make(accessor,_capabilityClassDefinition); + _capabilityClassDefinition.addMethod(setter); + + LOGGER.debug( + Messages.QMAN_200043_GENERATED_ACCESSOR_METHOD, + _objectName, + accessor); + } + } catch(Exception exception) + { + throw new BuilderException(exception); + } + } + + public void onOperation(MBeanOperationInfo operation) throws BuilderException + { + StringBuilder method = new StringBuilder(); + try + { + method + .append("public Result ") + .append(operation.getName()) + .append("( "); + + for (MBeanParameterInfo parameter: operation.getSignature()) + { + method + .append(Class.forName(parameter.getType()).getCanonicalName()) + .append(' ') + .append(parameter.getName()) + .append(','); + } + + method.deleteCharAt(method.length()-1); + method.append(") throws EntityInstanceNotFoundFault, MethodInvocationFault,QManFault { return invoke(") + .append("\"").append(operation.getName()).append("\"") + .append(", new Object[]{ "); + + for (MBeanParameterInfo parameter: operation.getSignature()) + { + method.append(parameter.getName()) + .append(','); + } + + method.deleteCharAt(method.length()-1); + method.append("}, new String[]{ "); + + for (MBeanParameterInfo parameter: operation.getSignature()) + { + method + .append("\"") + .append(parameter.getType()) + .append("\","); + } + method.deleteCharAt(method.length()-1); + method.append("}); }"); + + String methodAsString = method.toString(); + methodAsString = methodAsString.replace("new Object[]{}","null"); + methodAsString = methodAsString.replace("new String[]{}","null"); + + CtMethod definition = CtNewMethod.make(methodAsString,_capabilityClassDefinition); + _capabilityClassDefinition.addMethod(definition); + } catch(Exception exception) + { + throw new BuilderException(exception); + } finally { + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug( + Messages.QMAN_200044_GENERATED_METHOD, + _objectName, + method.toString()); + } + } + } + + public void setEnvironment(Environment environment) + { + // Nothing to do here... + } + }; + + StringBuilder _properties = new StringBuilder("private static final QName[] PROPERTIES = new QName[]{ "); private Class _capabilityClass; - private EndAttributesHandler _endAttributeHandler = _noPropertyHasBeenDefined; + CtClass _capabilityClassDefinition; + EndAttributesHandler _endAttributeHandler = _noPropertyHasBeenDefined; + + private ObjectName _objectName; + + IArtifactBuilder _state; /** * Director callback. @@ -140,31 +328,7 @@ public class MBeanCapabilityBuilder implements IArtifactBuilder{ */ public void onAttribute(MBeanAttributeInfo attribute) throws BuilderException { - String name = attribute.getName(); - String type = attribute.getType(); - type = (type.startsWith("[B")) ? " byte[] " : type; - - try - { - addPropertyMemberInstance(type, name); - - String nameForAccessors = - Character.toUpperCase(name.charAt(0)) + - name.substring(1); - - if (attribute.isReadable()) - { - generateGetter(type, nameForAccessors); - } - - if (attribute.isWritable()) - { - generateSetter(type, nameForAccessors); - } - } catch(Exception exception) - { - throw new BuilderException(exception); - } + _state.onAttribute(attribute); } /** @@ -174,25 +338,21 @@ public class MBeanCapabilityBuilder implements IArtifactBuilder{ * @param objectName the name of the target JMX entity of this capability. * @throws BuilderException when the initialization fails. */ + @SuppressWarnings("unchecked") public void begin(ObjectName objectName) throws BuilderException { - String className = objectName.getKeyProperty(Names.CLASS); - ClassPool pool = ClassPool.getDefault(); - pool.insertClassPath(new ClassClassPath(MBeanCapabilityBuilder.class)); - pool.importPackage(QName.class.getPackage().getName()); - pool.importPackage(ObjectName.class.getPackage().getName()); - pool.importPackage(QManFault.class.getPackage().getName()); - pool.importPackage(Names.class.getPackage().getName()); - pool.importPackage(Result.class.getPackage().getName()); - - _capabilityClassDefinition = pool.makeClass("org.apache.qpid.management.wsdm.capabilities."+className); - try + try { - _capabilityClassDefinition.setSuperclass(pool.get(MBeanCapability.class.getName())); - } catch(Exception exception) + this._objectName = objectName; + String className = objectName.getKeyProperty(Names.CLASS); + _capabilityClass = (Class) Class.forName("org.apache.qpid.management.wsdm.capabilities."+className); + _state = new DummyCapabilityBuilder(); + } catch (ClassNotFoundException exception) { - throw new BuilderException(exception); - } + _state = _classNotAvailable; + } + + _state.begin(objectName); } /** @@ -219,52 +379,7 @@ public class MBeanCapabilityBuilder implements IArtifactBuilder{ */ public void onOperation(MBeanOperationInfo operation) throws BuilderException { - try - { - StringBuilder method = new StringBuilder() - .append("public Result ") - .append(operation.getName()) - .append("( "); - - for (MBeanParameterInfo parameter: operation.getSignature()) - { - method - .append(parameter.getType()) - .append(' ') - .append(parameter.getName()) - .append(','); - } - - method.deleteCharAt(method.length()-1); - method.append(") throws QManFault { return invoke(") - .append("\"").append(operation.getName()).append("\"") - .append(", new Object[]{ "); - - for (MBeanParameterInfo parameter: operation.getSignature()) - { - method.append(parameter.getName()) - .append(','); - } - - method.deleteCharAt(method.length()-1); - method.append("}, new String[]{ "); - - for (MBeanParameterInfo parameter: operation.getSignature()) - { - method - .append("\"") - .append(parameter.getType()) - .append("\","); - } - method.deleteCharAt(method.length()-1); - method.append("}); }"); - - CtMethod definition = CtNewMethod.make(method.toString(),_capabilityClassDefinition); - _capabilityClassDefinition.addMethod(definition); - } catch(Exception exception) - { - throw new BuilderException(exception); - } + _state.onOperation(operation); } /** @@ -289,7 +404,7 @@ public class MBeanCapabilityBuilder implements IArtifactBuilder{ */ public void endAttributes() throws BuilderException { - _endAttributeHandler.endAttributes(); + _state.endAttributes(); } /** @@ -303,15 +418,7 @@ public class MBeanCapabilityBuilder implements IArtifactBuilder{ @SuppressWarnings("unchecked") public void endOperations() throws BuilderException { - try - { - _capabilityClass = _capabilityClassDefinition.toClass( - QManAdapterCapability.class.getClassLoader(), - QManAdapterCapability.class.getProtectionDomain()); - } catch (Exception exception) - { - throw new BuilderException(exception); - } + _state.endOperations(); } /** @@ -321,7 +428,7 @@ public class MBeanCapabilityBuilder implements IArtifactBuilder{ */ public void setEnvironment(Environment environment) { - // N.A. + // Nothing to do here... } /** @@ -329,24 +436,22 @@ public class MBeanCapabilityBuilder implements IArtifactBuilder{ * * @param type the type of the property. * @param name the name of the property. - * @throws CannotCompileException compilation failure while adding the new feature. + * @return the getter method (as a string). */ - private void generateGetter(String type, String name) throws CannotCompileException + String generateGetter(String type, String name) { - StringBuilder buffer = new StringBuilder() + return new StringBuilder() .append("public ") .append(type) .append(' ') .append("get") .append(name) - .append("() throws QManFault { return (").append(type).append(") getAttribute(\"") + .append("() throws NoSuchAttributeFault,EntityInstanceNotFoundFault,QManFault { return (") + .append(type) + .append(") getAttribute(\"") .append(name) - .append("\"); }"); - - CtMethod getter = CtNewMethod.make(buffer.toString(),_capabilityClassDefinition); - _capabilityClassDefinition.addMethod(getter); - - appendToPropertiesArray(name); + .append("\"); }") + .toString(); } /** @@ -354,23 +459,21 @@ public class MBeanCapabilityBuilder implements IArtifactBuilder{ * * @param type the type of the property. * @param name the name of the property. - * @throws CannotCompileException compilation failure while adding the new feature. + * @return the setter method (as a string). */ - private void generateSetter(String type, String name) throws CannotCompileException + String generateSetter(String type, String name) { - StringBuilder buffer = new StringBuilder() + return new StringBuilder() .append("public void ") .append("set") .append(name) .append("(") .append(type) - .append(" newValue) throws QManFault {") + .append(" newValue) throws NoSuchAttributeFault,EntityInstanceNotFoundFault,QManFault {") .append(" setAttribute(\"") .append(name) - .append("\", newValue); }"); - - CtMethod setter = CtNewMethod.make(buffer.toString(),_capabilityClassDefinition); - _capabilityClassDefinition.addMethod(setter); + .append("\", newValue); }") + .toString(); } /** @@ -407,4 +510,20 @@ public class MBeanCapabilityBuilder implements IArtifactBuilder{ CtField field= CtField.make(buffer.toString(),_capabilityClassDefinition); _capabilityClassDefinition.addField(field); } + + /** + * Returns a name that will be used in accessor methods. + * That name will differ from the given one because the first letter will be capitalized. + * For example, if the given name is "name" the return value will be "Name". + * + * @param name the plain name of the attribute. + * @return a capitalized version of the given name to be used in accessors. + */ + String getNameForAccessors(String name) + { + return + Character.toUpperCase(name.charAt(0)) + + name.substring(1); + } + } \ No newline at end of file diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManAdapterCapability.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManAdapterCapability.java index ada995d35c..511587c372 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManAdapterCapability.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManAdapterCapability.java @@ -38,7 +38,6 @@ import org.apache.muse.core.AbstractCapability; import org.apache.muse.core.Resource; import org.apache.muse.core.ResourceManager; import org.apache.muse.core.routing.MessageHandler; -import org.apache.muse.core.routing.ReflectionMessageHandler; import org.apache.muse.core.serializer.SerializerRegistry; import org.apache.muse.ws.addressing.EndpointReference; import org.apache.muse.ws.addressing.soap.SoapFault; @@ -293,7 +292,7 @@ public class QManAdapterCapability extends AbstractCapability QName returnValueName = new QName(Names.NAMESPACE_URI,name+"Response",Names.PREFIX); String actionURI = Names.NAMESPACE_URI+"/"+name; - MessageHandler handler = new ReflectionMessageHandler(actionURI, requestName, returnValueName); + MessageHandler handler = new QManMessageHandler(actionURI, requestName, returnValueName); handler.setMethod(method); handlers.add(handler); } diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManMessageHandler.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManMessageHandler.java new file mode 100644 index 0000000000..150a7d1905 --- /dev/null +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManMessageHandler.java @@ -0,0 +1,103 @@ +/* + * + * 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.management.wsdm.capabilities; + +import java.lang.reflect.Method; + +import javax.xml.namespace.QName; + +import org.apache.muse.core.routing.ReflectionMessageHandler; +import org.apache.muse.core.serializer.Serializer; +import org.apache.muse.core.serializer.SerializerRegistry; +import org.apache.muse.util.xml.XmlUtils; +import org.apache.muse.ws.addressing.soap.SoapFault; +import org.apache.qpid.management.wsdm.muse.serializer.ByteArraySerializer; +import org.w3c.dom.Element; + +/** + * A custom implementation of Muse message handler to properly deal with + * byte arrays. + * + * @author Andrea Gazzarini + */ +public class QManMessageHandler extends ReflectionMessageHandler +{ + + /** + * Builds a new message handler with the given arguments. + * + * @param actionURI the action URI. + * @param requestQName the qname of the incoming request. + * @param returnValueName the qname of the result value. + */ + public QManMessageHandler(String actionURI, QName requestQName, + QName returnValueName) + { + super(actionURI, requestQName, returnValueName); + } + + /** + * Transforms the given xml element in the corresponding + * object representation. + * + * @throws SoapFaul when unmarshal operation fails. + */ + public Object[] fromXML(Element xml) throws SoapFault + { + Method method = getMethod(); + + if (xml == null ) + { + return EMPTY_REQUEST; + } + + Class[] parameters = method.getParameterTypes(); + Object[] objects = new Object[parameters.length]; + + Element[] elements = XmlUtils.getAllElements(xml); + + if (parameters.length == 1 && elements.length == 0) + { + elements = new Element[]{ xml }; + } + + if (elements.length != parameters.length) + { + throw new SoapFault("IncorrectParams"); + } + + SerializerRegistry registry = SerializerRegistry.getInstance(); + + for (int i = 0; i < elements.length; ++i) + { + Class clazz = parameters[i]; + if (clazz == byte[].class) + { + objects[i] = new ByteArraySerializer().fromXML(elements[i]); + } else + { + Serializer ser = registry.getSerializer(parameters[i]); + objects[i] = ser.fromXML(elements[i]); + } + } + return objects; + } +} \ No newline at end of file diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilder.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilder.java index 1bde65180d..86aba0e5bb 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilder.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilder.java @@ -31,7 +31,7 @@ import org.apache.muse.core.Environment; import org.apache.muse.util.xml.XmlUtils; import org.apache.muse.ws.resource.metadata.WsrmdConstants; import org.apache.qpid.management.Names; -import org.apache.qpid.qman.debug.XmlDebugger; +import org.apache.qpid.qman.debug.WsdlDebugger; import org.w3c.dom.Element; /** @@ -45,7 +45,7 @@ class RmdBuilder implements IArtifactBuilder { private List _metadataDescriptor = new ArrayList(); - private ObjectName _objectName; + ObjectName _objectName; /** * Nothing to be done here on this builder. @@ -96,7 +96,7 @@ class RmdBuilder implements IArtifactBuilder : Names.READ_ONLY); property.setAttribute(Names.MUTABILITY,Names.MUTABLE); - XmlDebugger.debug(_objectName, property); + WsdlDebugger.debug(_objectName, property); _metadataDescriptor.add(property); } diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifacts.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifacts.java index b8a4f7766f..ac4636b9c9 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifacts.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifacts.java @@ -23,12 +23,32 @@ package org.apache.qpid.management.wsdm.capabilities; import org.w3c.dom.Document; import org.w3c.dom.Element; +/** + * Web Service Artifacts. + * Basically it acts as a container for all artifacts built when a new WS-Resource is created. + * With WS artifacts we mean : + * + *
    + *
  • Capability class (which encapsulate the WS-DM capability concern)
  • + *
  • WS Resource Metadata Descriptor (RMD)
  • + *
  • Web Service Description (WSDL)
  • + *
+ * + * @author Andrea Gazzarini + */ class WsArtifacts { private final Class_capabilityClass; private final Element[] _resourceMetadataDescriptor; private final Document _wsdl; - + + /** + * Builds a new artifacts container with the given artifacts. + * + * @param capabilityClass the capability class. + * @param resourceMetadataDescriptor the resource metadata descriptor. + * @param wsdl the wsdl. + */ public WsArtifacts( Class capabilityClass, Element[] resourceMetadataDescriptor, @@ -39,17 +59,34 @@ class WsArtifacts { this._wsdl = wsdl; } - public Class getCapabilityClass() + /** + * Returns the capability class. + * + * @return the capability class. + */ + Class getCapabilityClass() { return _capabilityClass; } - public Element[] getResourceMetadataDescriptor() + /** + * Returns the resource metadata descriptor. + * It is not a whole document but each property metadata is described in a + * separated element so the returned object is an array of elements. + * + * @return the resource metadata descriptor. + */ + Element[] getResourceMetadataDescriptor() { return _resourceMetadataDescriptor; } - public Document getWsdl() + /** + * Returns the web service description. + * + * @return the web service description (WSDL). + */ + Document getWsdl() { return _wsdl; } diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifactsFactory.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifactsFactory.java index 0209ddb55e..2a1bf059c3 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifactsFactory.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifactsFactory.java @@ -85,7 +85,8 @@ class WsArtifactsFactory LOGGER.debug( Messages.QMAN_200041_INCOMING_OBJECT_NAME_AND_DERIVED_KEY, - objectName,searchKey); + objectName, + searchKey); result = _cache.get(searchKey); if (result == null) diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsdlBuilder.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsdlBuilder.java index a9aa845f3d..bc0e4da4fd 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsdlBuilder.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsdlBuilder.java @@ -21,26 +21,36 @@ package org.apache.qpid.management.wsdm.capabilities; import java.net.InetAddress; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; import javax.management.MBeanAttributeInfo; import javax.management.MBeanOperationInfo; import javax.management.MBeanParameterInfo; import javax.management.ObjectName; +import javax.xml.XMLConstants; import javax.xml.namespace.QName; import org.apache.muse.core.Environment; +import org.apache.muse.util.ReflectUtils; import org.apache.muse.util.xml.XmlUtils; import org.apache.muse.ws.wsdl.WsdlUtils; import org.apache.qpid.management.Messages; import org.apache.qpid.management.Names; import org.apache.qpid.management.wsdm.muse.serializer.ObjectSerializer; -import org.apache.qpid.qman.debug.XmlDebugger; +import org.apache.qpid.qman.debug.WsdlDebugger; import org.apache.qpid.transport.util.Logger; import org.apache.xpath.XPathAPI; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; - +/** + * TO BE IMPROVED USING JAXB!! + * + * @author Andrea Gazzarini + */ class WsdlBuilder implements IArtifactBuilder { private final static Logger LOGGER = Logger.get(WsdlBuilder.class); @@ -53,6 +63,10 @@ class WsdlBuilder implements IArtifactBuilder { private ObjectName _objectName; + private boolean mapTypeHasBeenDeclared; + private boolean uuidTypeHasBeenDeclared; + private Map arrayTypesAlreadyDeclared = new HashMap(); + public void onAttribute(MBeanAttributeInfo attributeMetadata) throws BuilderException { try @@ -73,14 +87,17 @@ class WsdlBuilder implements IArtifactBuilder { */ - schema.appendChild(defineSchemaFor(attributeMetadata.getType(), attributeMetadata.getName())); - + schema.appendChild(defineSchemaFor(attributeMetadata.getType(), attributeMetadata.getName())); Element wsrpProperties = (Element) XPathAPI.selectSingleNode( _document, - "/wsdl:definitions/wsdl:types/xsd:schema[@targetNamespace='http://amqp.apache.org/qpid/management/qman']/xsd:element[@name='QManWsResourceProperties']/xsd:complexType/xsd:sequence"); + "/wsdl:definitions/wsdl:types/xsd:schema[" + + "@targetNamespace='http://amqp.apache.org/qpid/management/qman']" + + "/xsd:element[@name='QManWsResourceProperties']/xsd:complexType/xsd:sequence"); - Element propertyRef= XmlUtils.createElement(_document, new QName("http://www.w3.org/2001/XMLSchema","element","xsd")); - propertyRef.setAttribute("ref", "qman:"+attributeMetadata.getName()); + Element propertyRef= XmlUtils.createElement(_document, XSD_ELEMENT_QNAME); + propertyRef.setAttribute( + "ref", + Names.PREFIX+":"+attributeMetadata.getName()); wsrpProperties.appendChild(propertyRef); @@ -90,56 +107,95 @@ class WsdlBuilder implements IArtifactBuilder { } } + private final static QName XSD_ELEMENT_QNAME = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI,"element","xsd"); + private final static QName XSD_COMPLEX_TYPE_QNAME = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI,"complexType","xsd"); + private final static QName XSD_SEQUENCE_QNAME = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI,"sequence","xsd"); + private Element defineSchemaFor(String type, String attributeName) throws Exception { if (type.equals("java.util.Map")) { - Element prop = XmlUtils.createElement(_document, new QName("http://www.w3.org/2001/XMLSchema","element","xsd")); - prop.setAttribute("name",attributeName); - - Element complexType = XmlUtils.createElement(_document, new QName("http://www.w3.org/2001/XMLSchema","complexType","xsd")); + if (!mapTypeHasBeenDeclared) + { + Element complexType = XmlUtils.createElement(_document, XSD_COMPLEX_TYPE_QNAME); + complexType.setAttribute("name","map"); + Element sequence = XmlUtils.createElement(_document, XSD_SEQUENCE_QNAME); + + Element entry = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME); + entry.setAttribute("name", "entry"); + entry.setAttribute("minOccurs", "0"); + entry.setAttribute("maxOccurs", "unbounded"); + + Element complexType2 = XmlUtils.createElement(_document, XSD_COMPLEX_TYPE_QNAME); + Element sequence2 = XmlUtils.createElement(_document, XSD_SEQUENCE_QNAME); + + Element key = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME); + key.setAttribute("name", "key"); + key.setAttribute("type", "xsd:string"); + + Element value = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME); + value.setAttribute("name", "value"); + value.setAttribute("type", "xsd:anyType"); + + sequence2.appendChild(key); + sequence2.appendChild(value); + complexType2.appendChild(sequence2); + entry.appendChild(complexType2); + sequence.appendChild(entry); + complexType.appendChild(sequence); + schema.appendChild(complexType); + mapTypeHasBeenDeclared = true; + } + Element propertyDeclaration = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME); + propertyDeclaration.setAttribute("name",attributeName); + propertyDeclaration.setAttribute("type", "qman:map"); + return propertyDeclaration; - Element sequence = XmlUtils.createElement(_document, new QName("http://www.w3.org/2001/XMLSchema","sequence","xsd")); - - Element entry = XmlUtils.createElement(_document, new QName("http://www.w3.org/2001/XMLSchema","element","xsd")); - entry.setAttribute("name", "entry"); - entry.setAttribute("minOccurs", "0"); - entry.setAttribute("maxOccurs", "unbounded"); - - Element complexType2 = XmlUtils.createElement(_document, new QName("http://www.w3.org/2001/XMLSchema","complexType","xsd")); - Element sequence2 = XmlUtils.createElement(_document, new QName("http://www.w3.org/2001/XMLSchema","sequence","xsd")); - - Element key = XmlUtils.createElement(_document, new QName("http://www.w3.org/2001/XMLSchema","element","xsd")); - key.setAttribute("name", "key"); - key.setAttribute("type", "xsd:string"); - - Element value = XmlUtils.createElement(_document, new QName("http://www.w3.org/2001/XMLSchema","element","xsd")); - value.setAttribute("name", "value"); - value.setAttribute("type", "xsd:anyType"); - - sequence2.appendChild(key); - sequence2.appendChild(value); - complexType2.appendChild(sequence2); - entry.appendChild(complexType2); - sequence.appendChild(entry); - complexType.appendChild(sequence); - prop.appendChild(complexType); - return prop; } else if ("java.util.UUID".equals(type)) { - Element prop = XmlUtils.createElement(_document, new QName("http://www.w3.org/2001/XMLSchema","element","xsd")); - prop.setAttribute("name", attributeName); - Element complexType = XmlUtils.createElement(_document, new QName("http://www.w3.org/2001/XMLSchema","complexType","xsd")); - Element sequence = XmlUtils.createElement(_document, new QName("http://www.w3.org/2001/XMLSchema","sequence","xsd")); - Element uuid = XmlUtils.createElement(_document, new QName("http://www.w3.org/2001/XMLSchema","element","xsd")); - uuid.setAttribute("name", "uuid"); - uuid.setAttribute("type", "xsd:string"); - sequence.appendChild(uuid); - complexType.appendChild(sequence); - prop.appendChild(complexType); - return prop; - } else { - Element propertyDeclaration = XmlUtils.createElement(_document, new QName("http://www.w3.org/2001/XMLSchema","element","xsd")); + if (!uuidTypeHasBeenDeclared) + { + Element complexType = XmlUtils.createElement(_document, XSD_COMPLEX_TYPE_QNAME); + complexType.setAttribute("name", "uuid"); + Element sequence = XmlUtils.createElement(_document, XSD_SEQUENCE_QNAME); + Element uuid = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME); + uuid.setAttribute("name", "uuid"); + uuid.setAttribute("type", "xsd:string"); + sequence.appendChild(uuid); + complexType.appendChild(sequence); + schema.appendChild(complexType); + uuidTypeHasBeenDeclared = true; + } + Element propertyDeclaration = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME); + propertyDeclaration.setAttribute("name",attributeName); + propertyDeclaration.setAttribute("type", "qman:uuid"); + return propertyDeclaration; + } else if (type.startsWith("[")) + { + Class arrayClass = Class.forName(type); + Class clazz = ReflectUtils.getClassFromArrayClass(arrayClass); + String arrayType = arrayClass.getSimpleName().replace("[]", "").trim(); + arrayType = Character.toUpperCase(arrayType.charAt(0))+arrayType.substring(1); + if (!arrayTypesAlreadyDeclared.containsKey(type)) + { + Element complexType = XmlUtils.createElement(_document, XSD_COMPLEX_TYPE_QNAME); + complexType.setAttribute("name", "arrayOf"+arrayType); + Element sequence = XmlUtils.createElement(_document, XSD_SEQUENCE_QNAME); + Element entry = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME); + entry.setAttribute("name", "entry"); + entry.setAttribute("type", serializer.getXmlType(clazz)); + sequence.appendChild(entry); + complexType.appendChild(sequence); + schema.appendChild(complexType); + arrayTypesAlreadyDeclared.put(type, arrayType); + } + Element propertyDeclaration = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME); + propertyDeclaration.setAttribute("name",attributeName); + propertyDeclaration.setAttribute("type", "qman:arrayOf"+arrayTypesAlreadyDeclared.get(type)); + return propertyDeclaration; + } + else { + Element propertyDeclaration = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME); propertyDeclaration.setAttribute("name",attributeName); propertyDeclaration.setAttribute("type", serializer.getXmlType(Class.forName(type))); return propertyDeclaration; @@ -158,7 +214,7 @@ class WsdlBuilder implements IArtifactBuilder { StringBuilder builder = new StringBuilder("http://") .append(InetAddress.getLocalHost().getHostName()) .append(':') - .append(System.getProperty(Names.ADAPTER_PORT,"8080")) + .append(System.getProperty(Names.ADAPTER_PORT_PROPERTY_NAME,"8080")) .append('/') .append("qman") .append('/') @@ -218,14 +274,15 @@ class WsdlBuilder implements IArtifactBuilder { statusCode.setAttribute("type", "xsd:long"); Element statusText = _document.createElement("xsd:element"); - statusCode.setAttribute("name", "statusText"); - statusCode.setAttribute("type", "xsd:string"); + statusText.setAttribute("name", "statusText"); + statusText.setAttribute("type", "xsd:string"); sequence.appendChild(statusCode); sequence.appendChild(statusText); Element outputParams = _document.createElement("xsd:complexType"); outputParams.setAttribute("name", "outputParameters"); + sequence.appendChild(outputParams); Element complexTypeOutput = _document.createElement("xsd:complexType"); Element outputSequence = _document.createElement("xsd:sequence"); @@ -243,9 +300,10 @@ class WsdlBuilder implements IArtifactBuilder { Element entryComplexType = _document.createElement("xsd:complexType"); Element entrySequence = _document.createElement("xsd:sequence"); entryComplexType.appendChild(entrySequence); + entry.appendChild(entryComplexType); Element name = _document.createElement("xsd:name"); - name.setAttribute("name", "name"); + name.setAttribute("name", "key"); name.setAttribute("type", "xsd:string"); Element value = _document.createElement("xsd:element"); @@ -324,6 +382,7 @@ class WsdlBuilder implements IArtifactBuilder { Element methodNameRequestComplexType = _document.createElement("xsd:complexType"); methodNameRequestComplexType.setAttribute("name", methodNameRequest); Element methodNameRequestComplexTypeSequence = _document.createElement("xsd:sequence"); + for(MBeanParameterInfo parameter : operationMetadata.getSignature()) { methodNameRequestComplexTypeSequence.appendChild(defineSchemaFor(parameter.getType(), parameter.getName())); @@ -340,7 +399,7 @@ class WsdlBuilder implements IArtifactBuilder { Element result = _document.createElement("xsd:element"); result.setAttribute("name", "result"); - result.setAttribute("type", "qman:invocationResult"); + result.setAttribute("type", "qman:result"); methodNameResponseSequence.appendChild(result); schema.appendChild(methodNameResponseComplexType); @@ -459,7 +518,7 @@ class WsdlBuilder implements IArtifactBuilder { public Document getWsdl() { - XmlDebugger.debug(_objectName,_document); + WsdlDebugger.debug(_objectName,_document); return _document; } diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/engine/WSDMAdapterEnvironment.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/engine/WSDMAdapterEnvironment.java index 438c1d9db9..eb72bfc744 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/engine/WSDMAdapterEnvironment.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/engine/WSDMAdapterEnvironment.java @@ -67,18 +67,11 @@ public class WSDMAdapterEnvironment extends AbstractEnvironment public String getDefaultURIPrefix() { - String host = null; - try { - host = InetAddress.getLocalHost().getHostName(); - } catch (UnknownHostException e) { - host = "localhost"; - } - return new StringBuilder() .append("http://") - .append(host) + .append(System.getProperty(Names.ADAPTER_HOST_PROPERTY_NAME,"localhost")) .append(":") - .append(System.getProperty(Names.ADAPTER_PORT)) + .append(System.getProperty(Names.ADAPTER_PORT_PROPERTY_NAME,"8080")) .append(_servletContext.getContextPath()) .append("/services/") .toString(); diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/resources/QManWsResource.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/resources/QManWsResource.java index fc5f3fc7e4..78c3aea558 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/resources/QManWsResource.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/resources/QManWsResource.java @@ -321,16 +321,6 @@ public class QManWsResource implements WsResource return _capabilitiesByURI.get(capabilityURI); } -// /** -// * Returns all the WS-Action URIs supported by this resource. -// * -// * @return all of the WS-A Action URIs supported by this resource. -// */ -// protected Collection getCapabilityActions() -// { -// return Collections.unmodifiableSet(_capabilitiesByAction.keySet()); -// } - /** * Returns a collection with all registered capability URIs. * @@ -539,6 +529,10 @@ public class QManWsResource implements WsResource } catch (Throwable throwable) { + LOGGER.error( + throwable, + Messages.QMAN_100037_INVOKE_OPERATION_FAILURE); + SoapFault response = SoapUtils.convertToFault( (throwable.getCause()!= null) ? throwable.getCause() @@ -725,15 +719,20 @@ public class QManWsResource implements WsResource for (Element element : additionalProperties) { - rmdDoc.adoptNode(element); - metadataDescriptor.appendChild(element); + +// rmdDoc.importNode(element, true); + Element adopted = (Element) rmdDoc.importNode(element,false); + metadataDescriptor.appendChild(adopted); } return new SimpleMetadataDescriptor(metadataDescriptor); } catch(Exception exception) { - LOGGER.error(exception,Messages.QMAN_100021_RMD_BUID_FAILURE,getContextPath()); + LOGGER.error( + exception, + Messages.QMAN_100021_RMD_BUID_FAILURE, + getContextPath()); throw new SoapFault(exception); } } diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/DateSerializer.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/DateSerializer.java new file mode 100644 index 0000000000..60350ccc31 --- /dev/null +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/DateSerializer.java @@ -0,0 +1,75 @@ +/* + * + * 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.management.wsdm.muse.serializer; + +import java.util.Date; + +import javax.xml.namespace.QName; + +import org.apache.muse.core.serializer.Serializer; +import org.apache.muse.util.xml.XmlUtils; +import org.apache.muse.ws.addressing.soap.SoapFault; +import org.w3c.dom.Element; + +/** + * Implementation of Muse Serializer for Date type. + * Note that Muse already ships a serializer but the formatter used on that class + * is losing precision betweem marshal / unmarshal operations. + * + * @author Andrea Gazzarini + */ +public class DateSerializer implements Serializer +{ + /** + * Return a Date representation of the given xml element. + * + * @param xml the element to unmarshal. + * @throws SoapFault when the unmarshalling fails. + */ + public Object fromXML(Element elementData) throws SoapFault + { + return new Date(Long.parseLong(elementData.getTextContent())); + } + + /** + * Returns the java type associated to this class. + * + * @return the java type associated to this class. + */ + public Class getSerializableType() + { + return Date.class; + } + + /** + * Return an xml representation of the given UUID with the given name. + * + * @param object the UUID to marshal. + * @param qname the qualified (xml) name of the object to use in xml representation. + * @return the xml representation of the UUID. + * @throws SoapFault when the marshalling fails. + */ + public Element toXML(Object obj, QName qname) throws SoapFault + { + Date date = (Date) obj; + return XmlUtils.createElement(qname, String.valueOf(date.getTime())); + } +} \ No newline at end of file diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/InvocationResultSerializer.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/InvocationResultSerializer.java index 5e208a281d..0af570eacf 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/InvocationResultSerializer.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/InvocationResultSerializer.java @@ -38,7 +38,6 @@ import org.w3c.dom.Element; */ public class InvocationResultSerializer implements Serializer { - private Serializer _longSerializer = SerializerRegistry.getInstance().getSerializer(long.class); private Serializer _stringSerializer = SerializerRegistry.getInstance().getSerializer(String.class); private Serializer _mapSerializer = SerializerRegistry.getInstance().getSerializer(Map.class); diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/MapSerializer.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/MapSerializer.java index 6a404d45b9..1d0d02c669 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/MapSerializer.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/MapSerializer.java @@ -49,7 +49,9 @@ import org.w3c.dom.Element; public class MapSerializer implements Serializer { - ByteArraySerializer byteArraySerializer = new ByteArraySerializer(); + ByteArraySerializer _byteArraySerializer = new ByteArraySerializer(); + Serializer _objectSerializer = SerializerRegistry.getInstance().getSerializer(Object.class); + Serializer _stringSerializer = SerializerRegistry.getInstance().getSerializer(String.class); /** * Return a map representation of the given xml element. @@ -70,10 +72,10 @@ public class MapSerializer implements Serializer Object value = null; for (Element element : keysAndValues) { - if (Names.KEY.equals(element.getNodeName())) + if (Names.KEY.equals(element.getLocalName())) { - key = objectDeserializer.fromXML(element); - } else if (Names.VALUE.equals(element.getNodeName())) + key = _stringSerializer.fromXML(element); + } else if (Names.VALUE.equals(element.getLocalName())) { value = objectDeserializer.fromXML(element); } @@ -103,23 +105,23 @@ public class MapSerializer implements Serializer */ public Element toXML(Object obj, QName qname) throws SoapFault { - Serializer objectSerializer = SerializerRegistry.getInstance().getSerializer(Object.class); + Map data = (Map) obj; - QName entryQName = new QName(Names.ENTRY); - QName keyQName = new QName(Names.KEY); - QName valueQName = new QName(Names.VALUE); + QName entryQName = new QName(qname.getNamespaceURI(),Names.ENTRY,qname.getPrefix()); + QName keyQName = new QName(qname.getNamespaceURI(),Names.KEY,qname.getPrefix()); + QName valueQName = new QName(qname.getNamespaceURI(),Names.VALUE,qname.getPrefix()); Element root = XmlUtils.createElement(qname); root.setAttribute("xmlns:xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI); for (Entry mapEntry: data.entrySet()) { Element entry = XmlUtils.createElement(entryQName); - entry.appendChild(objectSerializer.toXML(mapEntry.getKey(), keyQName)); + entry.appendChild(_stringSerializer.toXML(mapEntry.getKey(), keyQName)); if (mapEntry.getValue().getClass() == byte[].class) { - entry.appendChild(byteArraySerializer.toXML(mapEntry.getValue(), valueQName)); + entry.appendChild(_byteArraySerializer.toXML(mapEntry.getValue(), valueQName)); } else { - entry.appendChild(objectSerializer.toXML(mapEntry.getValue(), valueQName)); + entry.appendChild(_objectSerializer.toXML(mapEntry.getValue(), valueQName)); } root.appendChild(entry); } diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/ObjectSerializer.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/ObjectSerializer.java index 7569ace181..ff0c69cdda 100644 --- a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/ObjectSerializer.java +++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/ObjectSerializer.java @@ -24,6 +24,7 @@ import java.net.URI; import java.util.Date; import java.util.HashMap; import java.util.Map; +import java.util.UUID; import javax.xml.XMLConstants; import javax.xml.namespace.QName; @@ -47,49 +48,70 @@ public class ObjectSerializer implements Serializer private Map> xml2Java = new HashMap>(); { xml2Java.put("xsd:long", Long.class); - xml2Java.put("xsd:long", long.class); xml2Java.put("xsd:boolean",Boolean.class); - xml2Java.put("xsd:boolean",boolean.class); - xml2Java.put("xsd:double",Double.class); xml2Java.put("xsd:double",Double.class); xml2Java.put("xsd:float",Float.class); - xml2Java.put("xsd:float",float.class); xml2Java.put("xsd:integer",Integer.class); - xml2Java.put("xsd:integer",int.class); xml2Java.put("xsd:int",Integer.class); - xml2Java.put("xsd:int",int.class); xml2Java.put("xsd:short",Short.class); - xml2Java.put("xsd:short",short.class); xml2Java.put("xsd:string",String.class); xml2Java.put("xsd:anyURI",URI.class); - xml2Java.put("xsd:dateTime",URI.class); + xml2Java.put("xsd:dateTime",Date.class); xml2Java.put("xsd:QName",QName.class); xml2Java.put("xsd:element",Element.class); xml2Java.put("xsd:base64Binary",byte[].class); + xml2Java.put("qman:arrayOfLong",Long[].class); + xml2Java.put("qman:arrayOfBoolean",Boolean[].class); + xml2Java.put("qman:arrayOfDouble",Double[].class); + xml2Java.put("qman:arrayOfFloat",Float[].class); + xml2Java.put("qman:arrayOfInteger",Integer[].class); + xml2Java.put("qman:arrayOfShort",Short[].class); + xml2Java.put("qman:arrayOfString",String[].class); + xml2Java.put("qman:arrayOfURI",URI[].class); + xml2Java.put("qman:arrayOfDate",Date[].class); + xml2Java.put("qman:uuid",UUID.class); + xml2Java.put("qman:map",Map.class); + xml2Java.put("qman:map",HashMap.class); } private Map, String> java2Xml = new HashMap, String>(); - { + { + java2Xml.put(UUID.class,"qman:uuid"); java2Xml.put(Long.class,"xsd:long"); java2Xml.put(long.class,"xsd:long"); java2Xml.put(Boolean.class,"xsd:boolean"); - java2Xml.put(Boolean.class,"xsd:boolean"); - java2Xml.put(Double.class,"xsd:double"); + java2Xml.put(boolean.class,"xsd:boolean"); java2Xml.put(Double.class,"xsd:double"); + java2Xml.put(double.class,"xsd:double"); java2Xml.put(Float.class,"xsd:float"); - java2Xml.put(Float.class,"xsd:float"); - java2Xml.put(Integer.class,"xsd:integer"); + java2Xml.put(float.class,"xsd:float"); java2Xml.put(Integer.class,"xsd:integer"); - java2Xml.put(Integer.class,"xsd:int"); - java2Xml.put(Integer.class,"xsd:int"); - java2Xml.put(Short.class,"xsd:short"); + java2Xml.put(int.class,"xsd:integer"); java2Xml.put(Short.class,"xsd:short"); + java2Xml.put(short.class,"xsd:short"); java2Xml.put(String.class,"xsd:string"); java2Xml.put(URI.class,"xsd:anyURI"); java2Xml.put(Date.class,"xsd:dateTime"); java2Xml.put(QName.class,"xsd:QName"); java2Xml.put(Element.class,"xsd:element"); java2Xml.put(byte[].class,"xsd:base64Binary"); + java2Xml.put(Long[].class,"qman:arrayOfLong"); + java2Xml.put(long[].class,"qman:arrayOfLong"); + java2Xml.put(Boolean[].class,"qman:arrayOfBoolean"); + java2Xml.put(boolean[].class,"qman:arrayOfBoolean"); + java2Xml.put(Double[].class,"qman:arrayOfDouble"); + java2Xml.put(double[].class,"qman:arrayOfDouble"); + java2Xml.put(Float[].class,"qman:arrayOfFloat"); + java2Xml.put(float[].class,"qman:arrayOfFloat"); + java2Xml.put(Integer[].class,"qman:arrayOfInteger"); + java2Xml.put(int[].class,"qman:arrayOfInteger"); + java2Xml.put(Short[].class,"qman:arrayOfShort"); + java2Xml.put(short[].class,"qman:arrayOfShort"); + java2Xml.put(String[].class,"qman:arrayOfString"); + java2Xml.put(URI[].class,"qman:arrayOfURI"); + java2Xml.put(Date[].class,"qman:arrayOfDate"); + java2Xml.put(Map.class,"qman:map"); + java2Xml.put(HashMap.class,"qman:map"); } /** @@ -113,14 +135,18 @@ public class ObjectSerializer implements Serializer { throw new SoapFault( "No type attribute was found for the current element. " + - "If you are using this serializer, in order to unmarshal the opportune type the xsi:type must be specified."); + "If you are using this serializer, in order to unmarshal the" + + " opportune type the xsi:type must be specified."); } Class clazz = xml2Java.get(typeAttribute.getValue()); if (clazz == null) { - throw new SoapFault(String.format("No corresponding class was found on this serializer mappings for xsi:type %s.",typeAttribute)); + throw new SoapFault( + String.format( + "No corresponding class was found on this serializer mappings for xsi:type %s.", + typeAttribute)); } if (clazz == byte[].class) { @@ -155,7 +181,8 @@ public class ObjectSerializer implements Serializer if (clazz == byte[].class) { result = new ByteArraySerializer().toXML(obj,qname); - } else { + } + else { result = SerializerRegistry.getInstance().getSerializer(clazz).toXML(obj,qname); } result.setAttribute(Names.XSI_TYPE, java2Xml.get(clazz)); diff --git a/java/management/client/src/main/java/org/apache/qpid/qman/debug/WsdlDebugger.java b/java/management/client/src/main/java/org/apache/qpid/qman/debug/WsdlDebugger.java new file mode 100644 index 0000000000..398a69817b --- /dev/null +++ b/java/management/client/src/main/java/org/apache/qpid/qman/debug/WsdlDebugger.java @@ -0,0 +1,49 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.qman.debug; + +import javax.management.ObjectName; + +import org.apache.muse.util.xml.XmlUtils; +import org.apache.qpid.transport.util.Logger; +import org.w3c.dom.Node; + +/** + * Utility class used for debbugging WSDL documents + * + * @author Andrea Gazzarini + */ +public class WsdlDebugger { + public final static Logger LOGGER = Logger.get(WsdlDebugger.class); + + /** + * Prints out to log the given node. + * + * @param node the xml node to be printed out. + */ + public static void debug(ObjectName resourceId, Node node) + { + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug(resourceId+" : "+XmlUtils.toString(node, false,true)); + } + } +} \ No newline at end of file diff --git a/java/management/client/src/test/java/log4j.xml b/java/management/client/src/test/java/log4j.xml new file mode 100644 index 0000000000..da47cadb80 --- /dev/null +++ b/java/management/client/src/test/java/log4j.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/management/client/src/test/java/org/apache/qpid/management/TestConstants.java b/java/management/client/src/test/java/org/apache/qpid/management/TestConstants.java index 56195b6f20..d7ecd707fe 100644 --- a/java/management/client/src/test/java/org/apache/qpid/management/TestConstants.java +++ b/java/management/client/src/test/java/org/apache/qpid/management/TestConstants.java @@ -64,4 +64,7 @@ public interface TestConstants String YEARS = "years"; int SAMPLE_MIN_VALUE = 1; int SAMPLE_MAX_VALUE = 120; -} + + String DEFAULT_HOST = "localhost"; + int DEFAULT_PORT = 8080; +} \ No newline at end of file diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/EnhancedReflectionProxyHandler.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/EnhancedReflectionProxyHandler.java new file mode 100644 index 0000000000..732f110ba3 --- /dev/null +++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/EnhancedReflectionProxyHandler.java @@ -0,0 +1,67 @@ +/* + * + * 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.management.wsdm; + +import javax.xml.namespace.QName; + +import org.apache.muse.core.proxy.ReflectionProxyHandler; +import org.apache.muse.util.xml.XmlUtils; +import org.apache.muse.ws.addressing.soap.SoapFault; +import org.apache.qpid.management.wsdm.muse.serializer.ByteArraySerializer; +import org.w3c.dom.Element; + +/** + * Custom implementation of Muse ReflectionProxyHandler that uses a base64 serializer + * for byte arrays. + * + * @author Andrea Gazzarini + */ +public class EnhancedReflectionProxyHandler extends ReflectionProxyHandler +{ + @Override + protected Element serialize(Object obj, QName qname) throws SoapFault + { + if (obj == null) + { + return XmlUtils.createElement(qname); + } + + if (obj.getClass() == byte[].class) + { + return new ByteArraySerializer().toXML(obj, qname); + } else + { + return super.serialize(obj, qname); + } + } + + @Override + protected Object deserialize(Element xml, Class theClass) throws SoapFault + { + if (theClass == byte[].class) + { + return new ByteArraySerializer().fromXML(xml); + } else + { + return super.deserialize(xml, theClass); + } + } +} \ No newline at end of file diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/ServerThread.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/ServerThread.java new file mode 100644 index 0000000000..ff7d9b5a8a --- /dev/null +++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/ServerThread.java @@ -0,0 +1,82 @@ +/* + * + * 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.management.wsdm; + +import java.io.File; + +import org.apache.qpid.management.Names; +import org.mortbay.component.LifeCycle.Listener; +import org.mortbay.jetty.Connector; +import org.mortbay.jetty.Server; +import org.mortbay.jetty.nio.SelectChannelConnector; +import org.mortbay.jetty.webapp.WebAppContext; +import org.mortbay.start.Monitor; + +public class ServerThread extends Thread +{ + private final Listener _lifecycleListener; + private Server server; + ServerThread(Listener listener) + { + this._lifecycleListener = listener; + } + + @Override + public void run() + { + try + { + Monitor.monitor(); + server = new Server(); + server.setStopAtShutdown(true); + + Connector connector=new SelectChannelConnector(); + connector.setPort( + Integer.parseInt( + System.getProperty(Names.ADAPTER_PORT_PROPERTY_NAME))); + connector.setHost(System.getProperty(Names.ADAPTER_HOST_PROPERTY_NAME)); + + server.setConnectors(new Connector[]{connector}); + + WebAppContext webapp = new WebAppContext(); +// webapp.setExtractWAR(false); + webapp.setContextPath("/qman"); + webapp.setDefaultsDescriptor("/org/apache/qpid/management/wsdm/web.xml"); + + String webApplicationPath = System.getProperty("qman.war"); + File rootFolderPath = (webApplicationPath != null) ? new File(webApplicationPath) : new File("."); + + webapp.setWar(rootFolderPath.toURI().toURL().toExternalForm()); + webapp.addLifeCycleListener(_lifecycleListener); + server.setHandler(webapp); + server.start(); + server.join(); + } catch(Exception exception) + { + throw new RuntimeException(exception); + } + } + + public void shutdown() throws Exception + { + server.stop(); + } +} diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/WebApplicationLifeCycleListener.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/WebApplicationLifeCycleListener.java new file mode 100644 index 0000000000..3a0bbb608a --- /dev/null +++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/WebApplicationLifeCycleListener.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.management.wsdm; +import org.mortbay.component.LifeCycle; +import org.mortbay.component.LifeCycle.Listener; + +/** + * Adapter class used to provide an empty (base) implementation of + * Lifecycle listener interface. + * + * @author Andrea Gazzarini + */ +public class WebApplicationLifeCycleListener implements Listener +{ + public void lifeCycleFailure(LifeCycle event, Throwable cause) + { + } + + public void lifeCycleStarted(LifeCycle event) + { + } + + public void lifeCycleStarting(LifeCycle event) + { + } + + public void lifeCycleStopped(LifeCycle event) + { + } + + public void lifeCycleStopping(LifeCycle event) + { + } +} \ No newline at end of file diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/WsDmAdapterTest.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/WsDmAdapterTest.java new file mode 100644 index 0000000000..8a4434bee1 --- /dev/null +++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/WsDmAdapterTest.java @@ -0,0 +1,1026 @@ +/* + * + * 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.management.wsdm; + +import java.lang.management.ManagementFactory; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.net.URI; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.xml.namespace.QName; + +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.apache.muse.core.proxy.ProxyHandler; +import org.apache.muse.core.proxy.ReflectionProxyHandler; +import org.apache.muse.core.serializer.SerializerRegistry; +import org.apache.muse.ws.addressing.EndpointReference; +import org.apache.muse.ws.addressing.soap.SoapFault; +import org.apache.muse.ws.resource.remote.WsResourceClient; +import org.apache.muse.ws.resource.sg.remote.ServiceGroupClient; +import org.apache.qpid.management.Names; +import org.apache.qpid.management.TestConstants; +import org.apache.qpid.management.wsdm.capabilities.Result; +import org.apache.qpid.management.wsdm.muse.serializer.DateSerializer; +import org.apache.qpid.management.wsdm.muse.serializer.InvocationResultSerializer; +import org.apache.qpid.management.wsdm.muse.serializer.MapSerializer; +import org.apache.qpid.management.wsdm.muse.serializer.ObjectSerializer; +import org.apache.qpid.management.wsdm.muse.serializer.UUIDSerializer; +import org.mortbay.component.LifeCycle; +import org.mortbay.component.LifeCycle.Listener; +import org.w3c.dom.Element; + +/** + * Test case for WS-Resource lifecycle management. + * + * @author Andrea Gazzarini + */ +public class WsDmAdapterTest extends TestCase { + + private MBeanServer _managementServer; + private ObjectName _resourceObjectName; + + private WsResourceClient _resourceClient; + private MBeanInfo _mbeanInfo; + + private Map _invocationHandlers = createInvocationHandlers(); + final Long retCodeOk = new Long(0); + + /** + * Test case wide set up. + * Provides Server startup & shutdown global procedure. + * + * @author Andrea Gazzarini + */ + private static class WsDmAdapterTestSetup extends TestSetup + { + private Object _serverMonitor = new Object(); + + Listener listener = new WebApplicationLifeCycleListener() + { + public void lifeCycleStarted(LifeCycle event) + { + synchronized (_serverMonitor) + { + _serverMonitor.notify(); + } + } + }; + + private ServerThread server; + + /** + * Builds a new test setup with for the given test. + * + * @param test the decorated test. + */ + public WsDmAdapterTestSetup(Test test) + { + super(test); + } + + /** + * Starts up Web server. + * + * @throws Exception when the server startup fails. + */ + @Override + protected void setUp() throws Exception + { + SerializerRegistry.getInstance().registerSerializer(Object.class, new ObjectSerializer()); + SerializerRegistry.getInstance().registerSerializer(Date.class, new DateSerializer()); + SerializerRegistry.getInstance().registerSerializer(Map.class, new MapSerializer()); + SerializerRegistry.getInstance().registerSerializer(HashMap.class, new MapSerializer()); + SerializerRegistry.getInstance().registerSerializer(UUID.class, new UUIDSerializer()); + SerializerRegistry.getInstance().registerSerializer(Result.class, new InvocationResultSerializer()); + + System.setProperty( + Names.ADAPTER_PORT_PROPERTY_NAME, + String.valueOf(TestConstants.DEFAULT_PORT)); + + System.setProperty( + Names.ADAPTER_HOST_PROPERTY_NAME, + TestConstants.DEFAULT_HOST); + + server = new ServerThread(listener); + server.start(); + + synchronized(_serverMonitor) { + _serverMonitor.wait(); + } + } + + @Override + protected void tearDown() throws Exception + { + server.shutdown(); + } + }; + + /** + * Set up fixture for this test case. + * + * @throws Exception when the test case intialization fails. + */ + protected void setUp() throws Exception + { + _managementServer = ManagementFactory.getPlatformMBeanServer(); + + ServiceGroupClient serviceGroup = getServiceGroupClient(); + WsResourceClient [] members = serviceGroup.getMembers(); + + assertEquals( + "No resource has been yet created so how is " + + "it possible that service group children list is not empty?", + 0, + members.length); + + _managementServer.invoke( + Names.QPID_EMULATOR_OBJECT_NAME, + "createQueue", new Object[]{_resourceObjectName = createResourceName()}, + new String[]{ObjectName.class.getName()}); + + members = serviceGroup.getMembers(); + assertEquals( + "One resource has just been created so " + + "I expect to find it on service group children list...", + 1, + members.length); + + _resourceClient = members[0]; + _mbeanInfo = _managementServer.getMBeanInfo(_resourceObjectName); + } + + /** + * Shutdown procedure for this test case. + * + * @throws Exception when either the server or some resource fails to shutdown. + */ + @Override + protected void tearDown() throws Exception + { + ServiceGroupClient serviceGroup = getServiceGroupClient(); + WsResourceClient [] members = serviceGroup.getMembers(); + + _managementServer.invoke( + Names.QPID_EMULATOR_OBJECT_NAME, + "unregister", + new Object[]{_resourceObjectName}, + new String[]{ObjectName.class.getName()}); + + members = serviceGroup.getMembers(); + + assertEquals( + "No resource has been yet created so how is it possible that service group children list is not empty?", + 0, + members.length); + } + + /** + * Test the WS-RP GetResourceProperty interface of the WS-DM adapter. + * + *
precondition : a ws resource exists and is registered. + *
postcondition : property values coming from WS-DM resource are the same of the JMX interface. + */ + public void testGeResourcePropertiesOK() throws Exception + { + MBeanAttributeInfo [] attributesMetadata = _mbeanInfo.getAttributes(); + for (MBeanAttributeInfo attributeMetadata : attributesMetadata) + { + String name = attributeMetadata.getName(); + Object propertyValues = _resourceClient.getPropertyAsObject( + new QName( + Names.NAMESPACE_URI, + name, + Names.PREFIX), + Class.forName(attributeMetadata.getType())); + + int length = Array.getLength(propertyValues); + if (length != 0) + { + Object propertyValue = Array.get(propertyValues, 0); + + assertEquals( + "Comparison failed for property "+name, + _managementServer.getAttribute(_resourceObjectName,name), + propertyValue); + } else { + assertNull( + String.format( + "\"%s\" property value shouldn't be null. Its value is %s", + name, + _managementServer.getAttribute(_resourceObjectName,name)), + _managementServer.getAttribute(_resourceObjectName,name)); + } + } + } + + /** + * Test the WS-RP SetResourceProperty interface of the WS-DM adapter. + * + *
precondition : a WS-Resource exists and is registered. + *
postcondition : property values are correctly updated on the target WS-Resource.. + */ + public void testSetResourcePropertiesOK() throws Exception + { + Map sampleMap = new HashMap(); + sampleMap.put("Key1", "BLABALABLABALBAL"); + sampleMap.put("Key2", 182838484l); + sampleMap.put("Key3", -928376362); + sampleMap.put("Key4", 23762736276.33D); + sampleMap.put("Key4", 2327363.2F); + + Map sampleValues = new HashMap(); + sampleValues.put(String.class.getName(),"SAMPLE_STRING"); + sampleValues.put(UUID.class.getName(),UUID.randomUUID()); + sampleValues.put(Boolean.class.getName(),Boolean.FALSE); + sampleValues.put(Map.class.getName(),sampleMap); + sampleValues.put(Long.class.getName(),283781273L); + sampleValues.put(Integer.class.getName(),12727); + sampleValues.put(Short.class.getName(),new Short((short)22)); + sampleValues.put(Date.class.getName(),new Date()); + + MBeanAttributeInfo [] attributesMetadata = _mbeanInfo.getAttributes(); + boolean atLeastThereIsOneWritableProperty = false; + + for (MBeanAttributeInfo attributeMetadata : attributesMetadata) + { + String name = attributeMetadata.getName(); + + if (attributeMetadata.isWritable()) + { + atLeastThereIsOneWritableProperty = true; + Object sampleValue = sampleValues.get(attributeMetadata.getType()); + Object []values = new Object[]{sampleValue}; + + Object result = _managementServer.getAttribute(_resourceObjectName, name); + if (result == null) + { + _resourceClient.insertResourceProperty( + new QName( + Names.NAMESPACE_URI, + name, + Names.PREFIX), + values); + } else + { + _resourceClient.updateResourceProperty( + new QName( + Names.NAMESPACE_URI, + name, + Names.PREFIX), + values); + } + + Object propertyValues = _resourceClient.getPropertyAsObject( + new QName( + Names.NAMESPACE_URI, + name, + Names.PREFIX), + Class.forName(attributeMetadata.getType())); + int length = Array.getLength(propertyValues); + if (length != 0) + { + Object propertyValue = Array.get(propertyValues, 0); + + assertEquals( + "Comparison failed for property "+name, + sampleValue, + propertyValue); + } else { + assertNull( + String.format( + "\"%s\" property value shouldn't be null. Its value is %s", + name, + _managementServer.getAttribute(_resourceObjectName,name)), + sampleValue); + } + } + } + assertTrue( + "It's not possibile to run successfully this test case if " + + "the target WS-Resource has no at least one writable property", + atLeastThereIsOneWritableProperty); + } + + /** + * Test the WS-RP SetResourceProperty interface of the WS-DM adapter when the + * target property is null. + * According to WS-RP specs this operation is not allowed because in this case a SetResourceProperty with an "Insert" + * message should be sent in order to initialize the property. + * + *
precondition : a ws resource exists and is registered. The value of the target property is null. + *
postcondition : a Soap fault is received indicating the failuire. + */ + public void testSetResourcePropertiesKO() throws Exception + { + Object typePropertyValue = _managementServer.getAttribute(_resourceObjectName, "Type"); + assertNull(typePropertyValue); + + try + { + _resourceClient.updateResourceProperty( + new QName( + Names.NAMESPACE_URI, + "Type", + Names.PREFIX), + new Object[]{"sampleValue"}); + fail( + "If the property is null on the target ws resource, according " + + "to WS-RP specs, an update of its value is not possible."); + } catch(SoapFault expected) + { + + } + } + +// public void testGetAndPutResourcePropertyDocumentOK() throws Exception +// { +// Element properties = _resourceClient.getResourcePropertyDocument(); +// +// Element mgmtPubInterval = XmlUtils.getElement(properties, new QName(Names.NAMESPACE_URI,"MgmtPubInterval",Names.PREFIX)); +// mgmtPubInterval.setTextContent(String.valueOf(Long.MAX_VALUE)); +// +// Element durable = XmlUtils.getElement(properties, new QName(Names.NAMESPACE_URI,"Durable",Names.PREFIX)); +// durable.setTextContent(String.valueOf(Boolean.FALSE)); +// +// Element consumerCount = XmlUtils.getElement(properties, new QName(Names.NAMESPACE_URI,"ConsumerCount",Names.PREFIX)); +// consumerCount.setTextContent(String.valueOf(13)); +// +// fail("PutResourcePropertyDocument not yet implemented!"); +//// _resourceClient.putResourcePropertyDocument(properties); +//// +//// Element newProperties = _resourceClient.getResourcePropertyDocument(); +//// +//// assertEquals(properties,newProperties); +// } + + /** + * Test the WS-RP GetResourceProperties interface of the WS-DM adapter. + * + *
precondition : a ws resource exists and is registered. + *
postcondition : Properties are correctly returned according to WSRP interface and they (their value) + * are matching with corresponding MBean properties. + */ + public void testGetMultipleResourcePropertiesOK() throws Exception + { + MBeanAttributeInfo [] attributesMetadata = _mbeanInfo.getAttributes(); + QName[] names = new QName[attributesMetadata.length]; + + int index = 0; + for (MBeanAttributeInfo attributeMetadata : _mbeanInfo.getAttributes()) + { + QName qname = new QName(Names.NAMESPACE_URI,attributeMetadata.getName(),Names.PREFIX); + names[index++] = qname; + } + + Element[] properties =_resourceClient.getMultipleResourceProperties(names); + for (Element element : properties) + { + String name = element.getLocalName(); + Object value = _managementServer.getAttribute(_resourceObjectName, name); + if ("Name".equals(name)) + { + assertEquals( + value, + element.getTextContent()); + } else if ("Durable".equals(name)) + { + assertEquals( + value, + Boolean.valueOf(element.getTextContent())); + } else if ("ExpireTime".equals(name)) + { + assertEquals( + value, + new Date(Long.valueOf(element.getTextContent()))); + } else if ("MsgTotalEnqueues".equals(name)) + { + assertEquals( + value, + Long.valueOf(element.getTextContent())); + } else if ("ConsumerCount".equals(name)) + { + assertEquals( + value, + Integer.valueOf(element.getTextContent())); + }else if ("VhostRef".equals(name)) + { + assertEquals( + value, + UUID.fromString(element.getTextContent())); + } + } + } + + /** + * Test operation invocation on WS-Resource. + * This method tests the exchange of simple types between requestor and service provider. + * With simple types we mean : + * + *
    + *
  • java.lang.Long / long (xsd:long) + *
  • java.lang.Integer / int (xsd:int / xsd:integer) + *
  • java.lang.Double/ double (xsd:double) + *
  • java.lang.Float / float (xsd:float) + *
  • java.lang.Short / short (xsd:short) + *
  • java.lang.Boolean / boolean (xsd:boolean) + *
  • java.lang.String (xsd:string) + *
  • java.net.URI (xsd:anyURI) + *
  • java.util.Date(xsd:dateTime) + *
+ * + *
precondition : a ws resource exists and is registered and the requested operation is available on that. + *
postcondition : invocations are executed successfully, no exception is thrown and parameters are correctly returned. + */ + @SuppressWarnings("unchecked") + public void testOperationInvocationOK_withSimpleTypes() throws Exception + { + Long expectedLongResult = new Long(1373); + Boolean expectedBooleanResult = Boolean.TRUE; + Double expectedDoubleResult = new Double(12763.44); + Float expectedFloatResult = new Float(2727.233f); + Integer expectedIntegerResult = new Integer(28292); + Short expectedShortResult = new Short((short)227); + String expectedStringResult = "expectedStringResult"; + URI expectedUriResult = URI.create("http://qpid.apache.org/"); + Date expectedDateResult = new Date(); + + Object result = _resourceClient.invoke( + _invocationHandlers.get("echoWithSimpleTypes"), + new Object[]{ + expectedLongResult, + expectedBooleanResult, + expectedDoubleResult, + expectedFloatResult, + expectedIntegerResult, + expectedShortResult, + expectedStringResult, + expectedUriResult, + expectedDateResult}); + + Method getStatusCode = result.getClass().getMethod("getStatusCode"); + Method getOutputParameters = result.getClass().getMethod("getOutputParameters"); + assertEquals(retCodeOk,getStatusCode.invoke(result)); + Map out = (Map) getOutputParameters.invoke(result); + + assertEquals("Output parameters must be 9.",9,out.size()); + assertTrue("Long output parameter not found on result object.",out.containsValue(expectedLongResult)); + assertTrue("Boolean output parameter not found on result object.",out.containsValue(expectedBooleanResult)); + assertTrue("Double output parameter not found on result object.",out.containsValue(expectedDoubleResult)); + assertTrue("Float output parameter not found on result object.",out.containsValue(expectedFloatResult)); + assertTrue("Integer output parameter not found on result object.",out.containsValue(expectedIntegerResult)); + assertTrue("Short output parameter not found on result object.",out.containsValue(expectedShortResult)); + assertTrue("String output parameter not found on result object.",out.containsValue(expectedStringResult)); + assertTrue("URI output parameter not found on result object.",out.containsValue(expectedUriResult)); + assertTrue("Date output parameter not found on result object.",out.containsValue(expectedDateResult)); + } + + /** + * Test operation invocation on WS-Resource. + * This method tests the exchange of arrays between requestor and service provider. + * For this test exchanged arrays contain : + * + *
    + *
  • java.lang.Long (xsd:long) + *
  • java.lang.Integer (xsd:int / xsd:integer) + *
  • java.lang.Double (xsd:double) + *
  • java.lang.Float (xsd:float) + *
  • java.lang.Short (xsd:short) + *
  • java.lang.Boolean (xsd:boolean) + *
  • java.lang.String (xsd:string) + *
  • java.net.URI (xsd:anyURI) + *
  • java.util.Date(xsd:dateTime) + *
+ * + *
precondition : a ws resource exists and is registered and the requested operation is available on that. + *
postcondition : invocations are executed successfully, no exception is thrown and parameters are correctly returned. + */ + @SuppressWarnings("unchecked") + public void testOperationInvocationOK_withWrapperArrays() throws Exception + { + Long [] expectedLongResult = {new Long(2),new Long(1),new Long(3),new Long(4)}; + Boolean [] expectedBooleanResult = { Boolean.TRUE,Boolean.FALSE,Boolean.FALSE}; + Double [] expectedDoubleResult = {12763.44d,2832.33d,2292.33d,22293.22d}; + Float [] expectedFloatResult = {2727.233f,1f,2f,4f,5.4f,33.2f}; + Integer [] expectedIntegerResult = {1,2,3,4,55,66,77,88,99}; + Short [] expectedShortResult = {(short)227,(short)23,(short)9}; + String [] expectedStringResult = {"s1","s2","s333","s4"}; + URI [] expectedUriResult = { + URI.create("http://qpid.apache.org/"), + URI.create("http://www.apache.org"), + URI.create("http://projects.apache.org")}; + + Date [] expectedDateResult = { + new Date(), + new Date(38211897), + new Date(903820382)}; + + Object result = _resourceClient.invoke( + _invocationHandlers.get("echoWithArrays"), + new Object[]{ + expectedLongResult, + expectedBooleanResult, + expectedDoubleResult, + expectedFloatResult, + expectedIntegerResult, + expectedShortResult, + expectedStringResult, + expectedUriResult, + expectedDateResult}); + + Method getStatusCode = result.getClass().getMethod("getStatusCode"); + Method getOutputParameters = result.getClass().getMethod("getOutputParameters"); + assertEquals(retCodeOk,getStatusCode.invoke(result)); + Map out = (Map) getOutputParameters.invoke(result); + + assertEquals("Output parameters must be 9.",9,out.size()); + assertTrue("Long array doesn't match.",Arrays.equals(expectedLongResult, (Long[])out.get(Long.class.getName()))); + assertTrue("Boolean array doesn't match.",Arrays.equals(expectedBooleanResult, (Boolean[])out.get(Boolean.class.getName()))); + assertTrue("Double array doesn't match.",Arrays.equals(expectedDoubleResult, (Double[])out.get(Double.class.getName()))); + assertTrue("Float array doesn't match.",Arrays.equals(expectedFloatResult, (Float[])out.get(Float.class.getName()))); + assertTrue("Integer array doesn't match.", Arrays.equals(expectedIntegerResult, (Integer[])out.get(Integer.class.getName()))); + assertTrue("Short array doesn't match.",Arrays.equals(expectedShortResult, (Short[])out.get(Short.class.getName()))); + assertTrue("String array doesn't match.",Arrays.equals(expectedStringResult, (String[])out.get(String.class.getName()))); + assertTrue("URI array doesn't match.",Arrays.equals(expectedUriResult, (URI[])out.get(URI.class.getName()))); + assertTrue("Date array doesn't match.",Arrays.equals(expectedDateResult, (Date[])out.get(Date.class.getName()))); + } + + /** + * Test operation invocation on WS-Resource. + * This method tests the exchange of primitive type arrays between requestor and service provider. + * NOte that even the sent array contain primtiive type QMan deals only with objects so in the result + * object you will find the corresponding wrapper types. + * + * For this test exchanged arrays contain : + * + *
    + *
  • java.lang.Long / long (xsd:long) + *
  • java.lang.Integer / int (xsd:int / xsd:integer) + *
  • java.lang.Double/ double (xsd:double) + *
  • java.lang.Float / float (xsd:float) + *
  • java.lang.Short / short (xsd:short) + *
  • java.lang.Boolean / boolean (xsd:boolean) + *
+ * + *
precondition : a ws resource exists and is registered and the requested operation is available on that. + *
postcondition : invocations are executed successfully, no exception is thrown and parameters are correctly returned. + */ + @SuppressWarnings("unchecked") + public void testOperationInvocationOK_withPrimitiveArrays() throws Exception + { + long [] expectedLongResult = {1L,2L,3L,4L}; + boolean [] expectedBooleanResult = { true,false,false}; + double [] expectedDoubleResult = {12763.44d,2832.33d,2292.33d,22293.22d}; + float [] expectedFloatResult = {2727.233f,1f,2f,4f,5.4f,33.2f}; + int [] expectedIntegerResult = {1,2,3,4,55,66,77,88,99}; + short [] expectedShortResult = {(short)227,(short)23,(short)9}; + + Object result = _resourceClient.invoke( + _invocationHandlers.get("echoWithSimpleTypeArrays"), + new Object[]{ + expectedLongResult, + expectedBooleanResult, + expectedDoubleResult, + expectedFloatResult, + expectedIntegerResult, + expectedShortResult}); + + Method getStatusCode = result.getClass().getMethod("getStatusCode"); + Method getOutputParameters = result.getClass().getMethod("getOutputParameters"); + assertEquals(retCodeOk,getStatusCode.invoke(result)); + Map out = (Map) getOutputParameters.invoke(result); + + assertEquals("Output parameters must be 6.",6,out.size()); + assertArrayEquals(expectedLongResult, out.get(long.class.getName())); + assertArrayEquals(expectedBooleanResult, out.get(boolean.class.getName())); + assertArrayEquals(expectedDoubleResult, out.get(double.class.getName())); + assertArrayEquals(expectedFloatResult, out.get(float.class.getName())); + assertArrayEquals(expectedIntegerResult, out.get(int.class.getName())); + assertArrayEquals(expectedShortResult, out.get(short.class.getName())); + } + + /** + * Test operation invocation on WS-Resource. + * This method tests the exchange of a byte type array between requestor and service provider. + * + *
precondition : a WS-Resource exists and is registered and the requested operation is available on that. + *
postcondition : invocations are executed successfully, no exception is thrown and byte array are correctly returned. + */ + @SuppressWarnings("unchecked") + public void testOperationInvocationOK_withByteArray() throws Exception + { + byte [] expectedByteResult = {1,3,4,2,2,44,22,3,3,55,66}; + + Object result = _resourceClient.invoke( + _invocationHandlers.get("echoWithByteArray"), + new Object[]{expectedByteResult}); + + Method getStatusCode = result.getClass().getMethod("getStatusCode"); + Method getOutputParameters = result.getClass().getMethod("getOutputParameters"); + + assertEquals(retCodeOk,getStatusCode.invoke(result)); + Map out = (Map) getOutputParameters.invoke(result); + + assertEquals("Output parameters must be 1.",1,out.size()); + assertArrayEquals(expectedByteResult, out.get(byte[].class.getName())); + } + + /** + * Test a simple operation invocation on a WS-Resource. + * This method tests a simple operation without any input and output parameters. + * + *
precondition : a ws resource exists and is registered and the requested operation is available on that. + *
postcondition : invocations are executed successfully an no exception is thrown. + */ + @SuppressWarnings("unchecked") + public void testSimpleOperationInvocationOK() throws Exception + { + Object result = _resourceClient.invoke( + _invocationHandlers.get("voidWithoutArguments"), + null); + + Method getStatusCode = result.getClass().getMethod("getStatusCode"); + assertEquals( + "Something was wrong...expected return code is "+retCodeOk, + retCodeOk, + getStatusCode.invoke(result)); + } + + /** + * Test a the invocation on a WS-Resource with a method that throws an exception.. + * + *
precondition : a ws resource exists and is registered and the requested operation is available on that. + *
postcondition : an exception is thrown by the requested method. + */ + @SuppressWarnings("unchecked") + public void testInvocationException_OK() throws Exception + { + try + { + _resourceClient.invoke( + _invocationHandlers.get("throwsException"), + null); + fail("The requested operation has thrown an exception so a Soap Fault is expected..."); + } catch(SoapFault expected) + { + } + } + + /** + * Test operation invocation on WS-Resource. + * This method tests the exchange of UUID type between requestor and service provider. + * + *
precondition : a WS-Resource exists and is registered and the requested operation is available on that. + *
postcondition : invocations are executed successfully, no exception is thrown and parameters are correctly returned. + */ + @SuppressWarnings("unchecked") + public void testOperationInvocationOK_withUUID() throws Exception + { + UUID expectedUuid = UUID.randomUUID(); + + Object result = _resourceClient.invoke( + _invocationHandlers.get("echoWithUUID"), + new Object[]{expectedUuid}); + + Method getStatusCode = result.getClass().getMethod("getStatusCode"); + Method getOutputParameters = result.getClass().getMethod("getOutputParameters"); + + assertEquals(retCodeOk,getStatusCode.invoke(result)); + Map out = (Map) getOutputParameters.invoke(result); + + assertEquals("Output parameters must be 1.",1,out.size()); + assertEquals(expectedUuid, out.get("uuid")); + } + + /** + * Test operation invocation on WS-Resource. + * This method tests the exchange of Map type between requestor and service provider. + * For this test exchanged arrays contain : + * + *
precondition : a ws resource exists and is registered and the requested operation is available on that. + *
postcondition : invocations are executed successfully, no exception is thrown and parameters are correctly returned. + */ + @SuppressWarnings("unchecked") + public void testOperationInvocationOK_withMap() throws Exception + { + Map expectedMap = new HashMap(); + expectedMap.put("p1", new Long(1)); + expectedMap.put("p2", Boolean.TRUE); + expectedMap.put("p3", 1234d); + expectedMap.put("p4", 11.2f); + expectedMap.put("p5", 1272); + expectedMap.put("p6", (short)12); + expectedMap.put("p7", "aString"); + expectedMap.put("p8", "http://qpid.apache.org"); + expectedMap.put("p9", new Date(12383137128L)); + expectedMap.put("p10", new byte[]{1,2,2,3,3,4}); + + Object result = _resourceClient.invoke( + _invocationHandlers.get("echoWithMap"), + new Object[]{expectedMap}); + + Method getStatusCode = result.getClass().getMethod("getStatusCode"); + Method getOutputParameters = result.getClass().getMethod("getOutputParameters"); + + assertEquals(retCodeOk,getStatusCode.invoke(result)); + Map out = (Map) ((Map) getOutputParameters.invoke(result)).get("map"); + + assertEquals("Output parameters must be 10.",10,out.size()); + assertEquals(expectedMap.get("p1"),out.get("p1")); + assertEquals(expectedMap.get("p2"),out.get("p2")); + assertEquals(expectedMap.get("p3"),out.get("p3")); + assertEquals(expectedMap.get("p4"),out.get("p4")); + assertEquals(expectedMap.get("p5"),out.get("p5")); + assertEquals(expectedMap.get("p6"),out.get("p6")); + assertEquals(expectedMap.get("p7"),out.get("p7")); + assertEquals(expectedMap.get("p8"),out.get("p8")); + assertEquals(expectedMap.get("p9"),out.get("p9")); + assertTrue( Arrays.equals((byte[])expectedMap.get("p10"),(byte[])out.get("p10"))); + } + + /** + * Main entry point for running this test case. + * + * @return the decorated test case. + */ + public static Test suite() { + TestSuite suite = new TestSuite("Test Suite for WS-DM Adapter"); + suite.addTestSuite(WsDmAdapterTest.class); + return new WsDmAdapterTestSetup(suite); + } + + /** + * Creates a service group client reference. + * + * @return a service group client reference. + */ + private ServiceGroupClient getServiceGroupClient() + { + URI address = URI.create( + "http://"+ + TestConstants.DEFAULT_HOST+ + ":"+ + TestConstants.DEFAULT_PORT+ + "/qman/services/adapter"); + return new ServiceGroupClient(new EndpointReference(address)); + } + + /** + * In order to test the behaviour of the WS-DM adapter, at + * least one resource must be created. This is the method that + * returns the name (ObjectName on JMX side, Resource-ID on WSDM side) + * of that resource + * + * @return the name of the MBean instance that will be created. + * @throws Exception when the name if malformed. Practically never. + */ + private ObjectName createResourceName() throws Exception + { + return new ObjectName( + "Q-MAN:objectId="+UUID.randomUUID()+ + ", brokerID="+UUID.randomUUID()+ + ",class=queue"+ + ",package=org.apache.qpid"+ + ",name="+System.currentTimeMillis()); + } + + private Map createInvocationHandlers() + { + Map handlers = new HashMap(); + + ProxyHandler handler = new ReflectionProxyHandler(); + handler.setAction(Names.NAMESPACE_URI+"/"+"voidWithoutArguments"); + handler.setRequestName( + new QName( + Names.NAMESPACE_URI, + "voidWithoutArgumentsRequest", + Names.PREFIX)); + handler.setRequestParameterNames(new QName[]{}); + handler.setResponseName( + new QName( + Names.NAMESPACE_URI, + "voidWithoutArgumentsResponse", + Names.PREFIX)); + handler.setReturnType(Result.class); + + ProxyHandler exceptionHandler = new ReflectionProxyHandler(); + exceptionHandler.setAction(Names.NAMESPACE_URI+"/"+"throwsException"); + exceptionHandler.setRequestName( + new QName( + Names.NAMESPACE_URI, + "throwsExceptionRequest", + Names.PREFIX)); + + exceptionHandler.setRequestParameterNames(new QName[]{}); + exceptionHandler.setResponseName( + new QName( + Names.NAMESPACE_URI, + "throwsExceptionResponse", + Names.PREFIX)); + + exceptionHandler.setReturnType(Result.class); + + ProxyHandler echoWithWrapperTypesHandler = new ReflectionProxyHandler(); + echoWithWrapperTypesHandler.setAction(Names.NAMESPACE_URI+"/"+"echoWithSimpleTypes"); + echoWithWrapperTypesHandler.setRequestName( + new QName( + Names.NAMESPACE_URI, + "echoWithSimpleTypesRequest", + Names.PREFIX)); + + echoWithWrapperTypesHandler.setRequestParameterNames(new QName[]{ + new QName(Names.NAMESPACE_URI,"p1",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p2",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p3",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p4",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p5",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p6",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p7",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p8",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p9",Names.PREFIX), + }); + + echoWithWrapperTypesHandler.setResponseName( + new QName( + Names.NAMESPACE_URI, + "echoWithSimpleTypesResponse", + Names.PREFIX)); + + echoWithWrapperTypesHandler.setReturnType(Result.class); + + ProxyHandler echoWithArrayOfWrapperTypes = new ReflectionProxyHandler(); + echoWithArrayOfWrapperTypes.setAction(Names.NAMESPACE_URI+"/"+"echoWithArrays"); + echoWithArrayOfWrapperTypes.setRequestName( + new QName( + Names.NAMESPACE_URI, + "echoWithArraysRequest", + Names.PREFIX)); + + echoWithArrayOfWrapperTypes.setRequestParameterNames(new QName[]{ + new QName(Names.NAMESPACE_URI,"p1",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p2",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p3",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p4",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p5",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p6",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p7",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p8",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p9",Names.PREFIX), + }); + + echoWithArrayOfWrapperTypes.setResponseName( + new QName( + Names.NAMESPACE_URI, + "echoWithArraysResponse", + Names.PREFIX)); + + echoWithArrayOfWrapperTypes.setReturnType(Result.class); + + ProxyHandler echoWithArrayOfPrimitiveTypes = new ReflectionProxyHandler(); + echoWithArrayOfPrimitiveTypes.setAction(Names.NAMESPACE_URI+"/"+"echoWithSimpleTypeArrays"); + echoWithArrayOfPrimitiveTypes.setRequestName( + new QName( + Names.NAMESPACE_URI, + "echoWithSimpleTypeArraysRequest", + Names.PREFIX)); + + echoWithArrayOfPrimitiveTypes.setRequestParameterNames(new QName[]{ + new QName(Names.NAMESPACE_URI,"p1",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p2",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p3",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p4",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p5",Names.PREFIX), + new QName(Names.NAMESPACE_URI,"p6",Names.PREFIX)}); + + echoWithArrayOfPrimitiveTypes.setResponseName( + new QName( + Names.NAMESPACE_URI, + "echoWithSimpleTypeArraysResponse", + Names.PREFIX)); + + echoWithArrayOfPrimitiveTypes.setReturnType(Result.class); + + ProxyHandler echoWithByteArray = new EnhancedReflectionProxyHandler(); + echoWithByteArray.setAction(Names.NAMESPACE_URI+"/"+"echoWithByteArray"); + echoWithByteArray.setRequestName( + new QName( + Names.NAMESPACE_URI, + "echoWithByteArrayRequest", + Names.PREFIX)); + + echoWithByteArray.setRequestParameterNames( + new QName[]{ + new QName(Names.NAMESPACE_URI,"p1",Names.PREFIX)}); + + echoWithByteArray.setResponseName( + new QName( + Names.NAMESPACE_URI, + "echoWithByteArrayResponse", + Names.PREFIX)); + + echoWithByteArray.setReturnType(Result.class); + + ProxyHandler echoWithUUID = new EnhancedReflectionProxyHandler(); + echoWithUUID.setAction(Names.NAMESPACE_URI+"/"+"echoWithUUID"); + echoWithUUID.setRequestName( + new QName( + Names.NAMESPACE_URI, + "echoWithUUIDRequest", + Names.PREFIX)); + + echoWithUUID.setRequestParameterNames( + new QName[]{ + new QName(Names.NAMESPACE_URI,"p1",Names.PREFIX)}); + + echoWithUUID.setResponseName( + new QName( + Names.NAMESPACE_URI, + "echoWithUUIDResponse", + Names.PREFIX)); + + echoWithUUID.setReturnType(Result.class); + + ProxyHandler echoWithMap = new EnhancedReflectionProxyHandler(); + echoWithMap.setAction(Names.NAMESPACE_URI+"/"+"echoWithMap"); + echoWithMap.setRequestName( + new QName( + Names.NAMESPACE_URI, + "echoWithMapRequest", + Names.PREFIX)); + + echoWithMap.setRequestParameterNames( + new QName[]{ + new QName(Names.NAMESPACE_URI,"p1",Names.PREFIX)}); + + echoWithMap.setResponseName( + new QName( + Names.NAMESPACE_URI, + "echoWithMapResponse", + Names.PREFIX)); + + echoWithMap.setReturnType(Result.class); + + handlers.put("voidWithoutArguments",handler); + handlers.put("echoWithSimpleTypes",echoWithWrapperTypesHandler); + handlers.put("echoWithArrays",echoWithArrayOfWrapperTypes); + handlers.put("echoWithSimpleTypeArrays", echoWithArrayOfPrimitiveTypes); + handlers.put("echoWithByteArray", echoWithByteArray); + handlers.put("echoWithUUID", echoWithUUID); + handlers.put("echoWithMap", echoWithMap); + handlers.put("throwsException",exceptionHandler); + return handlers; + } + + /** + * Internal method used for array comparison using reflection. + * + * @param expectedArray the expected array. + * @param resultArray the array that must match the expected one. + */ + private void assertArrayEquals(Object expectedArray, Object resultArray) + { + int expectedArrayLength = Array.getLength(expectedArray); + int resultArrayLength = Array.getLength(resultArray); + + assertEquals(expectedArrayLength,resultArrayLength); + + for (int index = 0; index < expectedArrayLength; index++) + { + Object expected = Array.get(expectedArray, index); + Object result = Array.get(resultArray, index); + + assertEquals(expected,result); + } + } +} \ No newline at end of file diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilderTest.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilderTest.java new file mode 100644 index 0000000000..ead6bea6cc --- /dev/null +++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilderTest.java @@ -0,0 +1,278 @@ +/* + * + * 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.management.wsdm.capabilities; + +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.List; + +import javassist.CtClass; +import javassist.CtMethod; + +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import junit.framework.TestCase; + +import org.apache.qpid.management.domain.handler.impl.QpidDomainObject; +import org.apache.qpid.management.wsdm.common.EntityInstanceNotFoundFault; +import org.apache.qpid.management.wsdm.common.MethodInvocationFault; +import org.apache.qpid.management.wsdm.common.NoSuchAttributeFault; +import org.apache.qpid.management.wsdm.common.QManFault; + +/** + * Test case for MBean capability builder. + * + * @author Andrea Gazzarini + */ +public class MBeanCapabilityBuilderTest extends TestCase +{ + + private MBeanCapabilityBuilder _builder; + private ObjectName _objectName; + + /** + * Set up fixture for this test case. + */ + protected void setUp() throws Exception + { + _builder = new MBeanCapabilityBuilder(); + _objectName = new ObjectName("Test:Name=aName,class=DomainObject"); + } + + /** + * Tests that state change that occcurs on the begin() method when the requested + * class has not been defined. + */ + public void testBegin_withClassNotYetDefined() throws Exception + { + _builder.begin(_objectName); + assertEquals(_builder._state,_builder._classNotAvailable); + } + + /** + * Tests that state change that occcurs on the begin() method when the requested + * class has not been defined. + */ + public void testBegin_withClassAlreadyDefined() throws Exception + { + _objectName = new ObjectName("Test:Name=aString,class=MBeanCapabilityBuilder"); + _builder.begin(_objectName); + + assertTrue(_builder._state instanceof DummyCapabilityBuilder); + assertSame(_builder._endAttributeHandler, _builder._noPropertyHasBeenDefined); + } + + /** + * Tests the generateGetter method(). + */ + public void testGenerateGetter() + { + String name ="MyProperty"; + String type = Long.class.getName(); + String expected = + "public "+ + type+ + " get"+ + name+ + "() throws NoSuchAttributeFault,EntityInstanceNotFoundFault,QManFault { return ("+ + type+ + ") getAttribute(\""+ + name+ + "\"); }"; + + String result = _builder.generateGetter(type, name); + assertEquals(expected,result); + } + + /** + * Tests the generateGetter method(). + */ + public void testGenerateSetter() + { + String name ="MyProperty"; + String type = Long.class.getName(); + String expected = + "public void setMyProperty("+ + type+ + " newValue) throws NoSuchAttributeFault,EntityInstanceNotFoundFault,QManFault { setAttribute(\""+ + name+ + "\", newValue); }"; + + String result = _builder.generateSetter(type, name); + assertEquals(expected,result); + } + + /** + * Tests the whole execution of the builder. + */ + @SuppressWarnings("unchecked") + public void testBuildOK() throws Exception + { + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + QpidDomainObject mbean = new QpidDomainObject(); + server.registerMBean(mbean, _objectName); + + _builder.begin(_objectName); + + CtClass definition = _builder._capabilityClassDefinition; + assertEquals( + MBeanCapability.class.getName(), + definition.getSuperclass().getName()); + + MBeanInfo metadata = server.getMBeanInfo(_objectName); + + for (MBeanAttributeInfo attribute : metadata.getAttributes()) + { + _builder.onAttribute(attribute); + checkAttribute(attribute, definition); + + assertSame( + _builder._endAttributeHandler, + _builder._atLeastThereIsOneProperty); + } + + for (MBeanOperationInfo operation : metadata.getOperations()) + { + _builder.onOperation(operation); + checkOperation(operation,definition); + } + + _builder.endAttributes(); + _builder.endOperations(); + + assertNotNull(_builder.getCapabilityClass()); + } + + /** + * Checks an operation / method after that it has been declared on + * capability definition. + * + * @param operation the (JMX) operation metadata. + * @param definition the capability class definition. + * @throws Exception when something goes wrong during introspection. + */ + private void checkOperation(MBeanOperationInfo operation, CtClass definition) throws Exception + { + CtMethod method = definition.getDeclaredMethod(operation.getName()); + assertNotNull(method); + + checkExceptionTypes( + method.getExceptionTypes(), + new String[]{ + QManFault.class.getName(), + EntityInstanceNotFoundFault.class.getName(), + MethodInvocationFault.class.getName()}); + + assertEquals(Result.class.getName(),method.getReturnType().getName()); + + CtClass [] parameterTypes = method.getParameterTypes(); + MBeanParameterInfo [] parameterMetadata = operation.getSignature(); + + assertEquals(parameterTypes.length, parameterMetadata.length); + for (int i = 0; i < parameterMetadata.length; i++) + { + assertEquals( + parameterTypes[i].getName(), + Class.forName(parameterMetadata[i].getType()).getCanonicalName()); + } + } + + /** + * Checks the exception types associated with a method. + * + * @param exceptionTypes the exception types actually thrown. + * @param expectedExceptionNames the expected exception types (as strings). + */ + private void checkExceptionTypes(CtClass [] exceptionTypes, String [] expectedExceptionNames) + { + List exceptionNames = new ArrayList(exceptionTypes.length); + for (CtClass exception : exceptionTypes) + { + exceptionNames.add(exception.getName()); + } + + for (String expectedExceptionName : expectedExceptionNames) + { + exceptionNames.remove(expectedExceptionName); + } + + assertTrue(exceptionNames.isEmpty()); + } + + /** + * Checks an attribute after that it has been declared on capability definition. + * + * @param attribute the (JMX) attribute metadata. + * @param definition the capability class definition. + * @throws Exception when something goes wrong during introspection. + */ + private void checkAttribute(MBeanAttributeInfo attribute, CtClass definition) throws Exception + { + String name = _builder.getNameForAccessors(attribute.getName()); + + String newPropertyDeclaration = + new StringBuilder("new QName(Names.NAMESPACE_URI, \"") + .append(attribute.getName()) + .append("\", Names.PREFIX),") + .toString(); + assertTrue(_builder._properties.indexOf(newPropertyDeclaration) != -1); + + if (attribute.isReadable()) + { + CtMethod getter = definition.getDeclaredMethod("get"+name); + assertNotNull(getter); + + checkExceptionTypes( + getter.getExceptionTypes(), + new String[]{ + QManFault.class.getName(), + NoSuchAttributeFault.class.getName(), + EntityInstanceNotFoundFault.class.getName()}); + + assertEquals(0,getter.getParameterTypes().length); + assertEquals(attribute.getType(),getter.getReturnType().getName()); + } + + if (attribute.isWritable()) + { + CtMethod setter = definition.getDeclaredMethod("set"+name); + assertNotNull(setter); + + checkExceptionTypes( + setter.getExceptionTypes(), + new String[]{ + QManFault.class.getName(), + NoSuchAttributeFault.class.getName(), + EntityInstanceNotFoundFault.class.getName()}); + + CtClass [] parameterTypes = setter.getParameterTypes(); + + assertEquals(1,parameterTypes.length); + assertEquals(attribute.getType(),parameterTypes[0].getName()); + assertEquals(void.class.getName(),setter.getReturnType().getName()); + } + } +} \ No newline at end of file diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityTest.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityTest.java new file mode 100644 index 0000000000..a9a6491209 --- /dev/null +++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityTest.java @@ -0,0 +1,204 @@ +/* + * + * 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.management.wsdm.capabilities; + +import java.lang.management.ManagementFactory; +import java.net.URI; + +import javax.management.ObjectName; + +import junit.framework.TestCase; + +import org.apache.muse.ws.addressing.EndpointReference; +import org.apache.muse.ws.resource.WsResource; +import org.apache.muse.ws.resource.impl.SimpleWsResource; +import org.apache.qpid.management.domain.handler.impl.QpidDomainObject; +import org.apache.qpid.management.wsdm.common.EntityInstanceNotFoundFault; +import org.apache.qpid.management.wsdm.common.NoSuchAttributeFault; +import org.apache.qpid.management.wsdm.common.QManFault; + +/** + * Test case for MBeanCapability supertype layer.. + * + * @author Andrea Gazzarini + */ +public class MBeanCapabilityTest extends TestCase +{ + private final String _typeAttributeName = "Type"; + private final String _newTypeValue = "DomainObject"; + + private ObjectName _objectName; + private ObjectName _unknownObjectName; + + private MBeanCapability _capability; + + @Override + protected void setUp() throws Exception + { + _objectName = new ObjectName("Test:Name=aName"); + _unknownObjectName = new ObjectName("Test:Type=unknown"); + + _capability = new MBeanCapability(){ + @Override + public WsResource getWsResource() + { + return new SimpleWsResource(){ + @Override + public EndpointReference getEndpointReference() + { + return new EndpointReference(URI.create("http://qpid.apache.org/qman")); + } + }; + } + }; + _capability.setResourceObjectName(_objectName); + ManagementFactory.getPlatformMBeanServer().registerMBean(new QpidDomainObject(), _objectName); + } + + /** + * Tests the execution of the getAttribute() and setAttribute() method. + * + *
precondition : the mbean is registered and a _capability is associated with it. + *
postcondition : the set value of the requested attribute is correctly returned. + */ + public void testGetAndSetAttributeOK() throws Exception + { + Object name = _capability.getAttribute(_typeAttributeName); + assertNull("Name has an initial value of null so how is possibile that is not null?",name); + + _capability.setAttribute(_typeAttributeName,_newTypeValue); + + name = _capability.getAttribute(_typeAttributeName); + assertEquals("Now the name attribute must be set to \""+_newTypeValue+"\"",_newTypeValue,name); + } + + /** + * Tests the execution of the getAttribute() and setAttribte() methods when an unknown attribute is given.. + * + *
precondition : the mbean is registered, a _capability is associated with it and the requested attribute doesn't exist. + *
postcondition : an exception is thrown indicating the failure. + */ + public void testNoSuchAttributeFault() throws Exception + { + // I suppose that we shouldn't have an attribute with this name... + String unknownAttribute = String.valueOf(System.currentTimeMillis()); + + try + { + _capability.getAttribute(unknownAttribute); + fail("An exception must be thrown here in order to indicate that the attribute is unknown."); + } catch(NoSuchAttributeFault expected) + { + } + + try + { + _capability.setAttribute(unknownAttribute,null); + fail("An exception must be thrown here in order to indicate that the attribute is unknown."); + } catch(NoSuchAttributeFault expected) + { + } + } + + /** + * Tests the execution of the setAttribute,getAttribute and invoke methods when the target mbean + * doesn't exists. + * + *
precondition : the object name associated with the capability is not pointing to an existent MBean. + *
postcondition : an exception is thrown indicating the failure. + */ + public void testEntityInstanceNotFoundFault() throws Exception + { + _capability.setResourceObjectName(_unknownObjectName); + + try + { + _capability.getAttribute(_typeAttributeName); + fail("An exception must be thrown here in order to indicate that the attribute is unknown."); + } catch(EntityInstanceNotFoundFault expected) + { + } + + try + { + _capability.setAttribute(_typeAttributeName,_newTypeValue); + fail("An exception must be thrown here in order to indicate that the attribute is unknown."); + } catch(EntityInstanceNotFoundFault expected) + { + } + + try + { + _capability.invoke("operationName", null,null); + fail("An exception must be thrown here in order to indicate that the attribute is unknown."); + } catch(EntityInstanceNotFoundFault expected) + { + } + } + + /** + * Tests the execution of the setAttribute,getAttribute and invoke methods when an unknown / unexpected + * exception is thrown. + * + *
precondition : the mbean is registered and a capability is associated with it. Something + * unexpected happens during method invocation. + *
postcondition : an exception is thrown indicating the failure. + */ + public void testQManFault() throws Exception + { + // Emulate a RuntimeException (which is the best example of uncaught exception... :) ) + _capability.setResourceObjectName(null); + + try + { + _capability.getAttribute(_typeAttributeName); + fail("An exception must be thrown here in order to indicate that the attribute is unknown."); + } catch(QManFault expected) + { + } + + try + { + _capability.setAttribute(_typeAttributeName,_newTypeValue); + fail("An exception must be thrown here in order to indicate that the attribute is unknown."); + } catch(QManFault expected) + { + } + + try + { + _capability.invoke("operationName", null,null); + fail("An exception must be thrown here in order to indicate that the attribute is unknown."); + } catch(QManFault expected) + { + } + } + + + /** + * Shutdown procedure for this test case. + */ + @Override + protected void tearDown() throws Exception + { + ManagementFactory.getPlatformMBeanServer().unregisterMBean(_objectName); + } +} diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilderTest.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilderTest.java new file mode 100644 index 0000000000..77cda1c2c1 --- /dev/null +++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilderTest.java @@ -0,0 +1,110 @@ +/* + * + * 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.management.wsdm.capabilities; + +import java.lang.management.ManagementFactory; + +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.apache.qpid.management.Names; +import org.apache.qpid.management.domain.handler.impl.QpidDomainObject; +import org.w3c.dom.Element; + +import junit.framework.TestCase; + +/** + * Test case for Resource Metadata Descriptor Builder. + * + * @author Andrea Gazzarini + */ +public class RmdBuilderTest extends TestCase +{ + private MBeanInfo _metadata; + private RmdBuilder _builder; + private ObjectName _objectName; + + @Override + protected void setUp() throws Exception + { + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + _objectName = new ObjectName("Test:Name=QpidDomainObject"); + + server.registerMBean(new QpidDomainObject(), _objectName); + _metadata = server.getMBeanInfo(_objectName); + + _builder = new RmdBuilder(); + _builder.begin(_objectName); + + assertEquals(_objectName,_builder._objectName); + } + + /** + * Tests the execution of the onOperation() method. + */ + public void testOnOperation() throws Exception + { + MBeanAttributeInfo [] attributes = _metadata.getAttributes(); + for (MBeanAttributeInfo attribute : attributes) + { + _builder.onAttribute(attribute); + } + + Element [] rmd = _builder.getResourceMetadataDescriptor(); + + assertEquals(attributes.length,rmd.length); + + for (MBeanAttributeInfo attribute: _metadata.getAttributes()) + { + Element propertyMetadataDescriptor = getPropertyMetadatDescriptor(attribute.getName(), rmd); + + String modifiability = propertyMetadataDescriptor.getAttribute(Names.MODIFIABILITY); + String expectedValue = + attribute.isWritable() + ? Names.READ_WRITE + : Names.READ_ONLY; + assertEquals(expectedValue,modifiability); + } + } + + /** + * Returns the property metadata descriptor associated with the given attribute name. + * + * @param name the attribute name. + * @param rmd the resource metadata descriptor. + * @return the property metadata descriptor associated with the given attribute name. + * @throws RuntimeException if metadata for the given attribute is not found. + */ + private Element getPropertyMetadatDescriptor(String name, Element [] rmd) + { + for (Element propertyMetadataDescriptor : rmd) + { + if ((Names.PREFIX+":"+name).equals( + propertyMetadataDescriptor.getAttribute(Names.NAME_ATTRIBUTE))) + { + return propertyMetadataDescriptor; + } + } + throw new RuntimeException("Property MetadataDescriptor not found for attribute "+name); + } +} \ No newline at end of file diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/web.xml b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/web.xml new file mode 100644 index 0000000000..d0a9eb20a4 --- /dev/null +++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/web.xml @@ -0,0 +1,11 @@ + + + + Qpid emulator startip + QEmu + org.apache.qpid.management.wsdm.QEmuInitializer + 1 + + \ No newline at end of file -- cgit v1.2.1