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.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.SuggestCreator;
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 SuggestJob extends ExecJob {
43  
44      private static final Logger logger = LogManager.getLogger(SuggestJob.class);
45  
46      @Override
47      public String execute() {
48          final StringBuilder resultBuf = new StringBuilder();
49  
50          if (sessionId == null) { // create session id
51              sessionId = RandomStringUtils.randomAlphabetic(15);
52          }
53          resultBuf.append("Session Id: ").append(sessionId).append("\n");
54          if (jobExecutor != null) {
55              jobExecutor.addShutdownListener(() -> ComponentUtil.getProcessHelper().destroyProcess(sessionId));
56          }
57  
58          final TimeoutTask timeoutTask = createTimeoutTask();
59          try {
60              executeSuggestCreator();
61          } catch (final Exception e) {
62              logger.warn("Failed to create suggest data.", e);
63              resultBuf.append(e.getMessage()).append("\n");
64          } finally {
65              if (timeoutTask != null && !timeoutTask.isCanceled()) {
66                  timeoutTask.cancel();
67              }
68          }
69  
70          return resultBuf.toString();
71  
72      }
73  
74      protected void executeSuggestCreator() {
75          final List<String> cmdList = new ArrayList<>();
76          final String cpSeparator = SystemUtils.IS_OS_WINDOWS ? ";" : ":";
77          final ServletContext servletContext = ComponentUtil.getComponent(ServletContext.class);
78          final ProcessHelper processHelper = ComponentUtil.getProcessHelper();
79          final FessConfig fessConfig = ComponentUtil.getFessConfig();
80  
81          cmdList.add(fessConfig.getJavaCommandPath());
82  
83          // -cp
84          cmdList.add("-cp");
85          final StringBuilder buf = new StringBuilder(100);
86          ResourceUtil.getOverrideConfPath().ifPresent(p -> {
87              buf.append(p);
88              buf.append(cpSeparator);
89          });
90          final String confPath = System.getProperty(Constants.FESS_CONF_PATH);
91          if (StringUtil.isNotBlank(confPath)) {
92              buf.append(confPath);
93              buf.append(cpSeparator);
94          }
95          // WEB-INF/env/suggest/resources
96          buf.append("WEB-INF");
97          buf.append(File.separator);
98          buf.append("env");
99          buf.append(File.separator);
100         buf.append(getExecuteType());
101         buf.append(File.separator);
102         buf.append("resources");
103         buf.append(cpSeparator);
104         // WEB-INF/classes
105         buf.append("WEB-INF");
106         buf.append(File.separator);
107         buf.append("classes");
108         // target/classes
109         final String userDir = System.getProperty("user.dir");
110         final File targetDir = new File(userDir, "target");
111         final File targetClassesDir = new File(targetDir, "classes");
112         if (targetClassesDir.isDirectory()) {
113             buf.append(cpSeparator);
114             buf.append(targetClassesDir.getAbsolutePath());
115         }
116         // WEB-INF/lib
117         appendJarFile(cpSeparator, buf, new File(servletContext.getRealPath("/WEB-INF/lib")),
118                 "WEB-INF" + File.separator + "lib" + File.separator);
119         // WEB-INF/env/suggest/lib
120         appendJarFile(cpSeparator, buf, new File(servletContext.getRealPath("/WEB-INF/env/" + getExecuteType() + "/lib")),
121                 "WEB-INF" + File.separator + "env" + File.separator + getExecuteType() + File.separator + "lib" + File.separator);
122         // WEB-INF/plugin
123         appendJarFile(cpSeparator, buf, new File(servletContext.getRealPath("/WEB-INF/plugin")),
124                 "WEB-INF" + File.separator + "plugin" + File.separator);
125         final File targetLibDir = new File(targetDir, "fess" + File.separator + "WEB-INF" + File.separator + "lib");
126         if (targetLibDir.isDirectory()) {
127             appendJarFile(cpSeparator, buf, targetLibDir, targetLibDir.getAbsolutePath() + File.separator);
128         }
129         cmdList.add(buf.toString());
130 
131         if (useLocalFesen) {
132             final String httpAddress = System.getProperty(Constants.FESS_ES_HTTP_ADDRESS);
133             if (StringUtil.isNotBlank(httpAddress)) {
134                 cmdList.add("-D" + Constants.FESS_ES_HTTP_ADDRESS + "=" + httpAddress);
135             }
136         }
137 
138         final String systemLastaEnv = System.getProperty("lasta.env");
139         if (StringUtil.isNotBlank(systemLastaEnv)) {
140             if ("web".equals(systemLastaEnv)) {
141                 cmdList.add("-Dlasta.env=" + getExecuteType());
142             } else {
143                 cmdList.add("-Dlasta.env=" + systemLastaEnv);
144             }
145         } else if (StringUtil.isNotBlank(lastaEnv)) {
146             cmdList.add("-Dlasta.env=" + lastaEnv);
147         } else {
148             cmdList.add("-Dlasta.env=" + getExecuteType());
149         }
150 
151         addFessConfigProperties(cmdList);
152         addFessSystemProperties(cmdList);
153         addSystemProperty(cmdList, Constants.FESS_CONF_PATH, null, null);
154         cmdList.add("-Dfess." + getExecuteType() + ".process=true");
155         if (logFilePath == null) {
156             final String value = System.getProperty("fess.log.path");
157             logFilePath = value != null ? value : new File(targetDir, "logs").getAbsolutePath();
158         }
159         cmdList.add("-Dfess.log.path=" + logFilePath);
160         addSystemProperty(cmdList, "fess.log.name", "fess-" + getExecuteType(), "-" + getExecuteType());
161         if (logLevel == null) {
162             addSystemProperty(cmdList, "fess.log.level", null, null);
163         } else {
164             cmdList.add("-Dfess.log.level=" + logLevel);
165         }
166         stream(fessConfig.getJvmSuggestOptionsAsArray())
167                 .of(stream -> stream.filter(StringUtil::isNotBlank).forEach(value -> cmdList.add(value)));
168 
169         File ownTmpDir = null;
170         final String tmpDir = System.getProperty("java.io.tmpdir");
171         if (fessConfig.isUseOwnTmpDir() && StringUtil.isNotBlank(tmpDir)) {
172             ownTmpDir = new File(tmpDir, "fessTmpDir_" + sessionId);
173             if (ownTmpDir.mkdirs()) {
174                 cmdList.add("-Djava.io.tmpdir=" + ownTmpDir.getAbsolutePath());
175             } else {
176                 ownTmpDir = null;
177             }
178         }
179 
180         if (!jvmOptions.isEmpty()) {
181             jvmOptions.stream().filter(StringUtil::isNotBlank).forEach(cmdList::add);
182         }
183 
184         cmdList.add(SuggestCreator.class.getCanonicalName());
185 
186         cmdList.add("--sessionId");
187         cmdList.add(sessionId);
188 
189         final File propFile = ComponentUtil.getSystemHelper().createTempFile(getExecuteType() + "_", ".properties");
190         try {
191             cmdList.add("-p");
192             cmdList.add(propFile.getAbsolutePath());
193             createSystemProperties(cmdList, propFile);
194 
195             final File baseDir = new File(servletContext.getRealPath("/WEB-INF")).getParentFile();
196 
197             if (logger.isInfoEnabled()) {
198                 logger.info("SuggestCreator: \nDirectory={}\nOptions={}", baseDir, cmdList);
199             }
200 
201             final JobProcess jobProcess = processHelper.startProcess(sessionId, cmdList, pb -> {
202                 pb.directory(baseDir);
203                 pb.redirectErrorStream(true);
204             });
205 
206             final InputStreamThread it = jobProcess.getInputStreamThread();
207             it.start();
208 
209             final Process currentProcess = jobProcess.getProcess();
210             currentProcess.waitFor();
211             it.join(5000);
212 
213             final int exitValue = currentProcess.exitValue();
214 
215             if (logger.isInfoEnabled()) {
216                 logger.info("SuggestCreator: Exit Code={} - Process Output:\n{}", exitValue, it.getOutput());
217             }
218             if (exitValue != 0) {
219                 final StringBuilder out = new StringBuilder();
220                 if (processTimeout) {
221                     out.append("Process is terminated due to ").append(timeout).append(" second exceeded.\n");
222                 }
223                 out.append("Exit Code: ").append(exitValue).append("\nOutput:\n").append(it.getOutput());
224                 throw new JobProcessingException(out.toString());
225             }
226             ComponentUtil.getPopularWordHelper().clearCache();
227         } catch (final JobProcessingException e) {
228             throw e;
229         } catch (final Exception e) {
230             throw new JobProcessingException("SuggestCreator Process terminated.", e);
231         } finally {
232             try {
233                 processHelper.destroyProcess(sessionId);
234             } finally {
235                 if (propFile != null && !propFile.delete()) {
236                     logger.warn("Failed to delete {}.", propFile.getAbsolutePath());
237                 }
238                 deleteTempDir(ownTmpDir);
239             }
240         }
241     }
242 
243     @Override
244     protected String getExecuteType() {
245         return Constants.EXECUTE_TYPE_SUGGEST;
246     }
247 
248 }