You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by cl...@apache.org on 2018/09/26 18:51:00 UTC

activemq-artemis git commit: ARTEMIS-2095 - Typed Properties ThreadSafety

Repository: activemq-artemis
Updated Branches:
  refs/heads/2.6.x a59a5891f -> 2aa7844d5


ARTEMIS-2095 - Typed Properties ThreadSafety

(cherry picked from commit b8b89d81badf755b97846ca12beb5f9373dec31f)


Project: http://git-wip-us.apache.org/repos/asf/activemq-artemis/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-artemis/commit/2aa7844d
Tree: http://git-wip-us.apache.org/repos/asf/activemq-artemis/tree/2aa7844d
Diff: http://git-wip-us.apache.org/repos/asf/activemq-artemis/diff/2aa7844d

Branch: refs/heads/2.6.x
Commit: 2aa7844d58b21f3772c08b41344888ff8380431c
Parents: a59a589
Author: Michael André Pearce <mi...@me.com>
Authored: Wed Sep 26 16:00:01 2018 +0100
Committer: Clebert Suconic <cl...@apache.org>
Committed: Wed Sep 26 14:50:33 2018 -0400

----------------------------------------------------------------------
 .../utils/collections/TypedProperties.java      | 138 +++++++++-------
 .../utils/TypedPropertiesConcurrencyTest.java   | 162 +++++++++++++++++++
 .../artemis/jms/client/ActiveMQJMSProducer.java |  19 +--
 .../artemis/jms/client/ActiveMQMapMessage.java  |  11 +-
 .../amqp/converter/AmqpCoreConverter.java       |  24 +--
 .../amqp/converter/jms/ServerJMSMapMessage.java |  11 +-
 .../management/impl/ManagementServiceImpl.java  |   4 +-
 7 files changed, 265 insertions(+), 104 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/2aa7844d/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/TypedProperties.java
----------------------------------------------------------------------
diff --git a/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/TypedProperties.java b/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/TypedProperties.java
index aa2d551..4cf4805 100644
--- a/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/TypedProperties.java
+++ b/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/collections/TypedProperties.java
@@ -16,15 +16,17 @@
  */
 package org.apache.activemq.artemis.utils.collections;
 
+import io.netty.buffer.ByteBuf;
 import java.nio.ByteBuffer;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-
-import io.netty.buffer.ByteBuf;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 import org.apache.activemq.artemis.api.core.ActiveMQPropertyConversionException;
 import org.apache.activemq.artemis.api.core.SimpleString;
 import org.apache.activemq.artemis.logs.ActiveMQUtilBundle;
@@ -57,7 +59,7 @@ public class TypedProperties {
 
    private Map<SimpleString, PropertyValue> properties;
 
-   private volatile int size;
+   private int size;
 
    private boolean internalProperties;
 
@@ -67,11 +69,11 @@ public class TypedProperties {
    /**
     *  Return the number of properties
     * */
-   public int size() {
-      return properties.size();
+   public synchronized int size() {
+      return properties == null ? 0 : properties.size();
    }
 
-   public int getMemoryOffset() {
+   public synchronized int getMemoryOffset() {
       // The estimate is basically the encode size + 2 object references for each entry in the map
       // Note we don't include the attributes or anything else since they already included in the memory estimate
       // of the ServerMessage
@@ -86,75 +88,60 @@ public class TypedProperties {
       }
    }
 
-   public boolean hasInternalProperties() {
+   public synchronized boolean hasInternalProperties() {
       return internalProperties;
    }
 
    public void putBooleanProperty(final SimpleString key, final boolean value) {
-      checkCreateProperties();
       doPutValue(key, BooleanValue.of(value));
    }
 
    public void putByteProperty(final SimpleString key, final byte value) {
-      checkCreateProperties();
       doPutValue(key, ByteValue.valueOf(value));
    }
 
    public void putBytesProperty(final SimpleString key, final byte[] value) {
-      checkCreateProperties();
       doPutValue(key, value == null ? NullValue.INSTANCE : new BytesValue(value));
    }
 
    public void putShortProperty(final SimpleString key, final short value) {
-      checkCreateProperties();
       doPutValue(key, new ShortValue(value));
    }
 
    public void putIntProperty(final SimpleString key, final int value) {
-      checkCreateProperties();
       doPutValue(key, new IntValue(value));
    }
 
    public void putLongProperty(final SimpleString key, final long value) {
-      checkCreateProperties();
       doPutValue(key, new LongValue(value));
    }
 
    public void putFloatProperty(final SimpleString key, final float value) {
-      checkCreateProperties();
       doPutValue(key, new FloatValue(value));
    }
 
    public void putDoubleProperty(final SimpleString key, final double value) {
-      checkCreateProperties();
       doPutValue(key, new DoubleValue(value));
    }
 
    public void putSimpleStringProperty(final SimpleString key, final SimpleString value) {
-      checkCreateProperties();
       doPutValue(key, value == null ? NullValue.INSTANCE : new StringValue(value));
    }
 
    public void putNullValue(final SimpleString key) {
-      checkCreateProperties();
       doPutValue(key, NullValue.INSTANCE);
    }
 
    public void putCharProperty(final SimpleString key, final char value) {
-      checkCreateProperties();
       doPutValue(key, new CharValue(value));
    }
 
    public void putTypedProperties(final TypedProperties otherProps) {
-      if (otherProps == null || otherProps.properties == null) {
+      if (otherProps == null || otherProps == this || otherProps.properties == null) {
          return;
       }
 
-      checkCreateProperties();
-      Set<Entry<SimpleString, PropertyValue>> otherEntries = otherProps.properties.entrySet();
-      for (Entry<SimpleString, PropertyValue> otherEntry : otherEntries) {
-         doPutValue(otherEntry.getKey(), otherEntry.getValue());
-      }
+      otherProps.forEachInternal(this::doPutValue);
    }
 
    public Object getProperty(final SimpleString key) {
@@ -315,29 +302,46 @@ public class TypedProperties {
       return doRemoveProperty(key);
    }
 
-   public boolean containsProperty(final SimpleString key) {
-      if (size == 0) {
+   public synchronized boolean containsProperty(final SimpleString key) {
+      if (properties == null) {
          return false;
 
       } else {
          return properties.containsKey(key);
       }
    }
-
-   public Set<SimpleString> getPropertyNames() {
-      if (size == 0) {
+   public synchronized Set<SimpleString> getPropertyNames() {
+      if (properties == null) {
          return Collections.emptySet();
       } else {
-         return properties.keySet();
+         return new HashSet<>(properties.keySet());
+      }
+   }
+
+   public synchronized void forEachKey(Consumer<SimpleString> action) {
+      if (properties != null) {
+         properties.keySet().forEach(action::accept);
+      }
+   }
+
+   public synchronized void forEach(BiConsumer<SimpleString, Object> action) {
+      if (properties != null) {
+         properties.forEach((k, v) -> action.accept(k, v.getValue()));
+      }
+   }
+
+   private synchronized void forEachInternal(BiConsumer<SimpleString, PropertyValue> action) {
+      if (properties != null) {
+         properties.forEach(action::accept);
       }
    }
 
    public synchronized void decode(final ByteBuf buffer,
                                    final TypedPropertiesDecoderPools keyValuePools) {
       byte b = buffer.readByte();
-
       if (b == DataConstants.NULL) {
          properties = null;
+         size = 0;
       } else {
          int numHeaders = buffer.readInt();
 
@@ -416,12 +420,13 @@ public class TypedProperties {
       }
    }
 
-   public synchronized void decode(final ByteBuf buffer) {
+   public void decode(final ByteBuf buffer) {
       decode(buffer, null);
    }
 
+
    public synchronized void encode(final ByteBuf buffer) {
-      if (properties == null) {
+      if (properties == null || size == 0) {
          buffer.writeByte(DataConstants.NULL);
       } else {
          buffer.writeByte(DataConstants.NOT_NULL);
@@ -438,26 +443,26 @@ public class TypedProperties {
       }
    }
 
-   public int getEncodeSize() {
-      if (properties == null) {
+   public synchronized int getEncodeSize() {
+      if (properties == null || size == 0) {
          return DataConstants.SIZE_BYTE;
       } else {
          return DataConstants.SIZE_BYTE + DataConstants.SIZE_INT + size;
       }
    }
 
-   public void clear() {
+   public synchronized void clear() {
       if (properties != null) {
          properties.clear();
       }
+      size = 0;
    }
 
    @Override
-   public String toString() {
+   public synchronized String toString() {
       StringBuilder sb = new StringBuilder("TypedProperties[");
 
       if (properties != null) {
-
          Iterator<Entry<SimpleString, PropertyValue>> iter = properties.entrySet().iterator();
 
          while (iter.hasNext()) {
@@ -505,17 +510,15 @@ public class TypedProperties {
 
    // Private ------------------------------------------------------------------------------------
 
-   private void checkCreateProperties() {
-      if (properties == null) {
-         properties = new HashMap<>();
-      }
-   }
-
    private synchronized void doPutValue(final SimpleString key, final PropertyValue value) {
       if (key.startsWith(AMQ_PROPNAME)) {
          internalProperties = true;
       }
 
+      if (properties == null) {
+         properties = new HashMap<>();
+      }
+
       PropertyValue oldValue = properties.put(key, value);
       if (oldValue != null) {
          size += value.encodeSize() - oldValue.encodeSize();
@@ -530,23 +533,20 @@ public class TypedProperties {
       }
 
       PropertyValue val = properties.remove(key);
-
       if (val == null) {
          return null;
       } else {
          size -= SimpleString.sizeofString(key) + val.encodeSize();
-
          return val.getValue();
       }
    }
 
    private synchronized Object doGetProperty(final Object key) {
-      if (size == 0) {
+      if (properties == null) {
          return null;
       }
 
       PropertyValue val = properties.get(key);
-
       if (val == null) {
          return null;
       } else {
@@ -1003,21 +1003,41 @@ public class TypedProperties {
       }
    }
 
-   public boolean isEmpty() {
-      return properties.isEmpty();
+   public synchronized boolean isEmpty() {
+      if (properties == null) {
+         return true;
+      } else {
+         return properties.isEmpty();
+      }
+   }
+
+   public synchronized Set<String> getMapNames() {
+      if (properties == null) {
+         return Collections.emptySet();
+      } else {
+         Set<String> names = new HashSet<>(properties.size());
+         for (SimpleString name : properties.keySet()) {
+            names.add(name.toString());
+         }
+         return names;
+      }
    }
 
-   public Map<String, Object> getMap() {
-      Map<String, Object> m = new HashMap<>();
-      for (Entry<SimpleString, PropertyValue> entry : properties.entrySet()) {
-         Object val = entry.getValue().getValue();
-         if (val instanceof SimpleString) {
-            m.put(entry.getKey().toString(), ((SimpleString) val).toString());
-         } else {
-            m.put(entry.getKey().toString(), val);
+   public synchronized Map<String, Object> getMap() {
+      if (properties == null) {
+         return Collections.emptyMap();
+      } else {
+         Map<String, Object> m = new HashMap<>(properties.size());
+         for (Entry<SimpleString, PropertyValue> entry : properties.entrySet()) {
+            Object val = entry.getValue().getValue();
+            if (val instanceof SimpleString) {
+               m.put(entry.getKey().toString(), ((SimpleString) val).toString());
+            } else {
+               m.put(entry.getKey().toString(), val);
+            }
          }
+         return m;
       }
-      return m;
    }
 
    /**

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/2aa7844d/artemis-commons/src/test/java/org/apache/activemq/artemis/utils/TypedPropertiesConcurrencyTest.java
----------------------------------------------------------------------
diff --git a/artemis-commons/src/test/java/org/apache/activemq/artemis/utils/TypedPropertiesConcurrencyTest.java b/artemis-commons/src/test/java/org/apache/activemq/artemis/utils/TypedPropertiesConcurrencyTest.java
new file mode 100644
index 0000000..9e9e86a
--- /dev/null
+++ b/artemis-commons/src/test/java/org/apache/activemq/artemis/utils/TypedPropertiesConcurrencyTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.artemis.utils;
+
+
+import java.util.ConcurrentModificationException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.activemq.artemis.api.core.SimpleString;
+import org.apache.activemq.artemis.utils.collections.TypedProperties;
+import org.junit.Assert;
+import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+
+public class TypedPropertiesConcurrencyTest {
+
+   // Constructors --------------------------------------------------
+
+   // Public --------------------------------------------------------
+
+
+   private SimpleString key = SimpleString.toSimpleString("key");
+
+   @Test
+   public void testClearAndToString() throws Exception {
+      TypedProperties props = new TypedProperties();
+
+      ExecutorService executorService = Executors.newFixedThreadPool(1000);
+
+      AtomicBoolean hasError = new AtomicBoolean();
+      CountDownLatch countDownLatch = new CountDownLatch(1);
+      for (int i = 0; i < 10000; i++) {
+         int g = i;
+         executorService.submit(() -> {
+            try {
+               countDownLatch.await();
+               for (int h = 0; h < 100; h++) {
+                  props.putSimpleStringProperty(SimpleString.toSimpleString("S" + h), SimpleString.toSimpleString("hello"));
+               }
+               props.clear();
+            } catch (ConcurrentModificationException t) {
+               hasError.set(true);
+               t.printStackTrace();
+            } catch (InterruptedException e) {
+            }
+         });
+      }
+      for (int i = 0; i < 10; i++) {
+         executorService.submit( () -> {
+            try {
+               countDownLatch.await();
+               for (int k = 0; k < 1000; k++) {
+                  props.toString();
+               }
+            } catch (ConcurrentModificationException t) {
+               hasError.set(true);
+               t.printStackTrace();
+            } catch (InterruptedException e) {
+            }
+
+         });
+      }
+
+      countDownLatch.countDown();
+      Thread.sleep(1000);
+      executorService.shutdown();
+      executorService.awaitTermination(10, TimeUnit.SECONDS);
+      executorService.shutdown();
+      Assert.assertFalse(hasError.get());
+   }
+
+
+   @Test
+   public void testGetPropertyNamesClearAndToString() throws Exception {
+      TypedProperties props = new TypedProperties();
+
+      ExecutorService executorService = Executors.newFixedThreadPool(1000);
+
+      AtomicBoolean hasError = new AtomicBoolean();
+      CountDownLatch countDownLatch = new CountDownLatch(1);
+      for (int i = 0; i < 10000; i++) {
+         int g = i;
+         executorService.submit(() -> {
+            try {
+               countDownLatch.await();
+               for (int h = 0; h < 100; h++) {
+                  props.putSimpleStringProperty(SimpleString.toSimpleString("S" + h), SimpleString.toSimpleString("hello"));
+               }
+               props.getPropertyNames().clear();
+            } catch (UnsupportedOperationException uoe) {
+               //Catch this as this would be acceptable, as the set is meant to be like an enumeration so a user should not modify and should expect an implementation to protect itself..
+            } catch (ConcurrentModificationException t) {
+               hasError.set(true);
+               t.printStackTrace();
+            } catch (InterruptedException e) {
+            }
+         });
+      }
+      for (int i = 0; i < 10; i++) {
+         executorService.submit( () -> {
+            try {
+               countDownLatch.await();
+               for (int k = 0; k < 1000; k++) {
+                  props.toString();
+               }
+            } catch (ConcurrentModificationException t) {
+               hasError.set(true);
+               t.printStackTrace();
+            } catch (InterruptedException e) {
+            }
+
+         });
+      }
+
+      countDownLatch.countDown();
+      Thread.sleep(1000);
+      executorService.shutdown();
+      executorService.awaitTermination(10, TimeUnit.SECONDS);
+      executorService.shutdown();
+      Assert.assertFalse(hasError.get());
+   }
+
+
+   @Test
+   public void testEncodedSizeAfterClearIsSameAsNewTypedProperties() throws Exception {
+      TypedProperties props = new TypedProperties();
+      props.putSimpleStringProperty(SimpleString.toSimpleString("helllllloooooo"), SimpleString.toSimpleString("raaaaaaaaaaaaaaaaaaaaaaaa"));
+
+      props.clear();
+
+      assertEquals(new TypedProperties().getEncodeSize(), props.getEncodeSize());
+
+   }
+
+   @Test
+   public void testMemoryOffsetAfterClearIsSameAsNewTypedProperties() throws Exception {
+      TypedProperties props = new TypedProperties();
+      props.putSimpleStringProperty(SimpleString.toSimpleString("helllllloooooo"), SimpleString.toSimpleString("raaaaaaaaaaaaaaaaaaaaaaaa"));
+
+      props.clear();
+
+      assertEquals(new TypedProperties().getMemoryOffset(), props.getMemoryOffset());
+
+   }
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/2aa7844d/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQJMSProducer.java
----------------------------------------------------------------------
diff --git a/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQJMSProducer.java b/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQJMSProducer.java
index 965eefd..e97a3c2 100644
--- a/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQJMSProducer.java
+++ b/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQJMSProducer.java
@@ -31,7 +31,6 @@ import javax.jms.TextMessage;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -110,9 +109,13 @@ public final class ActiveMQJMSProducer implements JMSProducer {
     * @throws JMSException
     */
    private void setProperties(Message message) throws JMSException {
-      for (SimpleString name : properties.getPropertyNames()) {
-         message.setObjectProperty(name.toString(), properties.getProperty(name));
-      }
+      properties.forEach((k, v) -> {
+         try {
+            message.setObjectProperty(k.toString(), v);
+         } catch (JMSException e) {
+            throw JmsExceptionUtils.convertToRuntimeException(e);
+         }
+      });
    }
 
    @Override
@@ -511,13 +514,7 @@ public final class ActiveMQJMSProducer implements JMSProducer {
    @Override
    public Set<String> getPropertyNames() {
       try {
-         Set<SimpleString> simplePropNames = properties.getPropertyNames();
-         Set<String> propNames = new HashSet<>(simplePropNames.size());
-
-         for (SimpleString str : simplePropNames) {
-            propNames.add(str.toString());
-         }
-         return propNames;
+         return properties.getMapNames();
       } catch (ActiveMQPropertyConversionException ce) {
          throw new MessageFormatRuntimeException(ce.getMessage());
       } catch (RuntimeException e) {

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/2aa7844d/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQMapMessage.java
----------------------------------------------------------------------
diff --git a/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQMapMessage.java b/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQMapMessage.java
index 557b0b8..e0249bf 100644
--- a/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQMapMessage.java
+++ b/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQMapMessage.java
@@ -21,8 +21,6 @@ import javax.jms.MapMessage;
 import javax.jms.MessageFormatException;
 import java.util.Collections;
 import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Set;
 
 import org.apache.activemq.artemis.api.core.ActiveMQException;
 import org.apache.activemq.artemis.api.core.ActiveMQPropertyConversionException;
@@ -301,14 +299,7 @@ public class ActiveMQMapMessage extends ActiveMQMessage implements MapMessage {
 
    @Override
    public Enumeration getMapNames() throws JMSException {
-      Set<SimpleString> simplePropNames = map.getPropertyNames();
-      Set<String> propNames = new HashSet<>(simplePropNames.size());
-
-      for (SimpleString str : simplePropNames) {
-         propNames.add(str.toString());
-      }
-
-      return Collections.enumeration(propNames);
+      return Collections.enumeration(map.getMapNames());
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/2aa7844d/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/converter/AmqpCoreConverter.java
----------------------------------------------------------------------
diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/converter/AmqpCoreConverter.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/converter/AmqpCoreConverter.java
index d070579..4948e9d 100644
--- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/converter/AmqpCoreConverter.java
+++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/converter/AmqpCoreConverter.java
@@ -51,7 +51,6 @@ import javax.jms.DeliveryMode;
 import javax.jms.JMSException;
 
 import org.apache.activemq.artemis.api.core.ICoreMessage;
-import org.apache.activemq.artemis.api.core.SimpleString;
 import org.apache.activemq.artemis.core.message.impl.CoreMessageObjectPools;
 import org.apache.activemq.artemis.protocol.amqp.broker.AMQPMessage;
 import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerDestination;
@@ -176,22 +175,13 @@ public class AmqpCoreConverter {
          throw new RuntimeException("Unexpected body type: " + body.getClass());
       }
 
-      TypedProperties properties = message.getExtraProperties();
-      if (properties != null) {
-         for (SimpleString str : properties.getPropertyNames()) {
-            if (str.equals(AMQPMessage.ADDRESS_PROPERTY)) {
-               continue;
-            }
-            result.getInnerMessage().putBytesProperty(str, properties.getBytesProperty(str));
-         }
-      }
+      processExtraProperties(result, message.getExtraProperties());
 
       populateMessage(result, message.getProtonMessage());
       result.getInnerMessage().setReplyTo(message.getReplyTo());
       result.getInnerMessage().setDurable(message.isDurable());
       result.getInnerMessage().setPriority(message.getPriority());
       result.getInnerMessage().setAddress(message.getAddressSimpleString());
-
       result.encode();
 
       return result != null ? result.getInnerMessage() : null;
@@ -326,6 +316,18 @@ public class AmqpCoreConverter {
       return jms;
    }
 
+   private static ServerJMSMessage processExtraProperties(ServerJMSMessage jms, TypedProperties properties) {
+      if (properties != null) {
+         properties.forEach((k, v) -> {
+            if (!k.equals(AMQPMessage.ADDRESS_PROPERTY)) {
+               jms.getInnerMessage().putObjectProperty(k, v);
+            }
+         });
+      }
+
+      return jms;
+   }
+
    private static void setProperty(javax.jms.Message msg, String key, Object value) throws JMSException {
       if (value instanceof UnsignedLong) {
          long v = ((UnsignedLong) value).longValue();

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/2aa7844d/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/converter/jms/ServerJMSMapMessage.java
----------------------------------------------------------------------
diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/converter/jms/ServerJMSMapMessage.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/converter/jms/ServerJMSMapMessage.java
index 588b10e..9ee86af 100644
--- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/converter/jms/ServerJMSMapMessage.java
+++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/converter/jms/ServerJMSMapMessage.java
@@ -21,8 +21,6 @@ import javax.jms.MapMessage;
 import javax.jms.MessageFormatException;
 import java.util.Collections;
 import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Set;
 
 import org.apache.activemq.artemis.api.core.ActiveMQPropertyConversionException;
 import org.apache.activemq.artemis.api.core.ICoreMessage;
@@ -251,14 +249,7 @@ public final class ServerJMSMapMessage extends ServerJMSMessage implements MapMe
 
    @Override
    public Enumeration getMapNames() throws JMSException {
-      Set<SimpleString> simplePropNames = map.getPropertyNames();
-      Set<String> propNames = new HashSet<>(simplePropNames.size());
-
-      for (SimpleString str : simplePropNames) {
-         propNames.add(str.toString());
-      }
-
-      return Collections.enumeration(propNames);
+      return Collections.enumeration(map.getMapNames());
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/2aa7844d/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/impl/ManagementServiceImpl.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/impl/ManagementServiceImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/impl/ManagementServiceImpl.java
index ad888d0..ecb8d55 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/impl/ManagementServiceImpl.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/impl/ManagementServiceImpl.java
@@ -679,9 +679,7 @@ public class ManagementServiceImpl implements ManagementService {
 
                if (notification.getProperties() != null) {
                   TypedProperties props = notification.getProperties();
-                  for (SimpleString name : notification.getProperties().getPropertyNames()) {
-                     notificationMessage.putObjectProperty(name, props.getProperty(name));
-                  }
+                  props.forEach(notificationMessage::putObjectProperty);
                }
 
                notificationMessage.putStringProperty(ManagementHelper.HDR_NOTIFICATION_TYPE, new SimpleString(notification.getType().toString()));