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
8 package org.opendaylight.mdsal.binding.dom.adapter;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.util.concurrent.SettableFuture;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.LinkedHashSet;
17 import java.util.concurrent.ExecutionException;
18 import java.util.concurrent.TimeUnit;
19 import java.util.concurrent.TimeoutException;
20 import java.util.function.Predicate;
21 import org.checkerframework.checker.lock.qual.GuardedBy;
22 import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext;
23 import org.opendaylight.yangtools.yang.binding.Augmentation;
24 import org.opendaylight.yangtools.yang.common.QNameModule;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
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(duration, unit);
53 } catch (final InterruptedException | ExecutionException e) {
54 throw new IllegalStateException(e);
55 } catch (final TimeoutException e) {
56 LOG.trace("Wait for {} timed out", schemaPromise, e);
59 synchronized (postponedOperations) {
60 postponedOperations.remove(this);
65 final void unlockIfPossible(final BindingRuntimeContext context) {
66 if (!schemaPromise.isDone() && test(context)) {
67 schemaPromise.set(null);
72 schemaPromise.cancel(true);
76 private static final Logger LOG = LoggerFactory.getLogger(FutureSchema.class);
78 @GuardedBy("postponedOperations")
79 private final Set<FutureSchemaPredicate> postponedOperations = new LinkedHashSet<>();
80 private final long duration;
81 private final TimeUnit unit;
83 private volatile BindingRuntimeContext runtimeContext;
85 FutureSchema(final long time, final TimeUnit unit) {
87 this.unit = requireNonNull(unit);
90 static FutureSchema create(final long time, final TimeUnit unit, final boolean waitEnabled) {
91 return waitEnabled ? new Waiting(time, unit) : new NonWaiting(time, unit);
94 BindingRuntimeContext runtimeContext() {
95 final BindingRuntimeContext localRuntimeContext = runtimeContext;
96 if (localRuntimeContext != null) {
97 return localRuntimeContext;
100 if (waitForSchema(Collections.emptyList())) {
101 return runtimeContext;
104 throw new IllegalStateException("No SchemaContext is available");
107 void onRuntimeContextUpdated(final BindingRuntimeContext context) {
108 synchronized (postponedOperations) {
109 runtimeContext = context;
110 for (final FutureSchemaPredicate op : postponedOperations) {
111 op.unlockIfPossible(context);
125 public void close() {
126 synchronized (postponedOperations) {
127 postponedOperations.forEach(FutureSchemaPredicate::cancel);
131 boolean waitForSchema(final QNameModule module) {
132 return addPostponedOpAndWait(new FutureSchemaPredicate() {
134 public boolean test(final BindingRuntimeContext input) {
135 return input.modelContext().findModule(module).isPresent();
140 boolean waitForSchema(final Collection<Class<?>> bindingClasses) {
141 return addPostponedOpAndWait(new FutureSchemaPredicate() {
143 public boolean test(final BindingRuntimeContext context) {
144 return bindingClasses.stream().allMatch(clz -> {
145 if (Augmentation.class.isAssignableFrom(clz)) {
146 return context.getAugmentationDefinition(clz.asSubclass(Augmentation.class)) != null;
149 return context.getSchemaDefinition(clz) != null;
155 boolean addPostponedOpAndWait(final FutureSchemaPredicate postponedOp) {
156 synchronized (postponedOperations) {
157 postponedOperations.add(postponedOp);
159 // If the runtimeContext changed, this op may now be satisfied so check it.
160 final BindingRuntimeContext context = runtimeContext;
161 if (context != null) {
162 postponedOp.unlockIfPossible(context);
166 return postponedOp.waitForSchema();