View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.config;
18  
19  import org.apache.logging.log4j.Logger;
20  import org.apache.logging.log4j.core.AbstractLifeCycle;
21  import org.apache.logging.log4j.core.async.DaemonThreadFactory;
22  import org.apache.logging.log4j.core.util.CronExpression;
23  import org.apache.logging.log4j.status.StatusLogger;
24  
25  import java.util.Date;
26  import java.util.concurrent.Callable;
27  import java.util.concurrent.ScheduledExecutorService;
28  import java.util.concurrent.ScheduledFuture;
29  import java.util.concurrent.ScheduledThreadPoolExecutor;
30  import java.util.concurrent.TimeUnit;
31  
32  /**
33   *
34   */
35  public class ConfigurationScheduler extends AbstractLifeCycle {
36  
37      private static final Logger LOGGER = StatusLogger.getLogger();
38      private static final long serialVersionUID = 4570411889877332287L;
39      private ScheduledExecutorService executorService;
40  
41      private int scheduledItems = 0;
42  
43  
44      @Override
45      public void start() {
46          super.start();
47          if (scheduledItems > 0) {
48              LOGGER.debug("Starting {} Log4j2Scheduled threads", scheduledItems);
49              if (scheduledItems > 5) {
50                  scheduledItems = 5;
51              }
52              executorService = new ScheduledThreadPoolExecutor(scheduledItems, new DaemonThreadFactory("Log4j2Scheduled-"));
53          } else {
54              LOGGER.debug("No scheduled items");
55          }
56      }
57  
58      @Override
59      public void stop() {
60          if (executorService != null) {
61              LOGGER.debug("Stopping Log4j2Scheduled threads.");
62              executorService.shutdown();
63          }
64          super.stop();
65      }
66  
67      /**
68       * Increment the number of threads in the pool.
69       */
70      public void incrementScheduledItems() {
71          if (!isStarted()) {
72              ++scheduledItems;
73          } else {
74              LOGGER.error("Attempted to increment scheduled items after start");
75          }
76      }
77  
78      /**
79       * Decrement the number of threads in the pool
80       */
81      public void decrementScheduledItems() {
82          if (!isStarted() && scheduledItems > 0) {
83              --scheduledItems;
84          }
85      }
86  
87      /**
88       * Creates and executes a ScheduledFuture that becomes enabled after the given delay.
89       * @param callable the function to execute.
90       * @param delay the time from now to delay execution.
91       * @param unit the time unit of the delay parameter.
92       * @return a ScheduledFuture that can be used to extract result or cancel.
93       *
94       */
95      public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
96          return executorService.schedule(callable, delay, unit);
97      }
98  
99      /**
100      * Creates and executes a one-shot action that becomes enabled after the given delay.
101      * @param command the task to execute.
102      * @param delay the time from now to delay execution.
103      * @param unit the time unit of the delay parameter.
104      * @return a ScheduledFuture representing pending completion of the task and whose get() method will return null
105      * upon completion.
106      */
107     public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
108         return executorService.schedule(command, delay, unit);
109     }
110 
111 
112     /**
113      * Creates and executes an action that first based on a cron expression.
114      * @param cronExpression the cron expression describing the schedule.
115      * @param command The Runnable to run,
116      * @return a ScheduledFuture representing the next time the command will run.
117      */
118     public CronScheduledFuture<?> scheduleWithCron(CronExpression cronExpression, Runnable command) {
119         CronRunnable runnable = new CronRunnable(command, cronExpression);
120         ScheduledFuture<?> future = schedule(runnable, nextFireInterval(cronExpression), TimeUnit.MILLISECONDS);
121         CronScheduledFuture<?> cronScheduledFuture = new CronScheduledFuture<>(future);
122         runnable.setScheduledFuture(cronScheduledFuture);
123         return cronScheduledFuture;
124     }
125 
126 
127     /**
128      * Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently
129      * with the given period; that is executions will commence after initialDelay then initialDelay+period,
130      * then initialDelay + 2 * period, and so on.
131      * @param command the task to execute.
132      * @param initialDelay the time to delay first execution.
133      * @param period the period between successive executions.
134      * @param unit the time unit of the initialDelay and period parameters.
135      * @return a ScheduledFuture representing pending completion of the task, and whose get() method will throw an
136      * exception upon cancellation
137      */
138     public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
139         return executorService.scheduleAtFixedRate(command, initialDelay, period, unit);
140     }
141 
142     /**
143      * Creates and executes a periodic action that becomes enabled first after the given initial delay, and
144      * subsequently with the given delay between the termination of one execution and the commencement of the next.
145      * @param command the task to execute.
146      * @param initialDelay the time to delay first execution.
147      * @param delay the delay between the termination of one execution and the commencement of the next.
148      * @param unit the time unit of the initialDelay and delay parameters
149      * @return a ScheduledFuture representing pending completion of the task, and whose get() method will throw an
150      * exception upon cancellation
151      */
152     public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
153         return executorService.scheduleWithFixedDelay(command, initialDelay, delay, unit);
154     }
155 
156     private class CronRunnable implements Runnable {
157 
158         private final CronExpression cronExpression;
159         private final Runnable runnable;
160         private CronScheduledFuture<?> scheduledFuture;
161 
162         public CronRunnable(Runnable runnable, CronExpression cronExpression) {
163             this.cronExpression = cronExpression;
164             this.runnable = runnable;
165         }
166 
167         public void setScheduledFuture(CronScheduledFuture<?> future) {
168             this.scheduledFuture = future;
169         }
170 
171         public void run() {
172             try {
173                 runnable.run();
174             } catch(Throwable ex) {
175                 LOGGER.error("Error running command", ex);
176             } finally {
177                 ScheduledFuture<?> future = schedule(this, nextFireInterval(cronExpression), TimeUnit.MILLISECONDS);
178                 scheduledFuture.setScheduledFuture(future);
179             }
180         }
181     }
182 
183     private long nextFireInterval(CronExpression cronExpression) {
184         Date now = new Date();
185         Date fireDate = cronExpression.getNextValidTimeAfter(now);
186         return fireDate.getTime() - now.getTime();
187     }
188 
189 }