2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.md.sal.binding.impl;
11 import com.google.common.base.Predicate;
12 import com.google.common.base.Throwables;
13 import com.google.common.util.concurrent.SettableFuture;
14 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.LinkedHashSet;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.TimeUnit;
21 import java.util.concurrent.TimeoutException;
22 import javax.annotation.Nonnull;
23 import javax.annotation.concurrent.GuardedBy;
24 import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
25 import org.opendaylight.yangtools.yang.binding.Augmentation;
26 import org.opendaylight.yangtools.yang.common.QNameModule;
28 class FutureSchema implements AutoCloseable {
30 @GuardedBy(value = "postponedOperations")
31 private final Set<FutureSchemaPredicate> postponedOperations = new LinkedHashSet<>();
32 private final long duration;
33 private final TimeUnit unit;
34 private final boolean waitEnabled;
35 private volatile BindingRuntimeContext runtimeContext;
37 protected FutureSchema(final long time, final TimeUnit unit, final boolean waitEnabled) {
40 this.waitEnabled = waitEnabled;
43 BindingRuntimeContext runtimeContext() {
44 final BindingRuntimeContext localRuntimeContext = this.runtimeContext;
45 if (localRuntimeContext != null) {
46 return localRuntimeContext;
49 if (waitForSchema(Collections.emptyList())) {
50 return this.runtimeContext;
53 throw new IllegalStateException("No SchemaContext is available");
56 void onRuntimeContextUpdated(final BindingRuntimeContext context) {
57 synchronized (this.postponedOperations) {
58 this.runtimeContext = context;
59 for (final FutureSchemaPredicate op : this.postponedOperations) {
60 op.unlockIfPossible(context);
75 synchronized (this.postponedOperations) {
76 for (final FutureSchemaPredicate op : this.postponedOperations) {
82 private static boolean isSchemaAvailable(final Class<?> clz, final BindingRuntimeContext context) {
84 if (Augmentation.class.isAssignableFrom(clz)) {
85 schema = context.getAugmentationDefinition(clz);
87 schema = context.getSchemaDefinition(clz);
89 return schema != null;
92 boolean waitForSchema(final QNameModule module) {
93 return addPostponedOpAndWait(new FutureSchemaPredicate() {
95 public boolean apply(@Nonnull final BindingRuntimeContext input) {
96 return input.getSchemaContext().findModule(module).isPresent();
101 boolean waitForSchema(final Collection<Class<?>> bindingClasses) {
102 return addPostponedOpAndWait(new FutureSchemaPredicate() {
104 public boolean apply(final BindingRuntimeContext context) {
105 for (final Class<?> clz : bindingClasses) {
106 if (!isSchemaAvailable(clz, context)) {
115 private boolean addPostponedOpAndWait(final FutureSchemaPredicate postponedOp) {
116 if (!this.waitEnabled) {
120 final BindingRuntimeContext localRuntimeContext = this.runtimeContext;
121 synchronized (this.postponedOperations) {
122 this.postponedOperations.add(postponedOp);
124 // If the runtimeContext changed, this op may now be satisfied so check it.
125 if (localRuntimeContext != this.runtimeContext) {
126 postponedOp.unlockIfPossible(this.runtimeContext);
130 return postponedOp.waitForSchema();
133 private abstract class FutureSchemaPredicate implements Predicate<BindingRuntimeContext> {
135 final boolean waitForSchema() {
137 this.schemaPromise.get(FutureSchema.this.duration, FutureSchema.this.unit);
139 } catch (final InterruptedException | ExecutionException e) {
140 throw Throwables.propagate(e);
141 } catch (final TimeoutException e) {
144 synchronized (FutureSchema.this.postponedOperations) {
145 FutureSchema.this.postponedOperations.remove(this);
150 @SuppressFBWarnings(value = "NP_NONNULL_PARAM_VIOLATION", justification = "Void is the only allowed value")
151 final void unlockIfPossible(final BindingRuntimeContext context) {
152 if (!this.schemaPromise.isDone() && apply(context)) {
153 this.schemaPromise.set(null);
157 final void cancel() {
158 this.schemaPromise.cancel(true);
161 private final SettableFuture<?> schemaPromise = SettableFuture.create();