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;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.Date;
18 import java.util.LinkedHashSet;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.TimeUnit;
22 import java.util.concurrent.TimeoutException;
23 import java.util.function.Predicate;
24 import javax.annotation.concurrent.GuardedBy;
25 import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
26 import org.opendaylight.yangtools.yang.binding.Augmentation;
28 abstract class FutureSchema implements AutoCloseable {
29 private static final class Waiting extends FutureSchema {
30 Waiting(final long time, final TimeUnit unit) {
35 private static final class NonWaiting extends FutureSchema {
36 NonWaiting(final long time, final TimeUnit unit) {
41 boolean addPostponedOpAndWait(final FutureSchemaPredicate postponedOp) {
46 private abstract class FutureSchemaPredicate implements Predicate<BindingRuntimeContext> {
47 private final SettableFuture<Void> schemaPromise = SettableFuture.create();
49 final boolean waitForSchema() {
51 schemaPromise.get(FutureSchema.this.duration, FutureSchema.this.unit);
53 } catch (final InterruptedException | ExecutionException e) {
54 throw new RuntimeException(e);
55 } catch (final TimeoutException e) {
58 synchronized (FutureSchema.this.postponedOperations) {
59 FutureSchema.this.postponedOperations.remove(this);
64 final void unlockIfPossible(final BindingRuntimeContext context) {
65 if (!schemaPromise.isDone() && test(context)) {
66 schemaPromise.set(null);
71 schemaPromise.cancel(true);
75 @GuardedBy("postponedOperations")
76 private final Set<FutureSchemaPredicate> postponedOperations = new LinkedHashSet<>();
77 private final long duration;
78 private final TimeUnit unit;
80 private volatile BindingRuntimeContext runtimeContext;
82 FutureSchema(final long time, final TimeUnit unit) {
84 this.unit = requireNonNull(unit);
87 static FutureSchema create(final long time, final TimeUnit unit, final boolean waitEnabled) {
88 return waitEnabled ? new Waiting(time, unit) : new NonWaiting(time, unit);
91 BindingRuntimeContext runtimeContext() {
92 final BindingRuntimeContext localRuntimeContext = runtimeContext;
93 if (localRuntimeContext != null) {
94 return localRuntimeContext;
97 if (waitForSchema(Collections.emptyList())) {
98 return runtimeContext;
101 throw new IllegalStateException("No SchemaContext is available");
104 void onRuntimeContextUpdated(final BindingRuntimeContext context) {
105 synchronized (postponedOperations) {
106 runtimeContext = context;
107 for (final FutureSchemaPredicate op : postponedOperations) {
108 op.unlockIfPossible(context);
122 public void close() {
123 synchronized (postponedOperations) {
124 postponedOperations.forEach(FutureSchemaPredicate::cancel);
128 boolean waitForSchema(final URI namespace, final Date revision) {
129 return addPostponedOpAndWait(new FutureSchemaPredicate() {
131 public boolean test(final BindingRuntimeContext input) {
132 return input.getSchemaContext().findModuleByNamespaceAndRevision(namespace, revision) != null;
137 boolean waitForSchema(final Collection<Class<?>> bindingClasses) {
138 return addPostponedOpAndWait(new FutureSchemaPredicate() {
140 public boolean test(final BindingRuntimeContext context) {
141 return bindingClasses.stream().allMatch(clz -> {
142 if (Augmentation.class.isAssignableFrom(clz)) {
143 return context.getAugmentationDefinition(clz) != null;
146 return context.getSchemaDefinition(clz) != null;
152 boolean addPostponedOpAndWait(final FutureSchemaPredicate postponedOp) {
153 synchronized (postponedOperations) {
154 postponedOperations.add(postponedOp);
156 // If the runtimeContext changed, this op may now be satisfied so check it.
157 final BindingRuntimeContext context = runtimeContext;
158 if (context != null) {
159 postponedOp.unlockIfPossible(context);
163 return postponedOp.waitForSchema();