Add augmentation() method
[yangtools.git] / yang / yang-binding / src / main / java / org / opendaylight / yangtools / yang / binding / InstanceIdentifier.java
index ed90626f29b44eb0a4ebbd3b5e8ad6647ba5eb62..a36efd77de1d423eeb5091afb204ede4b80d43e2 100644 (file)
@@ -11,67 +11,281 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.concepts.Path;
+
 /**
- * Uniquely identifies instance of data tree.
+ * Uniquely identifies data location in the overall of data tree 
+ * modeled by YANG.
  * 
  * 
  */
-public class InstanceIdentifier {
+public final class InstanceIdentifier<T extends DataObject> implements Path<InstanceIdentifier<? extends DataObject>>,Immutable {
 
     private final List<PathArgument> path;
-    private final Class<? extends DataObject> targetType;
-
-    public InstanceIdentifier(Class<? extends DataObject> type) {
-        path = Collections.emptyList();
+    private final Class<T> targetType;
+    
+    public InstanceIdentifier(Class<T> type) {
+        path = Collections.<PathArgument> singletonList(new Item<>(type));
         this.targetType = type;
     }
 
-    public InstanceIdentifier(List<PathArgument> path, Class<? extends DataObject> type) {
+    public InstanceIdentifier(List<PathArgument> path, Class<T> type) {
         this.path = Collections.<PathArgument> unmodifiableList(new ArrayList<>(path));
         this.targetType = type;
     }
 
     /**
      * 
-     * @return
+     * @return path
      */
     public List<PathArgument> getPath() {
         return this.path;
     }
 
-    public Class<?> getTargetType() {
+    public Class<T> getTargetType() {
         return this.targetType;
     }
 
+    @Override
+    public String toString() {
+        return "InstanceIdentifier [path=" + path + "]";
+    }
+
     /**
-     * Path argument of instance identifier.
-     * 
+     * Path argument of {@link InstanceIdentifier}.
+     * <p>
      * Interface which implementations are used as path components of the
-     * instance path.
-     * 
-     * @author ttkacik
-     * 
+     * path in overall data tree.
+     *
      */
-    interface PathArgument {
+    public interface PathArgument {
+
+        Class<? extends DataObject> getType();
+
+    }
+
+    public static final class Item<T extends DataObject> implements PathArgument {
+        private final Class<T> type;
+
+        public Item(Class<T> type) {
+            this.type = type;
+        }
+
+        public Class<T> getType() {
+            return type;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((type == null) ? 0 : type.hashCode());
+            return result;
+        }
 
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            Item<?> other = (Item<?>) obj;
+            if (type == null) {
+                if (other.type != null)
+                    return false;
+            } else if (!type.equals(other.type))
+                return false;
+            return true;
+        }
+        
+        @Override
+        public String toString() {
+            return type.getName();
+        }
     }
 
-    public static class IdentifiableItem<I extends Identifiable<T>, T extends Identifier<I>> implements PathArgument {
+    public static final class IdentifiableItem<I extends Identifiable<T> & DataObject, T extends Identifier<I>> implements
+            PathArgument {
 
         private final T key;
-        private final Class<? extends I> type;
+        private final Class<I> type;
 
         public IdentifiableItem(Class<I> type, T key) {
+            if (type == null)
+                throw new IllegalArgumentException("Type must not be null.");
+            if (key == null)
+                throw new IllegalArgumentException("Key must not be null.");
             this.type = type;
             this.key = key;
         }
 
-        T getKey() {
+        public T getKey() {
             return this.key;
         }
 
-        Class<? extends I> getType() {
+        @Override
+        public Class<I> getType() {
             return this.type;
         }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) {
+                return false;
+            }
+            if (obj.hashCode() != hashCode()) {
+                return false;
+            }
+            if (!(obj instanceof IdentifiableItem<?, ?>)) {
+                return false;
+            }
+            IdentifiableItem<?, ?> foreign = (IdentifiableItem<?, ?>) obj;
+            return key.equals(foreign.getKey());
+        }
+
+        @Override
+        public int hashCode() {
+            return key.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return type.getName() + "[key=" + key + "]";
+        }
+    }
+
+    public interface InstanceIdentifierBuilder<T extends DataObject> extends Builder<InstanceIdentifier<T>> {
+
+        <N extends DataObject> InstanceIdentifierBuilder<N> node(Class<N> container);
+
+        <N extends Identifiable<K> & DataObject, K extends Identifier<N>> InstanceIdentifierBuilder<N> node(
+                Class<N> listItem, K listKey);
+
+        <N extends ChildOf<? super T>> InstanceIdentifierBuilder<N> child(Class<N> container);
+        
+        <N extends Identifiable<K> & ChildOf<? super T>, K extends Identifier<N>> InstanceIdentifierBuilder<N> child(
+                Class<N> listItem, K listKey);
+
+        <N extends DataObject & Augmentation<? super T>> InstanceIdentifierBuilder<N> augmentation(Class<N> container);
+
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static InstanceIdentifierBuilder<?> builder() {
+        return new BuilderImpl();
+    }
+
+    public static <T extends DataObject> InstanceIdentifierBuilder<T> builder(InstanceIdentifier<T> basePath) {
+        return new BuilderImpl<T>(basePath.path,basePath.targetType);
+    }
+
+    private static final class BuilderImpl<T extends DataObject> implements InstanceIdentifierBuilder<T> {
+
+        private List<PathArgument> path;
+        private Class<? extends DataObject> target = null;
+
+        public BuilderImpl() {
+            this.path = new ArrayList<>();
+        }
+        
+
+        public BuilderImpl(List<? extends PathArgument> prefix,Class<? extends DataObject> target) {
+            this.path = new ArrayList<>(prefix);
+            this.target = target;
+        }
+
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        @Override
+        public InstanceIdentifier<T> toInstance() {
+            List<PathArgument> immutablePath = Collections.unmodifiableList(new ArrayList<PathArgument>(path));
+            return new InstanceIdentifier(immutablePath, target);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <N extends DataObject> InstanceIdentifierBuilder<N> node(Class<N> container) {
+            target = container;
+            path.add(new Item<N>(container));
+            return (InstanceIdentifierBuilder<N>) this;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <N extends DataObject & Identifiable<K> , K extends Identifier<N>> InstanceIdentifierBuilder<N> node(
+                Class<N> listItem, K listKey) {
+            target = listItem;
+            path.add(new IdentifiableItem<N, K>(listItem, listKey));
+            return (InstanceIdentifierBuilder<N>) this;
+        }
+        
+        @Override
+        public <N extends ChildOf<? super T>> InstanceIdentifierBuilder<N> child(Class<N> container) {
+            return node(container);
+        }
+        
+        @Override
+        public <N extends Identifiable<K> & ChildOf<? super T>, K extends Identifier<N>> InstanceIdentifierBuilder<N> child(
+                Class<N> listItem, K listKey) {
+            return node(listItem,listKey);
+        }
+
+        @Override
+        public <N extends DataObject & Augmentation<? super T>> InstanceIdentifierBuilder<N> augmentation(
+                Class<N> container) {
+            return node(container);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((path == null) ? 0 : path.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        InstanceIdentifier<?> other = (InstanceIdentifier<?>) obj;
+        if (path == null) {
+            if (other.path != null) {
+                return false;
+            }
+        } else if (!path.equals(other.path)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean contains(final InstanceIdentifier<?> other) {
+        if(other == null) {
+            throw new IllegalArgumentException("other should not be null");
+        }
+        final int localSize = this.path.size();
+        final List<PathArgument> otherPath = other.getPath();
+        if(localSize > other.path.size()) {
+            return false;
+        }
+        for(int i = 0;i<localSize;i++ ) {
+            if(!path.get(i).equals(otherPath.get(i))) {
+                return false;
+            }
+        }
+        
+        return true;
     }
 }