Merge "Fix javadoc warnings in common concepts"
[yangtools.git] / yang / yang-data-api / src / main / java / org / opendaylight / yangtools / yang / data / api / YangInstanceIdentifier.java
index 84ebdf0f2035f30446e0098220050a80e9e7399d..c882db6693bb9b2a9b97ecb31650f8d95c94004f 100644 (file)
@@ -13,9 +13,12 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
-
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.io.Serializable;
 import java.lang.reflect.Array;
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -25,7 +28,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
-
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
 import org.opendaylight.yangtools.concepts.Builder;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.concepts.Path;
@@ -64,27 +67,44 @@ import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
  * </ul>
  *
  *
- * @see http://tools.ietf.org/html/rfc6020#section-9.13
+ * @see <a href="http://tools.ietf.org/html/rfc6020#section-9.13">RFC6020</a>
  */
 public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier>, Immutable, Serializable {
+    @SuppressWarnings("rawtypes")
+    private static final AtomicReferenceFieldUpdater<YangInstanceIdentifier, ImmutableList> LEGACYPATH_UPDATER =
+            AtomicReferenceFieldUpdater.newUpdater(YangInstanceIdentifier.class, ImmutableList.class, "legacyPath");
+    private static final AtomicReferenceFieldUpdater<YangInstanceIdentifier, String> TOSTRINGCACHE_UPDATER =
+            AtomicReferenceFieldUpdater.newUpdater(YangInstanceIdentifier.class, String.class, "toStringCache");
     private static final YangInstanceIdentifier EMPTY = trustedCreate(Collections.<PathArgument>emptyList());
+    private static final Field PATHARGUMENTS_FIELD;
 
-    private static final long serialVersionUID = 2L;
-    private final Iterable<PathArgument> pathArguments;
+    private static final long serialVersionUID = 3L;
+    private transient final Iterable<PathArgument> pathArguments;
     private final int hash;
 
-    private transient volatile ImmutableList<PathArgument> legacyPath = null;
+    private volatile ImmutableList<PathArgument> legacyPath = null;
     private transient volatile String toStringCache = null;
 
+    static {
+        final Field f;
+        try {
+            f = YangInstanceIdentifier.class.getDeclaredField("pathArguments");
+        } catch (NoSuchFieldException | SecurityException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+        f.setAccessible(true);
+
+        PATHARGUMENTS_FIELD = f;
+    }
+
     private final ImmutableList<PathArgument> getLegacyPath() {
         // Temporary variable saves a volatile read
         ImmutableList<PathArgument> ret = legacyPath;
         if (ret == null) {
-            synchronized (this) {
-                // We could have used a synchronized block, but let's just not bother
-                ret = ImmutableList.copyOf(pathArguments);
-                legacyPath = ret;
-            }
+            // We could have used a synchronized block, but the window is quite
+            // small and worst that can happen is duplicate object construction.
+            ret = ImmutableList.copyOf(pathArguments);
+            LEGACYPATH_UPDATER.lazySet(this, ret);
         }
 
         return ret;
@@ -296,19 +316,6 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
         return new BuilderImpl(origin.getPathArguments(), origin.hashCode());
     }
 
-    /**
-     * Returns new builder for InstanceIdentifier with first path argument set to {@link NodeIdentifier}.
-     *
-     * @param node QName of first {@link NodeIdentifier} path argument.
-     * @return  new builder for InstanceIdentifier with first path argument set to {@link NodeIdentifier}.
-     *
-     * @deprecated Either use {@link #node(QName)} or instantiate an intermediate builder.
-     */
-    @Deprecated
-    public static InstanceIdentifierBuilder builder(final QName node) {
-        return builder().node(node);
-    }
-
     /**
      * Path argument / component of InstanceIdentifier
      *
@@ -354,6 +361,8 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
     }
 
     private static abstract class AbstractPathArgument implements PathArgument {
+        private static final AtomicReferenceFieldUpdater<AbstractPathArgument, Integer> HASH_UPDATER =
+                AtomicReferenceFieldUpdater.newUpdater(AbstractPathArgument.class, Integer.class, "hash");
         private static final long serialVersionUID = -4546547994250849340L;
         private final QName nodeType;
         private volatile transient Integer hash = null;
@@ -380,13 +389,8 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
         public final int hashCode() {
             Integer ret = hash;
             if (ret == null) {
-                synchronized (this) {
-                    ret = hash;
-                    if (ret == null) {
-                        ret = hashCodeImpl();
-                        hash = ret;
-                    }
-                }
+                ret = hashCodeImpl();
+                HASH_UPDATER.lazySet(this, ret);
             }
 
             return ret;
@@ -603,7 +607,7 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
      * / module to the target node.
      *
      *
-     * @see http://tools.ietf.org/html/rfc6020#section-7.15
+     * @see <a href="http://tools.ietf.org/html/rfc6020#section-7.15">RFC6020</a>
      */
     public static final class AugmentationIdentifier implements PathArgument {
         private static final long serialVersionUID = -8122335594681936939L;
@@ -627,18 +631,6 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
             this.childNames = ImmutableSet.copyOf(childNames);
         }
 
-        /**
-         * Augmentation node has no QName
-         *
-         * @deprecated Use
-         *             {@link AugmentationIdentifier#AugmentationIdentifier(Set)}
-         *             instead.
-         */
-        @Deprecated
-        public AugmentationIdentifier(final QName nodeType, final Set<QName> childNames) {
-            this(childNames);
-        }
-
         /**
          * Returns set of all possible child nodes
          *
@@ -787,24 +779,41 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
          */
         String ret = toStringCache;
         if (ret == null) {
-            synchronized (this) {
-                ret = toStringCache;
-                if (ret == null) {
-                    final StringBuilder builder = new StringBuilder("/");
-                    PathArgument prev = null;
-                    for (PathArgument argument : getPathArguments()) {
-                        if (prev != null) {
-                            builder.append('/');
-                        }
-                        builder.append(argument.toRelativeString(prev));
-                        prev = argument;
-                    }
-
-                    ret = builder.toString();
-                    toStringCache = ret;
+            final StringBuilder builder = new StringBuilder("/");
+            PathArgument prev = null;
+            for (PathArgument argument : getPathArguments()) {
+                if (prev != null) {
+                    builder.append('/');
                 }
+                builder.append(argument.toRelativeString(prev));
+                prev = argument;
             }
+
+            ret = builder.toString();
+            TOSTRINGCACHE_UPDATER.lazySet(this, ret);
         }
         return ret;
     }
+
+    private void readObject(final ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
+        inputStream.defaultReadObject();
+
+        try {
+            PATHARGUMENTS_FIELD.set(this, legacyPath);
+        } catch (IllegalArgumentException | IllegalAccessException e) {
+            throw new IOException(e);
+        }
+    }
+
+    private void writeObject(final ObjectOutputStream outputStream) throws IOException {
+        /*
+         * This may look strange, but what we are doing here is side-stepping the fact
+         * that pathArguments is not generally serializable. We are forcing instantiation
+         * of the legacy path, which is an ImmutableList (thus Serializable) and write
+         * it out. The read path does the opposite -- it reads the legacyPath and then
+         * uses invocation API to set the field.
+         */
+        getLegacyPath();
+        outputStream.defaultWriteObject();
+    }
 }