1   /*
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2024, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  
15  package ch.qos.logback.classic.blackbox.joran;
16  
17  import ch.qos.logback.core.testUtil.RunnableWithCounterAndDone;
18  
19  import java.io.File;
20  import java.io.IOException;
21  
22  import static org.junit.jupiter.api.Assertions.fail;
23  
24  class UpdaterRunnable extends RunnableWithCounterAndDone {
25      private final ReconfigureOnChangeTaskTest reconfigureOnChangeTaskTest;
26      File configFile;
27      ReconfigureOnChangeTaskTest.UpdateType updateType;
28  
29      // it actually takes time for Windows to propagate file modification changes
30      // values below 100 milliseconds can be problematic the same propagation
31      // latency occurs in Linux but is even larger (>600 ms)
32      // final static int DEFAULT_SLEEP_BETWEEN_UPDATES = 60;
33  
34      final int sleepBetweenUpdates = 100;
35  
36      UpdaterRunnable(ReconfigureOnChangeTaskTest reconfigureOnChangeTaskTest, File configFile, ReconfigureOnChangeTaskTest.UpdateType updateType) {
37          this.reconfigureOnChangeTaskTest = reconfigureOnChangeTaskTest;
38          this.configFile = configFile;
39          this.updateType = updateType;
40      }
41  
42      UpdaterRunnable(ReconfigureOnChangeTaskTest reconfigureOnChangeTaskTest, File configFile) {
43          this(reconfigureOnChangeTaskTest, configFile, ReconfigureOnChangeTaskTest.UpdateType.TOUCH);
44      }
45  
46      public void run() {
47          while (!isDone()) {
48              try {
49                  Thread.sleep(sleepBetweenUpdates);
50              } catch (InterruptedException e) {
51              }
52              if (isDone()) {
53                  reconfigureOnChangeTaskTest.addInfo("Exiting Updater.run()", this);
54                  return;
55              }
56              counter++;
57              reconfigureOnChangeTaskTest.addInfo("Touching [" + configFile + "]", this);
58              switch (updateType) {
59              case TOUCH:
60                  touchFile();
61                  break;
62              case MALFORMED:
63                  try {
64                      malformedUpdate();
65                  } catch (IOException e) {
66                      e.printStackTrace();
67                      fail("malformedUpdate failed");
68                  }
69                  break;
70              case MALFORMED_INNER:
71                  try {
72                      malformedInnerUpdate();
73                  } catch (IOException e) {
74                      e.printStackTrace();
75                      fail("malformedInnerUpdate failed");
76                  }
77              }
78          }
79          reconfigureOnChangeTaskTest.addInfo("Exiting Updater.run()", this);
80      }
81  
82      private void malformedUpdate() throws IOException {
83          reconfigureOnChangeTaskTest.writeToFile(configFile,
84                          "<configuration scan=\"true\" scanPeriod=\"50 millisecond\">\n" + "  <root level=\"ERROR\">\n" + "</configuration>");
85      }
86  
87      private void malformedInnerUpdate() throws IOException {
88          reconfigureOnChangeTaskTest.writeToFile(configFile, "<included>\n" + "  <root>\n" + "</included>");
89      }
90  
91      void touchFile() {
92  
93          boolean result = configFile.setLastModified(System.currentTimeMillis());
94          if (!result)
95              reconfigureOnChangeTaskTest.addWarn(this.getClass().getName() + ".touchFile on " + configFile.toString() + " FAILED", this);
96      }
97  }