View Javadoc
1   /*
2    * Copyright 2012-2021 CodeLibs Project and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.codelibs.fess.exec;
17  
18  import java.io.File;
19  import java.lang.management.ManagementFactory;
20  import java.util.concurrent.ExecutorService;
21  import java.util.concurrent.Executors;
22  import java.util.concurrent.TimeUnit;
23  
24  import javax.annotation.Resource;
25  
26  import org.apache.logging.log4j.LogManager;
27  import org.apache.logging.log4j.Logger;
28  import org.codelibs.core.lang.StringUtil;
29  import org.codelibs.core.misc.DynamicProperties;
30  import org.codelibs.core.timer.TimeoutManager;
31  import org.codelibs.core.timer.TimeoutTask;
32  import org.codelibs.fesen.monitor.jvm.JvmInfo;
33  import org.codelibs.fesen.monitor.os.OsProbe;
34  import org.codelibs.fesen.monitor.process.ProcessProbe;
35  import org.codelibs.fess.Constants;
36  import org.codelibs.fess.crawler.client.FesenClient;
37  import org.codelibs.fess.es.client.SearchEngineClient;
38  import org.codelibs.fess.exception.ContainerNotAvailableException;
39  import org.codelibs.fess.timer.SystemMonitorTarget;
40  import org.codelibs.fess.util.ComponentUtil;
41  import org.kohsuke.args4j.CmdLineException;
42  import org.kohsuke.args4j.CmdLineParser;
43  import org.kohsuke.args4j.Option;
44  import org.lastaflute.di.core.external.GenericExternalContext;
45  import org.lastaflute.di.core.external.GenericExternalContextComponentDefRegister;
46  import org.lastaflute.di.core.factory.SingletonLaContainerFactory;
47  
48  public class ThumbnailGenerator {
49  
50      private static final Logger logger = LogManager.getLogger(ThumbnailGenerator.class);
51  
52      @Resource
53      public SearchEngineClient searchEngineClient;
54  
55      protected static class Options {
56          @Option(name = "-s", aliases = "--sessionId", metaVar = "sessionId", usage = "Session ID")
57          protected String sessionId;
58  
59          @Option(name = "-n", aliases = "--name", metaVar = "name", usage = "Name")
60          protected String name;
61  
62          @Option(name = "-p", aliases = "--properties", metaVar = "properties", usage = "Properties File")
63          protected String propertiesPath;
64  
65          @Option(name = "-t", aliases = "--numOfThreads", metaVar = "numOfThreads", usage = "The number of threads")
66          protected int numOfThreads = 1;
67  
68          @Option(name = "-c", aliases = "--cleanup", usage = "Clean-Up mode")
69          protected boolean cleanup;
70  
71          protected Options() {
72              // nothing
73          }
74  
75          @Override
76          public String toString() {
77              return "Options [sessionId=" + sessionId + ", name=" + name + ", propertiesPath=" + propertiesPath + ", numOfThreads="
78                      + numOfThreads + "]";
79          }
80  
81      }
82  
83      static void initializeProbes() {
84          // Force probes to be loaded
85          ProcessProbe.getInstance();
86          OsProbe.getInstance();
87          JvmInfo.jvmInfo();
88      }
89  
90      public static void main(final String[] args) {
91          final Options options = new Options();
92  
93          final CmdLineParser parser = new CmdLineParser(options);
94          try {
95              parser.parseArgument(args);
96          } catch (final CmdLineException e) {
97              System.err.println(e.getMessage());
98              System.err.println("java " + ThumbnailGenerator.class.getCanonicalName() + " [options...] arguments...");
99              parser.printUsage(System.err);
100             return;
101         }
102 
103         if (logger.isDebugEnabled()) {
104             try {
105                 ManagementFactory.getRuntimeMXBean().getInputArguments().stream().forEach(s -> logger.debug("Parameter: {}", s));
106                 System.getProperties().entrySet().stream().forEach(e -> logger.debug("Property: {}={}", e.getKey(), e.getValue()));
107                 System.getenv().entrySet().forEach(e -> logger.debug("Env: {}={}", e.getKey(), e.getValue()));
108                 logger.debug("Option: {}", options);
109             } catch (final Exception e) {
110                 // ignore
111             }
112         }
113 
114         final String httpAddress = System.getProperty(Constants.FESS_ES_HTTP_ADDRESS);
115         if (StringUtil.isNotBlank(httpAddress)) {
116             System.setProperty(FesenClient.HTTP_ADDRESS, httpAddress);
117         }
118 
119         TimeoutTask systemMonitorTask = null;
120         int exitCode;
121         try {
122             SingletonLaContainerFactory.setConfigPath("app.xml");
123             SingletonLaContainerFactory.setExternalContext(new GenericExternalContext());
124             SingletonLaContainerFactory.setExternalContextComponentDefRegister(new GenericExternalContextComponentDefRegister());
125             SingletonLaContainerFactory.init();
126 
127             final Thread shutdownCallback = new Thread("ShutdownHook") {
128                 @Override
129                 public void run() {
130                     if (logger.isDebugEnabled()) {
131                         logger.debug("Destroying LaContainer..");
132                     }
133                     destroyContainer();
134                 }
135             };
136             Runtime.getRuntime().addShutdownHook(shutdownCallback);
137 
138             systemMonitorTask = TimeoutManager.getInstance().addTimeoutTarget(new SystemMonitorTarget(),
139                     ComponentUtil.getFessConfig().getThumbnailSystemMonitorIntervalAsInteger(), true);
140 
141             final int totalCount = process(options);
142             if (totalCount != 0) {
143                 logger.info("Created {} thumbnail files.", totalCount);
144             } else {
145                 logger.info("No new thumbnails found.");
146             }
147             exitCode = 0;
148         } catch (final ContainerNotAvailableException e) {
149             if (logger.isDebugEnabled()) {
150                 logger.debug("ThumbnailGenerator is stopped.", e);
151             } else if (logger.isInfoEnabled()) {
152                 logger.info("ThumbnailGenerator is stopped.");
153             }
154             exitCode = Constants.EXIT_FAIL;
155         } catch (final Throwable t) {
156             logger.error("ThumbnailGenerator does not work correctly.", t);
157             exitCode = Constants.EXIT_FAIL;
158         } finally {
159             if (systemMonitorTask != null) {
160                 systemMonitorTask.cancel();
161             }
162             destroyContainer();
163         }
164 
165         System.exit(exitCode);
166     }
167 
168     private static void destroyContainer() {
169         TimeoutManager.getInstance().stop();
170         synchronized (SingletonLaContainerFactory.class) {
171             SingletonLaContainerFactory.destroy();
172         }
173     }
174 
175     private static int process(final Options options) {
176         final DynamicProperties systemProperties = ComponentUtil.getSystemProperties();
177 
178         if (StringUtil.isNotBlank(options.propertiesPath)) {
179             systemProperties.reload(options.propertiesPath);
180         } else {
181             try {
182                 final File propFile = ComponentUtil.getSystemHelper().createTempFile("thumbnail_", ".properties");
183                 if (propFile.delete() && logger.isDebugEnabled()) {
184                     logger.debug("Deleted a temp file: {}", propFile.getAbsolutePath());
185                 }
186                 systemProperties.reload(propFile.getAbsolutePath());
187                 propFile.deleteOnExit();
188             } catch (final Exception e) {
189                 logger.warn("Failed to create system properties file.", e);
190             }
191         }
192 
193         int totalCount = 0;
194         int count = 1;
195         final ExecutorService executorService = Executors.newFixedThreadPool(options.numOfThreads);
196         try {
197             while (count != 0) {
198                 count = ComponentUtil.getThumbnailManager().generate(executorService, options.cleanup);
199                 totalCount += count;
200             }
201             executorService.shutdown();
202             executorService.awaitTermination(60, TimeUnit.SECONDS);
203         } catch (final InterruptedException e) {
204             if (logger.isDebugEnabled()) {
205                 logger.debug("Interrupted.", e);
206             }
207         } finally {
208             executorService.shutdownNow();
209         }
210         return totalCount;
211     }
212 }