001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017package org.apache.logging.log4j.core.appender.rolling;
018
019import org.apache.logging.log4j.Logger;
020import org.apache.logging.log4j.core.LogEvent;
021import org.apache.logging.log4j.core.config.Configuration;
022import org.apache.logging.log4j.core.config.Scheduled;
023import org.apache.logging.log4j.core.config.plugins.Plugin;
024import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
025import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
026import org.apache.logging.log4j.core.config.plugins.PluginFactory;
027import org.apache.logging.log4j.core.util.CronExpression;
028import org.apache.logging.log4j.status.StatusLogger;
029
030import java.text.ParseException;
031import java.util.Date;
032
033/**
034 * Rolls a file over based on a cron schedule.
035 */
036@Plugin(name = "CronTriggeringPolicy", category = "Core", printObject = true)
037@Scheduled
038public final class CronTriggeringPolicy implements TriggeringPolicy {
039
040    private static Logger LOGGER = StatusLogger.getLogger();
041    private static final String defaultSchedule = "0 0 0 * * ?";
042    private RollingFileManager manager;
043    private final CronExpression cronExpression;
044    private final Configuration configuration;
045    private final boolean checkOnStartup;
046
047    private CronTriggeringPolicy(CronExpression schedule, boolean checkOnStartup, Configuration configuration) {
048        this.cronExpression = schedule;
049        this.configuration = configuration;
050        this.checkOnStartup = checkOnStartup;
051    }
052
053    /**
054     * Initializes the policy.
055     * @param aManager The RollingFileManager.
056     */
057    @Override
058    public void initialize(final RollingFileManager aManager) {
059        this.manager = aManager;
060        if (checkOnStartup) {
061            Date nextDate = cronExpression.getNextValidTimeAfter(new Date(this.manager.getFileTime()));
062            if (nextDate.getTime() < System.currentTimeMillis()) {
063                manager.rollover();
064            }
065        }
066        configuration.getScheduler().scheduleWithCron(cronExpression, new CronTrigger());
067    }
068
069    /**
070     * Determines whether a rollover should occur.
071     * @param event   A reference to the currently event.
072     * @return true if a rollover should occur.
073     */
074    @Override
075    public boolean isTriggeringEvent(final LogEvent event) {
076        return false;
077    }
078
079    public CronExpression getCronExpression() {
080        return cronExpression;
081    }
082
083    /**
084     * Creates a ScheduledTriggeringPolicy.
085     * @param configuration the Configuration.
086     * @param evaluateOnStartup check if the file should be rolled over immediately.
087     * @param schedule the cron expression.
088     * @return a ScheduledTriggeringPolicy.
089     */
090    @PluginFactory
091    public static CronTriggeringPolicy createPolicy(
092            @PluginConfiguration Configuration configuration,
093            @PluginAttribute("evaluateOnStartup") final String evaluateOnStartup,
094            @PluginAttribute("schedule") final String schedule) {
095        CronExpression cronExpression;
096        final boolean checkOnStartup = Boolean.parseBoolean(evaluateOnStartup);
097        if (schedule == null) {
098            LOGGER.info("No schedule specified, defaulting to Daily");
099            cronExpression = getSchedule(defaultSchedule);
100        } else {
101            cronExpression = getSchedule(schedule);
102            if (cronExpression == null) {
103                LOGGER.error("Invalid expression specified. Defaulting to Daily");
104                cronExpression = getSchedule(defaultSchedule);
105            }
106        }
107        return new CronTriggeringPolicy(cronExpression, checkOnStartup, configuration);
108    }
109
110    private static CronExpression getSchedule(String expression) {
111        try {
112            return new CronExpression(expression);
113        } catch (ParseException pe) {
114            LOGGER.error("Invalid cron expression - " + expression, pe);
115            return null;
116        }
117    }
118
119    @Override
120    public String toString() {
121        return "CronTriggeringPolicy(schedule=" + cronExpression.getCronExpression() + ")";
122    }
123
124    private class CronTrigger implements Runnable {
125
126        @Override
127        public void run() {
128            manager.rollover();
129        }
130    }
131
132}