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.generator.util.BindingRuntimeContext;
23 import org.opendaylight.yangtools.yang.binding.Augmentation;
24 import org.opendaylight.yangtools.yang.common.QNameModule;
26 abstract class FutureSchema implements AutoCloseable {
27 private static final class Waiting extends FutureSchema {
28 Waiting(final long time, final TimeUnit unit) {
33 private static final class NonWaiting extends FutureSchema {
34 NonWaiting(final long time, final TimeUnit unit) {
39 boolean addPostponedOpAndWait(final FutureSchemaPredicate postponedOp) {
44 private abstract class FutureSchemaPredicate implements Predicate<BindingRuntimeContext> {
45 private final SettableFuture<Void> schemaPromise = SettableFuture.create();
47 final boolean waitForSchema() {
49 schemaPromise.get(FutureSchema.this.duration, FutureSchema.this.unit);
51 } catch (final InterruptedException | ExecutionException e) {
52 throw new IllegalStateException(e);
53 } catch (final TimeoutException e) {
56 synchronized (FutureSchema.this.postponedOperations) {
57 FutureSchema.this.postponedOperations.remove(this);
62 final void unlockIfPossible(final BindingRuntimeContext context) {
63 if (!schemaPromise.isDone() && test(context)) {
64 schemaPromise.set(null);
69 schemaPromise.cancel(true);
73 @GuardedBy("postponedOperations")
74 private final Set<FutureSchemaPredicate> postponedOperations = new LinkedHashSet<>();
75 private final long duration;
76 private final TimeUnit unit;
78 private volatile BindingRuntimeContext runtimeContext;
80 FutureSchema(final long time, final TimeUnit unit) {
82 this.unit = requireNonNull(unit);
85 static FutureSchema create(final long time, final TimeUnit unit, final boolean waitEnabled) {
86 return waitEnabled ? new Waiting(time, unit) : new NonWaiting(time, unit);
89 BindingRuntimeContext runtimeContext() {
90 final BindingRuntimeContext localRuntimeContext = runtimeContext;
91 if (localRuntimeContext != null) {
92 return localRuntimeContext;
95 if (waitForSchema(Collections.emptyList())) {
96 return runtimeContext;
99 throw new IllegalStateException("No SchemaContext is available");
102 void onRuntimeContextUpdated(final BindingRuntimeContext context) {
103 synchronized (postponedOperations) {
104 runtimeContext = context;
105 for (final FutureSchemaPredicate op : postponedOperations) {
106 op.unlockIfPossible(context);
120 public void close() {
121 synchronized (postponedOperations) {
122 postponedOperations.forEach(FutureSchemaPredicate::cancel);
126 boolean waitForSchema(final QNameModule module) {
127 return addPostponedOpAndWait(new FutureSchemaPredicate() {
129 public boolean test(final BindingRuntimeContext input) {
130 return input.getSchemaContext().findModule(module).isPresent();
135 boolean waitForSchema(final Collection<Class<?>> bindingClasses) {
136 return addPostponedOpAndWait(new FutureSchemaPredicate() {
138 public boolean test(final BindingRuntimeContext context) {
139 return bindingClasses.stream().allMatch(clz -> {
140 if (Augmentation.class.isAssignableFrom(clz)) {
141 return context.getAugmentationDefinition(clz) != null;
144 return context.getSchemaDefinition(clz) != null;
150 boolean addPostponedOpAndWait(final FutureSchemaPredicate postponedOp) {
151 synchronized (postponedOperations) {
152 postponedOperations.add(postponedOp);
154 // If the runtimeContext changed, this op may now be satisfied so check it.
155 final BindingRuntimeContext context = runtimeContext;
156 if (context != null) {
157 postponedOp.unlockIfPossible(context);
161 return postponedOp.waitForSchema();