2 * Copyright (c) 2016 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package io.fd.honeycomb.v3po.translate.util.read;
19 import com.google.common.base.Optional;
20 import com.google.common.base.Preconditions;
21 import io.fd.honeycomb.v3po.translate.MappingContext;
22 import io.fd.honeycomb.v3po.translate.ModificationCache;
23 import io.fd.honeycomb.v3po.translate.read.ReadContext;
24 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
25 import io.fd.honeycomb.v3po.translate.read.Reader;
26 import java.io.Closeable;
27 import java.util.concurrent.ScheduledExecutorService;
28 import java.util.concurrent.ScheduledFuture;
29 import java.util.concurrent.TimeUnit;
30 import javax.annotation.Nonnegative;
31 import javax.annotation.Nonnull;
32 import org.opendaylight.yangtools.concepts.Builder;
33 import org.opendaylight.yangtools.yang.binding.DataObject;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
39 * Reader wrapper that periodically invokes a read to determine whether reads are still fully functional.
40 * In case a specific error occurs, Keep-alive failure listener gets notified.
42 public final class KeepaliveReaderWrapper<D extends DataObject, B extends Builder<D>> implements Reader<D, B>, Runnable, Closeable {
44 private static final Logger LOG = LoggerFactory.getLogger(KeepaliveReaderWrapper.class);
46 private static final NoopReadContext CTX = new NoopReadContext();
48 private final Reader<D, B> delegate;
49 private final Class<? extends Exception> exceptionType;
50 private final KeepaliveFailureListener failureListener;
51 private final ScheduledFuture<?> scheduledFuture;
54 * Create new Keepalive wrapper
56 * @param delegate underlying reader performing actual reads
57 * @param executor scheduled executor service to schedule keepalive calls
58 * @param exception type of exception used to differentiate keepalive exception from other exceptions
59 * @param delayInSeconds number of seconds to wait between keepalive calls
60 * @param failureListener listener to be called whenever a keepalive failure is detected
62 public KeepaliveReaderWrapper(@Nonnull final Reader<D, B> delegate,
63 @Nonnull final ScheduledExecutorService executor,
64 @Nonnull final Class<? extends Exception> exception,
65 @Nonnegative final int delayInSeconds,
66 @Nonnull final KeepaliveFailureListener failureListener) {
67 this.delegate = delegate;
68 this.exceptionType = exception;
69 this.failureListener = failureListener;
70 Preconditions.checkArgument(delayInSeconds > 0, "Delay cannot be < 0");
71 LOG.debug("Starting keep-alive execution on top of: {} with delay of: {} seconds", delegate, delayInSeconds);
72 scheduledFuture = executor.scheduleWithFixedDelay(this, delayInSeconds, delayInSeconds, TimeUnit.SECONDS);
76 public Optional<? extends DataObject> read(@Nonnull final InstanceIdentifier id,
77 @Nonnull final ReadContext ctx) throws ReadFailedException {
78 return delegate.read(id, ctx);
81 public void readCurrentAttributes(@Nonnull final InstanceIdentifier<D> id,
82 @Nonnull final B builder,
83 @Nonnull final ReadContext ctx) throws ReadFailedException {
84 delegate.readCurrentAttributes(id, builder, ctx);
88 public B getBuilder(final InstanceIdentifier<D> id) {
89 return delegate.getBuilder(id);
92 public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder,
93 @Nonnull final D readValue) {
94 delegate.merge(parentBuilder, readValue);
99 public InstanceIdentifier<D> getManagedDataObjectType() {
100 return delegate.getManagedDataObjectType();
105 LOG.trace("Invoking keepalive");
107 final Optional<? extends DataObject> read = read(delegate.getManagedDataObjectType(), CTX);
108 LOG.debug("Keepalive executed successfully with data: {}", read);
109 } catch (Exception e) {
110 if (exceptionType.isAssignableFrom(e.getClass())) {
111 LOG.warn("Keepalive failed. Notifying listener", e);
112 failureListener.onKeepaliveFailure();
114 LOG.warn("Keepalive failed unexpectedly", e);
115 throw new IllegalArgumentException("Unexpected failure during keep-alive execution", e);
120 public void close() {
121 // Do not interrupt, it's not our executor
122 scheduledFuture.cancel(false);
126 * Listener that gets called whenever keepalive fails as expected
128 public interface KeepaliveFailureListener {
130 void onKeepaliveFailure();
133 private static final class NoopMappingContext implements MappingContext {
135 public <T extends DataObject> Optional<T> read(@Nonnull final InstanceIdentifier<T> currentId) {
136 return Optional.absent();
140 public void delete(final InstanceIdentifier<?> path) {}
143 public <T extends DataObject> void merge(final InstanceIdentifier<T> path, final T data) {}
146 public <T extends DataObject> void put(final InstanceIdentifier<T> path, final T data) {}
149 public void close() {}
152 private static class NoopReadContext implements ReadContext {
154 private final ModificationCache modificationCache = new ModificationCache();
158 public ModificationCache getModificationCache() {
159 return modificationCache;
164 public MappingContext getMappingContext() {
165 return new NoopMappingContext();
169 public void close() {