Introduce NetconfTimer
[netconf.git] / protocol / netconf-common / src / main / java / org / opendaylight / netconf / common / impl / DefaultNetconfTimer.java
1 /*
2  * Copyright (c) 2024 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netconf.common.impl;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.util.concurrent.ThreadFactoryBuilder;
13 import io.netty.util.HashedWheelTimer;
14 import io.netty.util.Timeout;
15 import io.netty.util.TimerTask;
16 import java.util.concurrent.ThreadFactory;
17 import java.util.concurrent.TimeUnit;
18 import javax.annotation.PreDestroy;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21 import org.opendaylight.netconf.common.NetconfTimer;
22 import org.osgi.service.component.annotations.Activate;
23 import org.osgi.service.component.annotations.Component;
24 import org.osgi.service.component.annotations.Deactivate;
25 import org.osgi.service.metatype.annotations.AttributeDefinition;
26 import org.osgi.service.metatype.annotations.Designate;
27 import org.osgi.service.metatype.annotations.ObjectClassDefinition;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 /**
32  * Default {@link NetconfTimer}, delegating to a {@link HashedWheelTimer}.
33  */
34 @Singleton
35 @Component(service = NetconfTimer.class, configurationPid = "org.opendaylight.netconf.timer")
36 @Designate(ocd = DefaultNetconfTimer.Configuration.class)
37 public final class DefaultNetconfTimer implements NetconfTimer, AutoCloseable {
38     /**
39      * Configuration of {@link DefaultNetconfTimer}.
40      */
41     @ObjectClassDefinition
42     public @interface Configuration {
43         /**
44          * Return the duration of each timer tick in milliseconds.
45          *
46          * @return the duration of each timer tick in milliseconds
47          */
48         @AttributeDefinition(description = "Duration of each timer tick in milliseconds", min = "1")
49         long tick$_$duration$_$_millis() default 100;
50
51         /**
52          * Return the size of the timer wheel.
53          *
54          * @return the size of the timer wheel
55          */
56         @AttributeDefinition(description = "The size of the timer wheel", min = "1", max = "1073741824")
57         int ticks$_$per$_$wheel() default 512;
58     }
59
60     private static final Logger LOG = LoggerFactory.getLogger(DefaultNetconfTimer.class);
61     private static final ThreadFactory THREAD_FACTORY = new ThreadFactoryBuilder()
62         .setNameFormat("netconf-timer-%d")
63         .setDaemon(true)
64         .build();
65
66     private HashedWheelTimer delegate;
67
68     /**
69      * Default constructor. Uses default values for both tick duration and wheel size.
70      */
71     @Inject
72     public DefaultNetconfTimer() {
73         this(100, TimeUnit.MILLISECONDS, 512);
74     }
75
76     /**
77      * Low-level constructor.
78      *
79      * @param tickDuration the duration between tick
80      * @param unit the time unit of the {@code tickDuration}
81      * @param ticksPerWheel the size of the wheel
82      */
83     public DefaultNetconfTimer(final long tickDuration, final TimeUnit unit, final int ticksPerWheel) {
84         delegate = new HashedWheelTimer(THREAD_FACTORY, tickDuration, unit, ticksPerWheel);
85         LOG.info("NETCONF timer started");
86     }
87
88     /**
89      * OSGi constructor. Uses values from supplied {@link Configuration}.
90      *
91      * @param config the configuration
92      */
93     @Activate
94     public DefaultNetconfTimer(final Configuration config) {
95         this(config.tick$_$duration$_$_millis(), TimeUnit.MILLISECONDS, config.ticks$_$per$_$wheel());
96     }
97
98     @Override
99     public Timeout newTimeout(final TimerTask task, final long delay, final TimeUnit unit) {
100         final var local = delegate;
101         if (local == null) {
102             throw new IllegalStateException("Timer has already been stopped");
103         }
104         return local.newTimeout(requireNonNull(task), delay, requireNonNull(unit));
105     }
106
107     @Deactivate
108     @PreDestroy
109     @Override
110     public void close() {
111         if (delegate != null) {
112             delegate.stop();
113             delegate = null;
114             LOG.info("NETCONF timer started");
115         }
116     }
117 }