[jboss-svn-commits] JBoss Common SVN: r3341 - jboss-logmanager/trunk/src/main/java/org/jboss/logmanager.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Wed Jul 8 20:25:58 EDT 2009


Author: david.lloyd at jboss.com
Date: 2009-07-08 20:25:58 -0400 (Wed, 08 Jul 2009)
New Revision: 3341

Modified:
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/Logger.java
Log:
Make the attachment API typesafe

Modified: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/Logger.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/Logger.java	2009-07-08 23:34:24 UTC (rev 3340)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/Logger.java	2009-07-09 00:25:58 UTC (rev 3341)
@@ -27,7 +27,8 @@
 import java.util.ResourceBundle;
 import java.util.Map;
 import java.util.HashMap;
-import java.util.IdentityHashMap;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
 import java.util.concurrent.locks.Lock;
 
@@ -69,7 +70,7 @@
     /**
      * The attachments map.
      */
-    private volatile Map<Object, Object> attachments;
+    private volatile Map<AttachmentKey, Object> attachments = Collections.emptyMap();
 
     /**
      * The atomic updater for the {@link #handlers} field.
@@ -227,14 +228,16 @@
      * Get the attachment value for a given key, or {@code null} if there is no such attachment.
      *
      * @param key the key
+     * @param <V> the attachment value type
      * @return the attachment, or {@code null} if there is none for this key
      */
-    public Object getAttachment(Object key) {
+    @SuppressWarnings({ "unchecked" })
+    public <V> V getAttachment(AttachmentKey<V> key) {
         if (key == null) {
             throw new NullPointerException("key is null");
         }
-        final Map<Object, Object> attachments = this.attachments;
-        return attachments == null ? null : attachments.get(key);
+        final Map<AttachmentKey, Object> attachments = this.attachments;
+        return (V) attachments.get(key);
     }
 
     /**
@@ -242,11 +245,13 @@
      * A strong reference is maintained to the key and value for as long as this logger exists.
      *
      * @param key the attachment key
+     * @param <V> the attachment value type
      * @param value the attachment value
      * @return the current attachment, if there is one, or {@code null} if the value was successfully attached
      * @throws SecurityException if a security manager exists and if the caller does not have {@code LoggingPermission(control)}
      */
-    public Object attachIfAbsent(Object key, Object value) throws SecurityException {
+    @SuppressWarnings({ "unchecked" })
+    public <V> V attachIfAbsent(AttachmentKey<V> key, V value) throws SecurityException {
         LogContext.checkAccess();
         if (key == null) {
             throw new NullPointerException("key is null");
@@ -254,17 +259,17 @@
         if (value == null) {
             throw new NullPointerException("value is null");
         }
-        Map<Object, Object> oldAttachments;
-        Map<Object, Object> newAttachments;
+        Map<AttachmentKey, Object> oldAttachments;
+        Map<AttachmentKey, Object> newAttachments;
         do {
             oldAttachments = attachments;
-            if (oldAttachments == null) {
-                newAttachments = new IdentityHashMap<Object, Object>();
+            if (oldAttachments.isEmpty()) {
+                newAttachments = Collections.<AttachmentKey, Object>singletonMap(key, value);
             } else {
                 if (oldAttachments.containsKey(key)) {
-                    return oldAttachments.get(key);
+                    return (V) oldAttachments.get(key);
                 }
-                newAttachments = new IdentityHashMap<Object, Object>(oldAttachments);
+                newAttachments = new HashMap<AttachmentKey, Object>(oldAttachments);
             }
             newAttachments.put(key, value);
         } while (! attachmentsUpdater.compareAndSet(this, oldAttachments, newAttachments));
@@ -275,33 +280,40 @@
      * Remove an attachment.
      *
      * @param key the attachment key
+     * @param <V> the attachment value type
      * @return the old value, or {@code null} if there was none
      * @throws SecurityException if a security manager exists and if the caller does not have {@code LoggingPermission(control)}
      */
-    public Object detach(Object key) throws SecurityException {
+    @SuppressWarnings({ "unchecked" })
+    public <V> V detach(AttachmentKey<V> key) throws SecurityException {
         LogContext.checkAccess();
         if (key == null) {
             throw new NullPointerException("key is null");
         }
-        Map<Object, Object> oldAttachments;
-        Map<Object, Object> newAttachments;
-        Object result;
+        Map<AttachmentKey, Object> oldAttachments;
+        Map<AttachmentKey, Object> newAttachments;
+        V result;
         do {
             oldAttachments = attachments;
-            if (oldAttachments == null) {
+            result = (V) oldAttachments.get(key);
+            if (result == null) {
                 return null;
+            }
+            if (oldAttachments.size() == 1) {
+                // special case - the new map is empty
+                newAttachments = Collections.emptyMap();
+            } else if (oldAttachments.size() == 2) {
+                // special case - the new map is a singleton
+                final Iterator<Map.Entry<AttachmentKey,Object>> it = oldAttachments.entrySet().iterator();
+                // find the entry that we are not removing
+                Map.Entry<AttachmentKey, Object> entry = it.next();
+                if (entry.getKey() == key) {
+                    // must be the next one
+                    entry = it.next();
+                }
+                newAttachments = Collections.singletonMap(entry.getKey(), entry.getValue());
             } else {
-                if (! oldAttachments.containsKey(key)) {
-                    return null;
-                }
-                if (oldAttachments.size() == 1) {
-                    // special case - the new map is empty
-                    newAttachments = null;
-                    result = oldAttachments.get(key);
-                } else {
-                    newAttachments = new IdentityHashMap<Object, Object>(oldAttachments);
-                    result = newAttachments.remove(key);
-                }
+                newAttachments = new HashMap<AttachmentKey, Object>(oldAttachments);
             }
         } while (! attachmentsUpdater.compareAndSet(this, oldAttachments, newAttachments));
         return result;
@@ -777,4 +789,12 @@
     public void logRaw(final LogRecord record) {
         logRaw((record instanceof ExtLogRecord) ? (ExtLogRecord) record : new ExtLogRecord(record, LOGGER_CLASS_NAME));
     }
+
+    /**
+     * An attachment key instance.
+     *
+     * @param <V> the attachment value type
+     */
+    public static final class AttachmentKey<V> {
+    }
 }




More information about the jboss-svn-commits mailing list