Shift Builder<P> from toInstance() to build()
[yangtools.git] / yang / yang-binding / src / main / java / org / opendaylight / yangtools / yang / binding / InstanceIdentifier.java
index b135a86234bdf8136f393cd7eb5b62f4e48e23ee..087a92c64b91f3de084af846306b6717ccca0bc0 100644 (file)
@@ -13,12 +13,17 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableCollection;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import org.opendaylight.yangtools.concepts.Builder;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.util.HashCodeBuilder;
 
 /**
  *
@@ -49,17 +54,30 @@ import org.opendaylight.yangtools.concepts.Path;
  * This would be the same as using a path like so, "/nodes/node/openflow:1" to refer to the openflow:1 node
  *
  */
-public class InstanceIdentifier<T extends DataObject> implements Path<InstanceIdentifier<? extends DataObject>>, Immutable {
+public class InstanceIdentifier<T extends DataObject> implements Path<InstanceIdentifier<? extends DataObject>>, Immutable, Serializable {
+    private static final Field PATHARGUMENTS_FIELD;
+    private static final long serialVersionUID = 2L;
     /*
      * Protected to differentiate internal and external access. Internal
      * access is required never to modify the contents. References passed
      * to outside entities have to be wrapped in an unmodifiable view.
      */
-    protected final Iterable<PathArgument> pathArguments;
+    protected transient final Iterable<PathArgument> pathArguments;
     private final Class<T> targetType;
     private final boolean wildcarded;
     private final int hash;
 
+    static {
+        final Field f;
+        try {
+            f = InstanceIdentifier.class.getDeclaredField("pathArguments");
+        } catch (NoSuchFieldException | SecurityException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+        f.setAccessible(true);
+        PATHARGUMENTS_FIELD = f;
+    }
+
     InstanceIdentifier(final Class<T> type, final Iterable<PathArgument> pathArguments, final boolean wildcarded, final int hash) {
         this.pathArguments = Preconditions.checkNotNull(pathArguments);
         this.targetType = Preconditions.checkNotNull(type);
@@ -315,10 +333,10 @@ public class InstanceIdentifier<T extends DataObject> implements Path<InstanceId
     }
 
     @SuppressWarnings("unchecked")
-    public final <N extends Identifiable<K> & ChildOf<? super T>, K extends Identifier<N>> InstanceIdentifier<N> child(
+    public final <N extends Identifiable<K> & ChildOf<? super T>, K extends Identifier<N>> KeyedInstanceIdentifier<N, K> child(
             final Class<N> listItem, final K listKey) {
         final PathArgument arg = new IdentifiableItem<>(listItem, listKey);
-        return (InstanceIdentifier<N>) childIdentifier(arg);
+        return (KeyedInstanceIdentifier<N, K>) childIdentifier(arg);
     }
 
     @SuppressWarnings("unchecked")
@@ -412,7 +430,7 @@ public class InstanceIdentifier<T extends DataObject> implements Path<InstanceId
         }
         Preconditions.checkArgument(a != null, "pathArguments may not be empty");
 
-        return trustedCreate(a, pathArguments, hashBuilder.toInstance(), wildcard);
+        return trustedCreate(a, pathArguments, hashBuilder.build(), wildcard);
     }
 
     /**
@@ -461,8 +479,13 @@ public class InstanceIdentifier<T extends DataObject> implements Path<InstanceId
      *
      * @param id instance identifier
      * @return key associated with the last component
+     * @throws IllegalArgumentException if the supplied identifier type cannot have a key.
+     * @throws NullPointerException if id is null.
      */
     public static <N extends Identifiable<K> & DataObject, K extends Identifier<N>> K keyOf(final InstanceIdentifier<N> id) {
+        Preconditions.checkNotNull(id);
+        Preconditions.checkArgument(id instanceof KeyedInstanceIdentifier, "%s does not have a key", id);
+
         @SuppressWarnings("unchecked")
         final K ret = ((KeyedInstanceIdentifier<N, K>)id).getKey();
         return ret;
@@ -494,7 +517,8 @@ public class InstanceIdentifier<T extends DataObject> implements Path<InstanceId
         Class<? extends DataObject> getType();
     }
 
-    private static abstract class AbstractPathArgument<T extends DataObject> implements PathArgument {
+    private static abstract class AbstractPathArgument<T extends DataObject> implements PathArgument, Serializable {
+        private static final long serialVersionUID = 1L;
         private final Class<T> type;
 
         protected AbstractPathArgument(final Class<T> type) {
@@ -527,7 +551,7 @@ public class InstanceIdentifier<T extends DataObject> implements Path<InstanceId
         }
 
         @Override
-        public int compareTo(PathArgument arg) {
+        public int compareTo(final PathArgument arg) {
             return type.getCanonicalName().compareTo(arg.getType().getCanonicalName());
         }
     }
@@ -539,6 +563,8 @@ public class InstanceIdentifier<T extends DataObject> implements Path<InstanceId
      * @param <T>
      */
     public static final class Item<T extends DataObject> extends AbstractPathArgument<T> {
+        private static final long serialVersionUID = 1L;
+
         public Item(final Class<T> type) {
             super(type);
         }
@@ -557,6 +583,7 @@ public class InstanceIdentifier<T extends DataObject> implements Path<InstanceId
      * @param <T> The identifier of the object
      */
     public static final class IdentifiableItem<I extends Identifiable<T> & DataObject, T extends Identifier<I>> extends AbstractPathArgument<I> {
+        private static final long serialVersionUID = 1L;
         private final T key;
 
         public IdentifiableItem(final Class<I> type, final T key) {
@@ -640,5 +667,35 @@ public class InstanceIdentifier<T extends DataObject> implements Path<InstanceId
          * @return
          */
         InstanceIdentifier<T> build();
+
+        /*
+         * @deprecated use #build()
+         */
+        @Deprecated
+        InstanceIdentifier<T> toInstance();
+    }
+
+    private void writeObject(final java.io.ObjectOutputStream out) throws IOException {
+        out.defaultWriteObject();
+        out.writeInt(Iterables.size(pathArguments));
+        for (Object o : pathArguments) {
+            out.writeObject(o);
+        }
+    }
+
+    private void readObject(final java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+
+        final int size = in.readInt();
+        final List<PathArgument> args = new ArrayList<>(size);
+        for (int i = 0; i < size; ++i) {
+            args.add((PathArgument) in.readObject());
+        }
+
+        try {
+            PATHARGUMENTS_FIELD.set(this, ImmutableList.copyOf(args));
+        } catch (IllegalArgumentException | IllegalAccessException e) {
+            throw new IOException(e);
+        }
     }
 }