/** * 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.activemq.openwire; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.net.URI; import java.net.URL; import java.util.Enumeration; import java.util.HashSet; import java.util.Set; import org.apache.activemq.command.ActiveMQDestination; import org.apache.activemq.command.ActiveMQQueue; import org.apache.activemq.command.ActiveMQTextMessage; import org.apache.activemq.command.BrokerId; import org.apache.activemq.command.BrokerInfo; import org.apache.activemq.command.ConnectionId; import org.apache.activemq.command.ConsumerId; import org.apache.activemq.command.DataStructure; import org.apache.activemq.command.LocalTransactionId; import org.apache.activemq.command.Message; import org.apache.activemq.command.MessageAck; import org.apache.activemq.command.MessageId; import org.apache.activemq.command.NetworkBridgeFilter; import org.apache.activemq.command.ProducerId; import org.apache.activemq.command.SessionId; import org.apache.activemq.command.TransactionId; import org.apache.activemq.filter.BooleanExpression; import org.apache.activemq.openwire.v1.ActiveMQTextMessageTest; import org.apache.activemq.openwire.v1.BrokerInfoTest; import org.apache.activemq.openwire.v1.MessageAckTest; import org.apache.activemq.test.TestSupport; import org.apache.activemq.util.ByteSequence; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class DataFileGeneratorTestSupport extends TestSupport { protected static final Object[] EMPTY_ARGUMENTS = {}; private static final Logger LOG = LoggerFactory.getLogger(DataFileGeneratorTestSupport.class); private static final Throwable SINGLETON_EXCEPTION = new Exception("shared exception"); private static final File MODULE_BASE_DIR; private static final File CONTROL_DIR; static { File basedir = null; try { URL resource = DataFileGeneratorTestSupport.class.getResource("DataFileGeneratorTestSupport.class"); URI baseURI = new URI(resource.toString()).resolve("../../../../.."); basedir = new File(baseURI).getCanonicalFile(); } catch (Exception e) { throw new RuntimeException(e); } MODULE_BASE_DIR = basedir; CONTROL_DIR = new File(MODULE_BASE_DIR, "src/test/resources/openwire-control"); } private int counter; private OpenWireFormat openWireformat; public void xtestControlFileIsValid() throws Exception { generateControlFile(); assertControlFileIsEqual(); } public void testGenerateAndReParsingIsTheSame() throws Exception { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); DataOutputStream ds = new DataOutputStream(buffer); Object expected = createObject(); LOG.info("Created: " + expected); openWireformat.marshal(expected, ds); ds.close(); // now lets try parse it back again ByteArrayInputStream in = new ByteArrayInputStream(buffer.toByteArray()); DataInputStream dis = new DataInputStream(in); Object actual = openWireformat.unmarshal(dis); assertBeansEqual("", new HashSet<>(), expected, actual); LOG.info("Parsed: " + actual); } protected void assertBeansEqual(String message, Set<Object> comparedObjects, Object expected, Object actual) throws Exception { assertNotNull("Actual object should be equal to: " + expected + " but was null", actual); if (comparedObjects.contains(expected)) { return; } comparedObjects.add(expected); Class<? extends Object> type = expected.getClass(); assertEquals("Should be of same type", type, actual.getClass()); BeanInfo beanInfo = Introspector.getBeanInfo(type); PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); for (int i = 0; i < descriptors.length; i++) { PropertyDescriptor descriptor = descriptors[i]; Method method = descriptor.getReadMethod(); if (method != null) { String name = descriptor.getName(); Object expectedValue = null; Object actualValue = null; try { expectedValue = method.invoke(expected, EMPTY_ARGUMENTS); actualValue = method.invoke(actual, EMPTY_ARGUMENTS); } catch (Exception e) { LOG.info("Failed to access property: " + name); } assertPropertyValuesEqual(message + name, comparedObjects, expectedValue, actualValue); } } } protected void assertPropertyValuesEqual(String name, Set<Object> comparedObjects, Object expectedValue, Object actualValue) throws Exception { String message = "Property " + name + " not equal"; if (expectedValue == null) { assertNull("Property " + name + " should be null", actualValue); } else if (expectedValue instanceof Object[]) { assertArrayEqual(message, comparedObjects, (Object[]) expectedValue, (Object[]) actualValue); } else if (expectedValue.getClass().isArray()) { assertPrimitiveArrayEqual(message, comparedObjects, expectedValue, actualValue); } else { if (expectedValue instanceof Exception) { assertExceptionsEqual(message, (Exception) expectedValue, actualValue); } else if (expectedValue instanceof ByteSequence) { assertByteSequencesEqual(message, (ByteSequence) expectedValue, actualValue); } else if (expectedValue instanceof DataStructure) { assertBeansEqual(message + name, comparedObjects, expectedValue, actualValue); } else if (expectedValue instanceof Enumeration) { assertEnumerationEqual(message + name, comparedObjects, (Enumeration<?>) expectedValue, (Enumeration<?>) actualValue); } else { assertEquals(message, expectedValue, actualValue); } } } protected void assertArrayEqual(String message, Set<Object> comparedObjects, Object[] expected, Object[] actual) throws Exception { assertEquals(message + ". Array length", expected.length, actual.length); for (int i = 0; i < expected.length; i++) { assertPropertyValuesEqual(message + ". element: " + i, comparedObjects, expected[i], actual[i]); } } protected void assertEnumerationEqual(String message, Set<Object> comparedObjects, Enumeration<?> expected, Enumeration<?> actual) throws Exception { while (expected.hasMoreElements()) { Object expectedElem = expected.nextElement(); Object actualElem = actual.nextElement(); assertPropertyValuesEqual(message + ". element: " + expectedElem, comparedObjects, expectedElem, actualElem); } } protected void assertPrimitiveArrayEqual(String message, Set<Object> comparedObjects, Object expected, Object actual) throws ArrayIndexOutOfBoundsException, IllegalArgumentException, Exception { int length = Array.getLength(expected); assertEquals(message + ". Array length", length, Array.getLength(actual)); for (int i = 0; i < length; i++) { assertPropertyValuesEqual(message + ". element: " + i, comparedObjects, Array.get(expected, i), Array.get(actual, i)); } } protected void assertByteSequencesEqual(String message, ByteSequence expected, Object actualValue) { assertTrue(message + ". Actual value should be a ByteSequence but was: " + actualValue, actualValue instanceof ByteSequence); ByteSequence actual = (ByteSequence) actualValue; int length = expected.getLength(); assertEquals(message + ". Length", length, actual.getLength()); int offset = expected.getOffset(); assertEquals(message + ". Offset", offset, actual.getOffset()); byte[] data = expected.getData(); byte[] actualData = actual.getData(); for (int i = 0; i < length; i++) { assertEquals(message + ". Offset " + i, data[offset + i], actualData[offset + i]); } } protected void assertExceptionsEqual(String message, Exception expected, Object actualValue) { assertTrue(message + ". Actual value should be an exception but was: " + actualValue, actualValue instanceof Exception); Exception actual = (Exception) actualValue; assertEquals(message, expected.getMessage(), actual.getMessage()); } @Override protected void setUp() throws Exception { super.setUp(); openWireformat = createOpenWireFormat(); } public void generateControlFile() throws Exception { CONTROL_DIR.mkdirs(); File dataFile = new File(CONTROL_DIR, getClass().getName() + ".bin"); FileOutputStream os = new FileOutputStream(dataFile); DataOutputStream ds = new DataOutputStream(os); openWireformat.marshal(createObject(), ds); ds.close(); } public InputStream generateInputStream() throws Exception { ByteArrayOutputStream os = new ByteArrayOutputStream(); DataOutputStream ds = new DataOutputStream(os); openWireformat.marshal(createObject(), ds); ds.close(); return new ByteArrayInputStream(os.toByteArray()); } public void assertControlFileIsEqual() throws Exception { File dataFile = new File(CONTROL_DIR, getClass().getName() + ".bin"); FileInputStream is1 = new FileInputStream(dataFile); int pos = 0; try { InputStream is2 = generateInputStream(); int a = is1.read(); int b = is2.read(); pos++; assertEquals("Data does not match control file: " + dataFile + " at byte position " + pos, a, b); while (a >= 0 && b >= 0) { a = is1.read(); b = is2.read(); pos++; assertEquals("Data does not match control file: " + dataFile + " at byte position " + pos, a, b); } is2.close(); } finally { is1.close(); } } protected abstract Object createObject() throws Exception; protected void populateObject(Object info) throws Exception { // empty method to allow derived classes to call super // to simplify generated code } protected OpenWireFormat createOpenWireFormat() { OpenWireFormat wf = new OpenWireFormat(); wf.setCacheEnabled(true); wf.setStackTraceEnabled(false); wf.setVersion(OpenWireFormat.DEFAULT_WIRE_VERSION); return wf; } protected BrokerId createBrokerId(String text) { return new BrokerId(text); } protected TransactionId createTransactionId(String string) { return new LocalTransactionId(createConnectionId(string), ++counter); } protected ConnectionId createConnectionId(String string) { return new ConnectionId(string); } protected SessionId createSessionId(String string) { return new SessionId(createConnectionId(string), ++counter); } protected ProducerId createProducerId(String string) { return new ProducerId(createSessionId(string), ++counter); } protected ConsumerId createConsumerId(String string) { return new ConsumerId(createSessionId(string), ++counter); } protected MessageId createMessageId(String string) { return new MessageId(createProducerId(string), ++counter); } protected ActiveMQDestination createActiveMQDestination(String string) { return new ActiveMQQueue(string); } protected Message createMessage(String string) throws Exception { ActiveMQTextMessage message = (ActiveMQTextMessage) ActiveMQTextMessageTest.SINGLETON.createObject(); message.setText(string); return message; } protected BrokerInfo createBrokerInfo(String string) throws Exception { return (BrokerInfo) BrokerInfoTest.SINGLETON.createObject(); } protected MessageAck createMessageAck(String string) throws Exception { return (MessageAck) MessageAckTest.SINGLETON.createObject(); } protected DataStructure createDataStructure(String string) throws Exception { return createBrokerInfo(string); } protected Throwable createThrowable(String string) { // we have issues with stack frames not being equal so share the same // exception each time return SINGLETON_EXCEPTION; } protected BooleanExpression createBooleanExpression(String string) { return new NetworkBridgeFilter(null, new BrokerId(string), 10, 10); } }