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.mdsal.binding.dom.adapter;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.util.concurrent.SettableFuture;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.LinkedHashSet;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.TimeUnit;
20 import java.util.concurrent.TimeoutException;
21 import java.util.function.Predicate;
22 import javax.annotation.concurrent.GuardedBy;
23 import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
24 import org.opendaylight.yangtools.yang.binding.Augmentation;
25 import org.opendaylight.yangtools.yang.common.QNameModule;
27 abstract class FutureSchema implements AutoCloseable {
28 private static final class Waiting extends FutureSchema {
29 Waiting(final long time, final TimeUnit unit) {
34 private static final class NonWaiting extends FutureSchema {
35 NonWaiting(final long time, final TimeUnit unit) {
40 boolean addPostponedOpAndWait(final FutureSchemaPredicate postponedOp) {
45 private abstract class FutureSchemaPredicate implements Predicate<BindingRuntimeContext> {
46 private final SettableFuture<Void> schemaPromise = SettableFuture.create();
48 final boolean waitForSchema() {
50 schemaPromise.get(FutureSchema.this.duration, FutureSchema.this.unit);
52 } catch (final InterruptedException | ExecutionException e) {
53 throw new RuntimeException(e);
54 } catch (final TimeoutException e) {
57 synchronized (FutureSchema.this.postponedOperations) {
58 FutureSchema.this.postponedOperations.remove(this);
63 final void unlockIfPossible(final BindingRuntimeContext context) {
64 if (!schemaPromise.isDone() && test(context)) {
65 schemaPromise.set(null);
70 schemaPromise.cancel(true);
74 @GuardedBy("postponedOperations")
75 private final Set<FutureSchemaPredicate> postponedOperations = new LinkedHashSet<>();
76 private final long duration;
77 private final TimeUnit unit;
79 private volatile BindingRuntimeContext runtimeContext;
81 FutureSchema(final long time, final TimeUnit unit) {
83 this.unit = requireNonNull(unit);
86 static FutureSchema create(final long time, final TimeUnit unit, final boolean waitEnabled) {
87 return waitEnabled ? new Waiting(time, unit) : new NonWaiting(time, unit);
90 BindingRuntimeContext runtimeContext() {
91 final BindingRuntimeContext localRuntimeContext = runtimeContext;
92 if (localRuntimeContext != null) {
93 return localRuntimeContext;
96 if (waitForSchema(Collections.emptyList())) {
97 return runtimeContext;
100 throw new IllegalStateException("No SchemaContext is available");
103 void onRuntimeContextUpdated(final BindingRuntimeContext context) {
104 synchronized (postponedOperations) {
105 runtimeContext = context;
106 for (final FutureSchemaPredicate op : postponedOperations) {
107 op.unlockIfPossible(context);
121 public void close() {
122 synchronized (postponedOperations) {
123 postponedOperations.forEach(FutureSchemaPredicate::cancel);
127 boolean waitForSchema(final QNameModule module) {
128 return addPostponedOpAndWait(new FutureSchemaPredicate() {
130 public boolean test(final BindingRuntimeContext input) {
131 return input.getSchemaContext().findModule(module).isPresent();
136 boolean waitForSchema(final Collection<Class<?>> bindingClasses) {
137 return addPostponedOpAndWait(new FutureSchemaPredicate() {
139 public boolean test(final BindingRuntimeContext context) {
140 return bindingClasses.stream().allMatch(clz -> {
141 if (Augmentation.class.isAssignableFrom(clz)) {
142 return context.getAugmentationDefinition(clz) != null;
145 return context.getSchemaDefinition(clz) != null;
151 boolean addPostponedOpAndWait(final FutureSchemaPredicate postponedOp) {
152 synchronized (postponedOperations) {
153 postponedOperations.add(postponedOp);
155 // If the runtimeContext changed, this op may now be satisfied so check it.
156 final BindingRuntimeContext context = runtimeContext;
157 if (context != null) {
158 postponedOp.unlockIfPossible(context);
162 return postponedOp.waitForSchema();