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.logging.log4j.LogManager;
28 import org.apache.logging.log4j.Logger;
29 import org.codelibs.core.lang.StringUtil;
30 import org.codelibs.core.timer.TimeoutTask;
31 import org.codelibs.fess.Constants;
32 import org.codelibs.fess.exception.JobProcessingException;
33 import org.codelibs.fess.helper.ProcessHelper;
34 import org.codelibs.fess.mylasta.direction.FessConfig;
35 import org.codelibs.fess.util.ComponentUtil;
36 import org.codelibs.fess.util.InputStreamThread;
37 import org.codelibs.fess.util.JobProcess;
38
39 public class PythonJob extends ExecJob {
40 static final Logger logger = LogManager.getLogger(PythonJob.class);
41
42 protected String filename;
43
44 protected List<String> argList = new ArrayList<>();
45
46 public PythonJob filename(final String filename) {
47 this.filename = filename;
48 return this;
49 }
50
51 public PythonJob arg(final String value) {
52 argList.add(value);
53 return this;
54 }
55
56 public PythonJob args(final String... values) {
57 stream(values).of(stream -> stream.forEach(argList::add));
58 return this;
59 }
60
61 @Override
62 public String execute() {
63 final StringBuilder resultBuf = new StringBuilder();
64
65 if (sessionId == null) {
66 sessionId = RandomStringUtils.randomAlphabetic(15);
67 }
68 resultBuf.append("Session Id: ").append(sessionId).append("\n");
69 if (jobExecutor != null) {
70 jobExecutor.addShutdownListener(() -> ComponentUtil.getProcessHelper().destroyProcess(sessionId));
71 }
72
73 final TimeoutTask timeoutTask = createTimeoutTask();
74 try {
75 executePython();
76 } catch (final Exception e) {
77 logger.warn("Failed to run python command.", e);
78 resultBuf.append(e.getMessage()).append("\n");
79 } finally {
80 if (timeoutTask != null && !timeoutTask.isCanceled()) {
81 timeoutTask.cancel();
82 }
83 }
84
85 return resultBuf.toString();
86
87 }
88
89 protected void executePython() {
90 final List<String> cmdList = new ArrayList<>();
91 final ServletContext servletContext = ComponentUtil.getComponent(ServletContext.class);
92 final ProcessHelper processHelper = ComponentUtil.getProcessHelper();
93 final FessConfig fessConfig = ComponentUtil.getFessConfig();
94
95 if (StringUtil.isBlank(filename)) {
96 throw new JobProcessingException("Python script is not specified.");
97 }
98
99 cmdList.add(fessConfig.getPythonCommandPath());
100
101 cmdList.add(getPyFilePath());
102
103 cmdList.addAll(argList);
104
105 try {
106
107 final File baseDir = new File(servletContext.getRealPath("/WEB-INF")).getParentFile();
108
109 if (logger.isInfoEnabled()) {
110 logger.info("Python: \nDirectory={}\nOptions={}", baseDir, cmdList);
111 }
112
113 final JobProcess jobProcess = processHelper.startProcess(sessionId, cmdList, pb -> {
114 pb.directory(baseDir);
115 pb.redirectErrorStream(true);
116 });
117
118 final InputStreamThread it = jobProcess.getInputStreamThread();
119 it.start();
120
121 final Process currentProcess = jobProcess.getProcess();
122 currentProcess.waitFor();
123 it.join(5000);
124
125 final int exitValue = currentProcess.exitValue();
126
127 if (logger.isInfoEnabled()) {
128 logger.info("Python: Exit Code={} - Process Output:\n{}", exitValue, it.getOutput());
129 }
130 if (exitValue != 0) {
131 final StringBuilder out = new StringBuilder();
132 if (processTimeout) {
133 out.append("Process is terminated due to ").append(timeout).append(" second exceeded.\n");
134 }
135 out.append("Exit Code: ").append(exitValue).append("\nOutput:\n").append(it.getOutput());
136 throw new JobProcessingException(out.toString());
137 }
138 ComponentUtil.getPopularWordHelper().clearCache();
139 } catch (final JobProcessingException e) {
140 throw e;
141 } catch (final Exception e) {
142 throw new JobProcessingException("Python Process terminated.", e);
143 } finally {
144 processHelper.destroyProcess(sessionId);
145
146 }
147 }
148
149 protected String getPyFilePath() {
150 final StringBuilder buf = new StringBuilder(100);
151 buf.append("WEB-INF");
152 buf.append(File.separator);
153 buf.append("env");
154 buf.append(File.separator);
155 buf.append(getExecuteType());
156 buf.append(File.separator);
157 buf.append("resources");
158 buf.append(File.separator);
159 buf.append(filename.replaceAll("\\.\\.+", ""));
160 return buf.toString();
161 }
162
163 @Override
164 protected String getExecuteType() {
165 return Constants.EXECUTE_TYPE_PYTHON;
166 }
167 }