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.appender.rolling.action;
18  
19  import java.nio.file.Path;
20  import java.nio.file.attribute.BasicFileAttributes;
21  import java.nio.file.attribute.FileTime;
22  import java.util.Arrays;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.Objects;
26  
27  import org.apache.logging.log4j.Logger;
28  import org.apache.logging.log4j.core.Core;
29  import org.apache.logging.log4j.core.config.plugins.Plugin;
30  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
31  import org.apache.logging.log4j.core.config.plugins.PluginElement;
32  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
33  import org.apache.logging.log4j.core.util.Clock;
34  import org.apache.logging.log4j.core.util.ClockFactory;
35  import org.apache.logging.log4j.status.StatusLogger;
36  
37  /**
38   * PathCondition that accepts paths that are older than the specified duration.
39   */
40  @Plugin(name = "IfLastModified", category = Core.CATEGORY_NAME, printObject = true)
41  public final class IfLastModified implements PathCondition {
42      private static final Logger LOGGER = StatusLogger.getLogger();
43      private static final Clock CLOCK = ClockFactory.getClock();
44  
45      private final Duration age;
46      private final PathCondition[] nestedConditions;
47  
48      private IfLastModified(final Duration age, final PathCondition[] nestedConditions) {
49          this.age = Objects.requireNonNull(age, "age");
50          this.nestedConditions = nestedConditions == null ? new PathCondition[0] : Arrays.copyOf(nestedConditions,
51                  nestedConditions.length);
52      }
53  
54      public Duration getAge() {
55          return age;
56      }
57  
58      public List<PathCondition> getNestedConditions() {
59          return Collections.unmodifiableList(Arrays.asList(nestedConditions));
60      }
61  
62      /*
63       * (non-Javadoc)
64       * 
65       * @see org.apache.logging.log4j.core.appender.rolling.action.PathCondition#accept(java.nio.file.Path,
66       * java.nio.file.Path, java.nio.file.attribute.BasicFileAttributes)
67       */
68      @Override
69      public boolean accept(final Path basePath, final Path relativePath, final BasicFileAttributes attrs) {
70          final FileTime fileTime = attrs.lastModifiedTime();
71          final long millis = fileTime.toMillis();
72          final long ageMillis = CLOCK.currentTimeMillis() - millis;
73          final boolean result = ageMillis >= age.toMillis();
74          final String match = result ? ">=" : "<";
75          final String accept = result ? "ACCEPTED" : "REJECTED";
76          LOGGER.trace("IfLastModified {}: {} ageMillis '{}' {} '{}'", accept, relativePath, ageMillis, match, age);
77          if (result) {
78              return IfAll.accept(nestedConditions, basePath, relativePath, attrs);
79          }
80          return result;
81      }
82  
83      /*
84       * (non-Javadoc)
85       * 
86       * @see org.apache.logging.log4j.core.appender.rolling.action.PathCondition#beforeFileTreeWalk()
87       */
88      @Override
89      public void beforeFileTreeWalk() {
90          IfAll.beforeFileTreeWalk(nestedConditions);
91      }
92  
93      /**
94       * Create an IfLastModified condition.
95       * 
96       * @param age The path age that is accepted by this condition. Must be a valid Duration.
97       * @param nestedConditions nested conditions to evaluate if this condition accepts a path
98       * @return An IfLastModified condition.
99       */
100     @PluginFactory
101     public static IfLastModified createAgeCondition( 
102             // @formatter:off
103             @PluginAttribute("age") final Duration age, 
104             @PluginElement("PathConditions") final PathCondition... nestedConditions) {
105             // @formatter:on
106         return new IfLastModified(age, nestedConditions);
107     }
108 
109     @Override
110     public String toString() {
111         final String nested = nestedConditions.length == 0 ? "" : " AND " + Arrays.toString(nestedConditions);
112         return "IfLastModified(age=" + age + nested + ")";
113     }
114 }