1
2
3
4
5
6
7
8
9
10
11 package psiprobe.controllers.deploy;
12
13 import com.google.common.base.Strings;
14
15 import jakarta.servlet.http.HttpServletRequest;
16 import jakarta.servlet.http.HttpServletResponse;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.nio.file.Files;
21 import java.nio.file.Path;
22 import java.time.Duration;
23
24 import org.apache.catalina.Context;
25 import org.apache.commons.io.FileUtils;
26 import org.apache.commons.io.FilenameUtils;
27 import org.apache.commons.io.file.PathUtils;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30 import org.springframework.beans.factory.annotation.Value;
31 import org.springframework.security.core.Authentication;
32 import org.springframework.security.core.context.SecurityContextHolder;
33 import org.springframework.stereotype.Controller;
34 import org.springframework.web.bind.annotation.GetMapping;
35 import org.springframework.web.bind.annotation.PostMapping;
36 import org.springframework.web.bind.annotation.RequestParam;
37 import org.springframework.web.multipart.MultipartFile;
38 import org.springframework.web.servlet.ModelAndView;
39 import org.springframework.web.servlet.view.InternalResourceView;
40
41 import psiprobe.controllers.AbstractTomcatContainerController;
42 import psiprobe.controllers.jsp.DisplayJspController;
43 import psiprobe.model.jsp.Summary;
44
45
46
47
48 @Controller
49 public class UploadWarController extends AbstractTomcatContainerController {
50
51
52 private static final Logger logger = LoggerFactory.getLogger(UploadWarController.class);
53
54
55 private static final int MAXSECONDS_WAITFOR_CONTEXT = 10;
56
57 @GetMapping("/adm/war.htm")
58 @Override
59 public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
60 throws Exception {
61 return super.handleRequest(request, response);
62 }
63
64 @Override
65 protected ModelAndView handleRequestInternal(HttpServletRequest request,
66 HttpServletResponse response) throws Exception {
67 return new ModelAndView(new InternalResourceView(getViewName()));
68 }
69
70 @PostMapping("/adm/war.htm")
71 public ModelAndView handleUpload(@RequestParam("war") MultipartFile file,
72 @RequestParam(value = "context", required = false) String contextName,
73 @RequestParam(value = "update", required = false) String updateParam,
74 @RequestParam(value = "compile", required = false) String compileParam,
75 @RequestParam(value = "discard", required = false) String discardParam,
76 HttpServletRequest request) throws Exception {
77
78 String errMsg = null;
79
80
81 if (file == null || file.isEmpty()) {
82 errMsg = getMessageSourceAccessor().getMessage("probe.src.deploy.war.notWar.failure")
83 + " [null or empty]";
84 request.setAttribute("errorMessage", errMsg);
85 return new ModelAndView(new InternalResourceView(getViewName()));
86 }
87
88
89 Path tmpPath = null;
90 try {
91 String fileName = file.getOriginalFilename();
92 if (!Strings.isNullOrEmpty(fileName)) {
93 fileName = FilenameUtils.getName(fileName);
94 tmpPath = Path.of(System.getProperty("java.io.tmpdir"), fileName);
95 file.transferTo(tmpPath);
96 } else {
97 errMsg = getMessageSourceAccessor().getMessage("probe.src.deploy.war.notWar.failure")
98 + " [null or empty]";
99 request.setAttribute("errorMessage", errMsg);
100 return new ModelAndView(new InternalResourceView(getViewName()));
101 }
102 } catch (IOException e) {
103 logger.error("Could not process file upload", e);
104 request.setAttribute("errorMessage", getMessageSourceAccessor()
105 .getMessage("probe.src.deploy.war.uploadfailure", new Object[] {e.getMessage()}));
106
107 Files.delete(tmpPath);
108 return new ModelAndView(new InternalResourceView(getViewName()));
109 }
110
111 if (!tmpPath.getFileName().toString().endsWith(".war")) {
112 errMsg = getMessageSourceAccessor().getMessage("probe.src.deploy.war.notWar.failure") + " ["
113 + tmpPath.getFileName() + "]";
114 request.setAttribute("errorMessage", errMsg);
115 return new ModelAndView(new InternalResourceView(getViewName()));
116 }
117
118 if (contextName == null || contextName.isEmpty()) {
119 String warFileName = tmpPath.getFileName().toString().replaceAll("\\.war$", "");
120 contextName = "/" + warFileName;
121 }
122
123 try {
124 contextName = getContainerWrapper().getTomcatContainer().formatContextName(contextName);
125
126
127
128
129
130 String visibleContextName = contextName.isEmpty() ? "/" : contextName;
131 request.setAttribute("contextName", visibleContextName);
132
133
134 if ("yes".equals(updateParam)
135 && getContainerWrapper().getTomcatContainer().findContext(contextName) != null) {
136 if (contextName.matches("\\w*")) {
137 logger.debug("updating {}: removing the old copy", contextName);
138 }
139 getContainerWrapper().getTomcatContainer().remove(contextName);
140 }
141
142 if (getContainerWrapper().getTomcatContainer().findContext(contextName) == null) {
143
144 String destWarFilename =
145 getContainerWrapper().getTomcatContainer().formatContextFilename(contextName);
146 File destWar = Path.of(getContainerWrapper().getTomcatContainer().getAppBase().getPath(),
147 destWarFilename + ".war").toFile();
148
149 FileUtils.moveFile(tmpPath.toFile(), destWar);
150
151
152 getContainerWrapper().getTomcatContainer().installWar(contextName);
153
154 Path destContext = Path
155 .of(getContainerWrapper().getTomcatContainer().getAppBase().getPath(), destWarFilename);
156
157
158 PathUtils.waitFor(destContext, Duration.ofSeconds(MAXSECONDS_WAITFOR_CONTEXT));
159
160 Context ctx = getContainerWrapper().getTomcatContainer().findContext(contextName);
161 if (ctx == null) {
162 errMsg = getMessageSourceAccessor().getMessage("probe.src.deploy.war.notinstalled",
163 new Object[] {visibleContextName});
164 } else {
165 request.setAttribute("success", Boolean.TRUE);
166
167 Authentication auth = SecurityContextHolder.getContext().getAuthentication();
168
169 String name = auth.getName();
170 if (contextName.matches("\\w*")) {
171 logger.info(getMessageSourceAccessor().getMessage("probe.src.log.deploywar"), name,
172 contextName);
173 }
174
175 if ("yes".equals(discardParam)) {
176 getContainerWrapper().getTomcatContainer().discardWorkDir(ctx);
177 if (contextName.matches("\\w*")) {
178 logger.info(getMessageSourceAccessor().getMessage("probe.src.log.discardwork"), name,
179 contextName);
180 }
181 }
182
183 if ("yes".equals(compileParam)) {
184 Summary summary = new Summary();
185 summary.setName(ctx.getName());
186 getContainerWrapper().getTomcatContainer().listContextJsps(ctx, summary, true);
187 request.getSession(false).setAttribute(DisplayJspController.SUMMARY_ATTRIBUTE, summary);
188 request.setAttribute("compileSuccess", Boolean.TRUE);
189 }
190 }
191 } else {
192 errMsg = getMessageSourceAccessor().getMessage("probe.src.deploy.war.alreadyExists",
193 new Object[] {visibleContextName});
194 }
195 } catch (IOException e) {
196 errMsg = getMessageSourceAccessor().getMessage("probe.src.deploy.war.failure",
197 new Object[] {e.getMessage()});
198 logger.error("Tomcat threw an exception when trying to deploy", e);
199 } finally {
200 if (errMsg != null) {
201 request.setAttribute("errorMessage", errMsg);
202 }
203
204 if (Files.exists(tmpPath)) {
205 Files.delete(tmpPath);
206 }
207 }
208 return new ModelAndView(new InternalResourceView(getViewName()));
209 }
210
211 @Value("/adm/deploy.htm")
212 @Override
213 public void setViewName(String viewName) {
214 super.setViewName(viewName);
215 }
216
217 }