BUG 3067: Added support for blocking if schema is not available.
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / md / sal / binding / impl / FutureSchema.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the terms of the Eclipse
5  * Public License v1.0 which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.md.sal.binding.impl;
9
10 import com.google.common.base.Predicate;
11 import com.google.common.base.Throwables;
12 import com.google.common.util.concurrent.SettableFuture;
13 import java.net.URI;
14 import java.util.Collection;
15 import java.util.Date;
16 import java.util.List;
17 import java.util.concurrent.CopyOnWriteArrayList;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.TimeUnit;
20 import java.util.concurrent.TimeoutException;
21 import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
22 import org.opendaylight.yangtools.yang.binding.Augmentation;
23
24 class FutureSchema implements AutoCloseable {
25
26     private final List<FutureSchemaPredicate> postponedOperations = new CopyOnWriteArrayList<>();
27     private final long duration;
28     private final TimeUnit unit;
29
30     protected FutureSchema(final long time, final TimeUnit unit) {
31         this.duration = time;
32         this.unit = unit;
33     }
34
35     void onRuntimeContextUpdated(final BindingRuntimeContext context) {
36         for (final FutureSchemaPredicate op : postponedOperations) {
37             op.unlockIfPossible(context);
38         }
39     }
40
41     long getDuration() {
42         return duration;
43     }
44
45     TimeUnit getUnit() {
46         return unit;
47     }
48
49     @Override
50     public void close() {
51         for (final FutureSchemaPredicate op : postponedOperations) {
52             op.cancel();
53         }
54     }
55
56     private static boolean isSchemaAvailable(final Class<?> clz, final BindingRuntimeContext context) {
57         final Object schema;
58         if (Augmentation.class.isAssignableFrom(clz)) {
59             schema = context.getAugmentationDefinition(clz);
60         } else {
61             schema = context.getSchemaDefinition(clz);
62         }
63         return schema != null;
64     }
65
66     boolean waitForSchema(final URI namespace, final Date revision) {
67         final FutureSchemaPredicate postponedOp = new FutureSchemaPredicate() {
68
69             @Override
70             public boolean apply(final BindingRuntimeContext input) {
71                 return input.getSchemaContext().findModuleByNamespaceAndRevision(namespace, revision) != null;
72             }
73         };
74         return postponedOp.waitForSchema();
75     }
76
77     boolean waitForSchema(final Collection<Class<?>> bindingClasses) {
78         final FutureSchemaPredicate postponedOp = new FutureSchemaPredicate() {
79
80             @Override
81             public boolean apply(final BindingRuntimeContext context) {
82                 for (final Class<?> clz : bindingClasses) {
83                     if (!isSchemaAvailable(clz, context)) {
84                         return false;
85                     }
86                 }
87                 return true;
88             }
89         };
90         return postponedOp.waitForSchema();
91     }
92
93     private abstract class FutureSchemaPredicate implements Predicate<BindingRuntimeContext> {
94
95         final boolean waitForSchema() {
96             try {
97                 schemaPromise.get(duration, unit);
98                 return true;
99             } catch (final InterruptedException | ExecutionException e) {
100                 throw Throwables.propagate(e);
101             } catch (final TimeoutException e) {
102                 return false;
103             } finally {
104                 postponedOperations.remove(this);
105             }
106         }
107
108         final void unlockIfPossible(final BindingRuntimeContext context) {
109             if (!schemaPromise.isDone() && apply(context)) {
110                 schemaPromise.set(null);
111             }
112         }
113
114         final void cancel() {
115             schemaPromise.cancel(true);
116         }
117
118         private final SettableFuture<?> schemaPromise = SettableFuture.create();
119     }
120
121 }