View Javadoc
1   /*
2    * Licensed under the GPL License. You may not use this file except in compliance with the License.
3    * You may obtain a copy of the License at
4    *
5    *   https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
6    *
7    * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
8    * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
9    * PURPOSE.
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.util.ArrayList;
23  import java.util.HashMap;
24  import java.util.List;
25  import java.util.Map;
26  
27  import org.apache.catalina.Context;
28  import org.apache.commons.io.FileUtils;
29  import org.apache.commons.io.FilenameUtils;
30  import org.slf4j.Logger;
31  import org.slf4j.LoggerFactory;
32  import org.springframework.beans.factory.annotation.Value;
33  import org.springframework.security.core.Authentication;
34  import org.springframework.security.core.context.SecurityContextHolder;
35  import org.springframework.stereotype.Controller;
36  import org.springframework.web.bind.annotation.GetMapping;
37  import org.springframework.web.bind.annotation.PostMapping;
38  import org.springframework.web.bind.annotation.RequestParam;
39  import org.springframework.web.multipart.MultipartFile;
40  import org.springframework.web.servlet.ModelAndView;
41  import org.springframework.web.servlet.view.InternalResourceView;
42  
43  import psiprobe.controllers.AbstractTomcatContainerController;
44  
45  /**
46   * Uploads single file to a deployed context.
47   */
48  @Controller
49  public class CopySingleFileController extends AbstractTomcatContainerController {
50  
51    /** The Constant logger. */
52    private static final Logger logger = LoggerFactory.getLogger(CopySingleFileController.class);
53  
54    @GetMapping("/adm/deployfile.htm")
55    @Override
56    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
57        throws Exception {
58      return super.handleRequest(request, response);
59    }
60  
61    @Override
62    protected ModelAndView handleRequestInternal(HttpServletRequest request,
63        HttpServletResponse response) throws Exception {
64      return new ModelAndView(new InternalResourceView(getViewName()));
65    }
66  
67    @PostMapping("/adm/deployfile.htm")
68    public ModelAndView handleFileUpload(@RequestParam("file") MultipartFile file,
69        @RequestParam("context") String contextName, @RequestParam("where") String where,
70        @RequestParam(value = "reload", required = false) String reloadParam,
71        @RequestParam(value = "discard", required = false) String discardParam,
72        HttpServletRequest request) throws IOException {
73  
74      List<Context> apps;
75      try {
76        apps = getContainerWrapper().getTomcatContainer().findContexts();
77      } catch (NullPointerException ex) {
78        throw new IllegalStateException(
79            "No container found for your server: " + getServletContext().getServerInfo(), ex);
80      }
81  
82      List<Map<String, String>> applications = new ArrayList<>();
83      for (Context appContext : apps) {
84        // check if this is not the ROOT webapp
85        if (!Strings.isNullOrEmpty(appContext.getName())) {
86          Map<String, String> app = new HashMap<>();
87          app.put("value", appContext.getName());
88          app.put("label", appContext.getName());
89          applications.add(app);
90        }
91      }
92      request.setAttribute("apps", applications);
93  
94      String errMsg = null;
95  
96      // If not multi-part content, exit
97      if (file == null || file.isEmpty()) {
98        errMsg = getMessageSourceAccessor().getMessage("probe.src.deploy.file.notFile.failure")
99            + " [null or empty]";
100       request.setAttribute("errorMessage", errMsg);
101       return new ModelAndView(new InternalResourceView(getViewName()));
102     }
103 
104     // Save the uploaded file to a temporary location
105     Path tmpPath = null;
106     try {
107       String fileName = file.getOriginalFilename();
108       if (!Strings.isNullOrEmpty(fileName)) {
109         fileName = FilenameUtils.getName(fileName);
110         tmpPath = Path.of(System.getProperty("java.io.tmpdir"), fileName);
111         file.transferTo(tmpPath);
112       } else {
113         errMsg = getMessageSourceAccessor().getMessage("probe.src.deploy.file.notFile.failure")
114             + " [null or empty]";
115         request.setAttribute("errorMessage", errMsg);
116         return new ModelAndView(new InternalResourceView(getViewName()));
117       }
118     } catch (IOException e) {
119       logger.error("Could not process file upload", e);
120       request.setAttribute("errorMessage", getMessageSourceAccessor()
121           .getMessage("probe.src.deploy.file.uploadfailure", new Object[] {e.getMessage()}));
122       // File is transferred so it will exist
123       Files.delete(tmpPath);
124       return new ModelAndView(new InternalResourceView(getViewName()));
125     }
126 
127     try {
128       contextName = getContainerWrapper().getTomcatContainer().formatContextName(contextName);
129 
130       /*
131        * pass the name of the newly deployed context to the presentation layer using this name the
132        * presentation layer can render a url to view compilation details
133        */
134       String visibleContextName = contextName.isEmpty() ? "/" : contextName;
135       request.setAttribute("contextName", visibleContextName);
136 
137       // Check if context is already deployed
138       if (getContainerWrapper().getTomcatContainer().findContext(contextName) != null) {
139 
140         File destFile = Path.of(getContainerWrapper().getTomcatContainer().getAppBase().getPath(),
141             contextName + where).toFile();
142 
143         // Checks if the destination path exists
144         if (destFile.exists()) {
145           if (!destFile.getAbsolutePath().contains("..")) {
146             // Copy the file overwriting it if it already exists
147             FileUtils.copyFileToDirectory(tmpPath.toFile(), destFile);
148 
149             request.setAttribute("successFile", Boolean.TRUE);
150             // Logging action
151             Authentication auth = SecurityContextHolder.getContext().getAuthentication();
152             // get username logger
153             String name = auth.getName();
154             if (contextName.matches("\\w*")) {
155               logger.info(getMessageSourceAccessor().getMessage("probe.src.log.copyfile"), name,
156                   contextName);
157             }
158             Context context = getContainerWrapper().getTomcatContainer().findContext(contextName);
159             // Checks if DISCARD "work" directory is selected
160             if ("yes".equalsIgnoreCase(discardParam)) {
161               getContainerWrapper().getTomcatContainer().discardWorkDir(context);
162               if (contextName.matches("\\w*")) {
163                 logger.info(getMessageSourceAccessor().getMessage("probe.src.log.discardwork"),
164                     name, contextName);
165               }
166             }
167             // Checks if RELOAD option is selected
168             if ("yes".equalsIgnoreCase(reloadParam) && context != null) {
169               context.reload();
170               request.setAttribute("reloadContext", Boolean.TRUE);
171               if (contextName.matches("\\w*")) {
172                 logger.info(getMessageSourceAccessor().getMessage("probe.src.log.reload"), name,
173                     contextName);
174               }
175             }
176           } else {
177             errMsg = getMessageSourceAccessor().getMessage("probe.src.deploy.file.pathNotValid");
178           }
179         } else {
180           errMsg = getMessageSourceAccessor().getMessage("probe.src.deploy.file.notPath");
181         }
182       } else {
183         errMsg = getMessageSourceAccessor().getMessage("probe.src.deploy.file.notExists",
184             new Object[] {visibleContextName});
185       }
186     } catch (IOException e) {
187       errMsg = getMessageSourceAccessor().getMessage("probe.src.deploy.file.failure",
188           new Object[] {e.getMessage()});
189       logger.error("Tomcat threw an exception when trying to deploy", e);
190     } finally {
191       if (errMsg != null) {
192         request.setAttribute("errorMessage", errMsg);
193       }
194       // File is copied so it will exist
195       Files.delete(tmpPath);
196     }
197     return new ModelAndView(new InternalResourceView(getViewName()));
198   }
199 
200   @Value("/adm/deploy.htm")
201   @Override
202   public void setViewName(String viewName) {
203     super.setViewName(viewName);
204   }
205 
206 }