1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.job;
17
18 import static org.codelibs.core.stream.StreamUtil.stream;
19
20 import java.io.File;
21 import java.util.ArrayList;
22 import java.util.List;
23
24 import javax.servlet.ServletContext;
25
26 import org.apache.commons.lang3.RandomStringUtils;
27 import org.apache.commons.lang3.SystemUtils;
28 import org.apache.logging.log4j.LogManager;
29 import org.apache.logging.log4j.Logger;
30 import org.codelibs.core.lang.StringUtil;
31 import org.codelibs.core.timer.TimeoutTask;
32 import org.codelibs.fess.Constants;
33 import org.codelibs.fess.exception.JobProcessingException;
34 import org.codelibs.fess.exec.ThumbnailGenerator;
35 import org.codelibs.fess.helper.ProcessHelper;
36 import org.codelibs.fess.mylasta.direction.FessConfig;
37 import org.codelibs.fess.util.ComponentUtil;
38 import org.codelibs.fess.util.InputStreamThread;
39 import org.codelibs.fess.util.JobProcess;
40 import org.codelibs.fess.util.ResourceUtil;
41
42 public class GenerateThumbnailJob extends ExecJob {
43 static final Logger logger = LogManager.getLogger(GenerateThumbnailJob.class);
44
45 protected int numOfThreads = 1;
46
47 protected boolean cleanup = false;
48
49 public GenerateThumbnailJob numOfThreads(final int numOfThreads) {
50 this.numOfThreads = numOfThreads;
51 return this;
52 }
53
54 public GenerateThumbnailJob cleanup() {
55 this.cleanup = true;
56 return this;
57 }
58
59 @Override
60 public String execute() {
61 final StringBuilder resultBuf = new StringBuilder();
62
63 if (sessionId == null) {
64 sessionId = RandomStringUtils.randomAlphabetic(15);
65 }
66 resultBuf.append("Session Id: ").append(sessionId).append("\n");
67 if (jobExecutor != null) {
68 jobExecutor.addShutdownListener(() -> ComponentUtil.getProcessHelper().destroyProcess(sessionId));
69 }
70
71 final TimeoutTask timeoutTask = createTimeoutTask();
72 try {
73 executeThumbnailGenerator();
74 } catch (final Exception e) {
75 logger.warn("Failed to generate thumbnails.", e);
76 resultBuf.append(e.getMessage()).append("\n");
77 } finally {
78 if (timeoutTask != null && !timeoutTask.isCanceled()) {
79 timeoutTask.cancel();
80 }
81 }
82
83 return resultBuf.toString();
84
85 }
86
87 protected void executeThumbnailGenerator() {
88 final List<String> cmdList = new ArrayList<>();
89 final String cpSeparator = SystemUtils.IS_OS_WINDOWS ? ";" : ":";
90 final ServletContext servletContext = ComponentUtil.getComponent(ServletContext.class);
91 final ProcessHelper processHelper = ComponentUtil.getProcessHelper();
92 final FessConfig fessConfig = ComponentUtil.getFessConfig();
93
94 cmdList.add(fessConfig.getJavaCommandPath());
95
96
97 cmdList.add("-cp");
98 final StringBuilder buf = new StringBuilder(100);
99 ResourceUtil.getOverrideConfPath().ifPresent(p -> {
100 buf.append(p);
101 buf.append(cpSeparator);
102 });
103 final String confPath = System.getProperty(Constants.FESS_CONF_PATH);
104 if (StringUtil.isNotBlank(confPath)) {
105 buf.append(confPath);
106 buf.append(cpSeparator);
107 }
108
109 buf.append("WEB-INF");
110 buf.append(File.separator);
111 buf.append("env");
112 buf.append(File.separator);
113 buf.append(getExecuteType());
114 buf.append(File.separator);
115 buf.append("resources");
116 buf.append(cpSeparator);
117
118 buf.append("WEB-INF");
119 buf.append(File.separator);
120 buf.append("classes");
121
122 final String userDir = System.getProperty("user.dir");
123 final File targetDir = new File(userDir, "target");
124 final File targetClassesDir = new File(targetDir, "classes");
125 if (targetClassesDir.isDirectory()) {
126 buf.append(cpSeparator);
127 buf.append(targetClassesDir.getAbsolutePath());
128 }
129
130 appendJarFile(cpSeparator, buf, new File(servletContext.getRealPath("/WEB-INF/lib")),
131 "WEB-INF" + File.separator + "lib" + File.separator);
132
133 appendJarFile(cpSeparator, buf, new File(servletContext.getRealPath("/WEB-INF/env/" + getExecuteType() + "/lib")),
134 "WEB-INF" + File.separator + "env" + File.separator + getExecuteType() + File.separator + "lib" + File.separator);
135
136 appendJarFile(cpSeparator, buf, new File(servletContext.getRealPath("/WEB-INF/plugin")),
137 "WEB-INF" + File.separator + "plugin" + File.separator);
138 final File targetLibDir = new File(targetDir, "fess" + File.separator + "WEB-INF" + File.separator + "lib");
139 if (targetLibDir.isDirectory()) {
140 appendJarFile(cpSeparator, buf, targetLibDir, targetLibDir.getAbsolutePath() + File.separator);
141 }
142 cmdList.add(buf.toString());
143
144 if (useLocalFesen) {
145 final String httpAddress = System.getProperty(Constants.FESS_ES_HTTP_ADDRESS);
146 if (StringUtil.isNotBlank(httpAddress)) {
147 cmdList.add("-D" + Constants.FESS_ES_HTTP_ADDRESS + "=" + httpAddress);
148 }
149 }
150
151 final String systemLastaEnv = System.getProperty("lasta.env");
152 if (StringUtil.isNotBlank(systemLastaEnv)) {
153 if ("web".equals(systemLastaEnv)) {
154 cmdList.add("-Dlasta.env=" + getExecuteType());
155 } else {
156 cmdList.add("-Dlasta.env=" + systemLastaEnv);
157 }
158 } else if (StringUtil.isNotBlank(lastaEnv)) {
159 cmdList.add("-Dlasta.env=" + lastaEnv);
160 } else {
161 cmdList.add("-Dlasta.env=" + getExecuteType());
162 }
163
164 addFessConfigProperties(cmdList);
165 addFessSystemProperties(cmdList);
166 addSystemProperty(cmdList, Constants.FESS_CONF_PATH, null, null);
167 cmdList.add("-Dfess." + getExecuteType() + ".process=true");
168 if (logFilePath == null) {
169 final String value = System.getProperty("fess.log.path");
170 logFilePath = value != null ? value : new File(targetDir, "logs").getAbsolutePath();
171 }
172 cmdList.add("-Dfess.log.path=" + logFilePath);
173 addSystemProperty(cmdList, Constants.FESS_VAR_PATH, null, null);
174 addSystemProperty(cmdList, Constants.FESS_THUMBNAIL_PATH, null, null);
175 addSystemProperty(cmdList, "fess.log.name", "fess-" + getExecuteType(), "-" + getExecuteType());
176 if (logLevel != null) {
177 cmdList.add("-Dfess.log.level=" + logLevel);
178 }
179 stream(fessConfig.getJvmThumbnailOptionsAsArray())
180 .of(stream -> stream.filter(StringUtil::isNotBlank).forEach(value -> cmdList.add(value)));
181
182 File ownTmpDir = null;
183 final String tmpDir = System.getProperty("java.io.tmpdir");
184 if (fessConfig.isUseOwnTmpDir() && StringUtil.isNotBlank(tmpDir)) {
185 ownTmpDir = new File(tmpDir, "fessTmpDir_" + sessionId);
186 if (ownTmpDir.mkdirs()) {
187 cmdList.add("-Djava.io.tmpdir=" + ownTmpDir.getAbsolutePath());
188 } else {
189 ownTmpDir = null;
190 }
191 }
192
193 if (!jvmOptions.isEmpty()) {
194 jvmOptions.stream().filter(StringUtil::isNotBlank).forEach(cmdList::add);
195 }
196
197 cmdList.add(ThumbnailGenerator.class.getCanonicalName());
198
199 cmdList.add("--sessionId");
200 cmdList.add(sessionId);
201 cmdList.add("--numOfThreads");
202 cmdList.add(Integer.toString(numOfThreads));
203 if (cleanup) {
204 cmdList.add("--cleanup");
205 }
206
207 final File propFile = ComponentUtil.getSystemHelper().createTempFile(getExecuteType() + "_", ".properties");
208 try {
209 cmdList.add("-p");
210 cmdList.add(propFile.getAbsolutePath());
211 createSystemProperties(cmdList, propFile);
212
213 final File baseDir = new File(servletContext.getRealPath("/WEB-INF")).getParentFile();
214
215 if (logger.isInfoEnabled()) {
216 logger.info("ThumbnailGenerator: \nDirectory={}\nOptions={}", baseDir, cmdList);
217 }
218
219 final JobProcess jobProcess = processHelper.startProcess(sessionId, cmdList, pb -> {
220 pb.directory(baseDir);
221 pb.redirectErrorStream(true);
222 });
223
224 final InputStreamThread it = jobProcess.getInputStreamThread();
225 it.start();
226
227 final Process currentProcess = jobProcess.getProcess();
228 currentProcess.waitFor();
229 it.join(5000);
230
231 final int exitValue = currentProcess.exitValue();
232
233 if (logger.isInfoEnabled()) {
234 logger.info("ThumbnailGenerator: Exit Code={} - Process Output:\n{}", exitValue, it.getOutput());
235 }
236 if (exitValue != 0) {
237 final StringBuilder out = new StringBuilder();
238 if (processTimeout) {
239 out.append("Process is terminated due to ").append(timeout).append(" second exceeded.\n");
240 }
241 out.append("Exit Code: ").append(exitValue).append("\nOutput:\n").append(it.getOutput());
242 throw new JobProcessingException(out.toString());
243 }
244 ComponentUtil.getPopularWordHelper().clearCache();
245 } catch (final JobProcessingException e) {
246 throw e;
247 } catch (final Exception e) {
248 throw new JobProcessingException("ThumbnailGenerator Process terminated.", e);
249 } finally {
250 try {
251 processHelper.destroyProcess(sessionId);
252 } finally {
253 if (propFile != null && !propFile.delete()) {
254 logger.warn("Failed to delete {}.", propFile.getAbsolutePath());
255 }
256 deleteTempDir(ownTmpDir);
257 }
258 }
259 }
260
261 @Override
262 protected String getExecuteType() {
263 return Constants.EXECUTE_TYPE_THUMBNAIL;
264 }
265 }