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