Adjust to yangtools-2.0.0 changes
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / md / sal / binding / impl / FutureSchema.java
index 4fa76c98d20cfc33ca1030f5f79a1ceea413aaf5..0c316e809d5e9165b536d51f10046b2d853cee52 100644 (file)
@@ -1,55 +1,79 @@
 /*
  * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
  *
- * This program and the accompanying materials are made available under the terms of the Eclipse
- * Public License v1.0 which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
+
 package org.opendaylight.controller.md.sal.binding.impl;
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Throwables;
 import com.google.common.util.concurrent.SettableFuture;
-import java.net.URI;
 import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
-import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import javax.annotation.concurrent.GuardedBy;
+import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 
 class FutureSchema implements AutoCloseable {
 
-    private final List<FutureSchemaPredicate> postponedOperations = new CopyOnWriteArrayList<>();
+    @GuardedBy(value="postponedOperations")
+    private final Set<FutureSchemaPredicate> postponedOperations = new LinkedHashSet<>();
     private final long duration;
     private final TimeUnit unit;
+    private final boolean waitEnabled;
+    private volatile BindingRuntimeContext runtimeContext;
 
-    protected FutureSchema(final long time, final TimeUnit unit) {
+    protected FutureSchema(final long time, final TimeUnit unit, final boolean waitEnabled) {
         this.duration = time;
         this.unit = unit;
+        this.waitEnabled = waitEnabled;
+    }
+
+    BindingRuntimeContext runtimeContext() {
+        final BindingRuntimeContext localRuntimeContext = this.runtimeContext;
+        if(localRuntimeContext != null) {
+            return localRuntimeContext;
+        }
+
+        if(waitForSchema(Collections.emptyList())) {
+            return this.runtimeContext;
+        }
+
+        throw new IllegalStateException("No SchemaContext is available");
     }
 
     void onRuntimeContextUpdated(final BindingRuntimeContext context) {
-        for (final FutureSchemaPredicate op : postponedOperations) {
-            op.unlockIfPossible(context);
+        synchronized(this.postponedOperations) {
+            this.runtimeContext = context;
+            for (final FutureSchemaPredicate op : this.postponedOperations) {
+                op.unlockIfPossible(context);
+            }
         }
     }
 
     long getDuration() {
-        return duration;
+        return this.duration;
     }
 
     TimeUnit getUnit() {
-        return unit;
+        return this.unit;
     }
 
     @Override
     public void close() {
-        for (final FutureSchemaPredicate op : postponedOperations) {
-            op.cancel();
+        synchronized(this.postponedOperations) {
+            for (final FutureSchemaPredicate op : this.postponedOperations) {
+                op.cancel();
+            }
         }
     }
 
@@ -63,20 +87,17 @@ class FutureSchema implements AutoCloseable {
         return schema != null;
     }
 
-    boolean waitForSchema(final URI namespace, final Date revision) {
-        final FutureSchemaPredicate postponedOp = new FutureSchemaPredicate() {
-
+    boolean waitForSchema(final QNameModule module) {
+        return addPostponedOpAndWait(new FutureSchemaPredicate() {
             @Override
             public boolean apply(final BindingRuntimeContext input) {
-                return input.getSchemaContext().findModuleByNamespaceAndRevision(namespace, revision) != null;
+                return input.getSchemaContext().findModule(module).isPresent();
             }
-        };
-        return postponedOp.waitForSchema();
+        });
     }
 
     boolean waitForSchema(final Collection<Class<?>> bindingClasses) {
-        final FutureSchemaPredicate postponedOp = new FutureSchemaPredicate() {
-
+        return addPostponedOpAndWait(new FutureSchemaPredicate() {
             @Override
             public boolean apply(final BindingRuntimeContext context) {
                 for (final Class<?> clz : bindingClasses) {
@@ -86,7 +107,24 @@ class FutureSchema implements AutoCloseable {
                 }
                 return true;
             }
-        };
+        });
+    }
+
+    private boolean addPostponedOpAndWait(final FutureSchemaPredicate postponedOp) {
+        if(!this.waitEnabled) {
+            return false;
+        }
+
+        final BindingRuntimeContext localRuntimeContext = this.runtimeContext;
+        synchronized(this.postponedOperations) {
+            this.postponedOperations.add(postponedOp);
+
+            // If the runtimeContext changed, this op may now be satisfied so check it.
+            if(localRuntimeContext != this.runtimeContext) {
+                postponedOp.unlockIfPossible(this.runtimeContext);
+            }
+        }
+
         return postponedOp.waitForSchema();
     }
 
@@ -94,25 +132,27 @@ class FutureSchema implements AutoCloseable {
 
         final boolean waitForSchema() {
             try {
-                schemaPromise.get(duration, unit);
+                this.schemaPromise.get(FutureSchema.this.duration, FutureSchema.this.unit);
                 return true;
             } catch (final InterruptedException | ExecutionException e) {
                 throw Throwables.propagate(e);
             } catch (final TimeoutException e) {
                 return false;
             } finally {
-                postponedOperations.remove(this);
+                synchronized(FutureSchema.this.postponedOperations) {
+                    FutureSchema.this.postponedOperations.remove(this);
+                }
             }
         }
 
         final void unlockIfPossible(final BindingRuntimeContext context) {
-            if (!schemaPromise.isDone() && apply(context)) {
-                schemaPromise.set(null);
+            if (!this.schemaPromise.isDone() && apply(context)) {
+                this.schemaPromise.set(null);
             }
         }
 
         final void cancel() {
-            schemaPromise.cancel(true);
+            this.schemaPromise.cancel(true);
         }
 
         private final SettableFuture<?> schemaPromise = SettableFuture.create();