View Javadoc
1   /*
2    * Copyright 2012-2025 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.app.web.thumbnail;
17  
18  import java.io.BufferedInputStream;
19  import java.io.File;
20  import java.io.FileInputStream;
21  import java.util.Map;
22  
23  import org.codelibs.core.lang.StringUtil;
24  import org.codelibs.fess.app.web.base.FessSearchAction;
25  import org.codelibs.fess.util.DocumentUtil;
26  import org.lastaflute.web.Execute;
27  import org.lastaflute.web.response.ActionResponse;
28  
29  import jakarta.annotation.Resource;
30  import jakarta.servlet.http.HttpServletResponse;
31  
32  /**
33   * Action class for handling thumbnail image requests.
34   * Serves thumbnail images for documents in the search results.
35   */
36  public class ThumbnailAction extends FessSearchAction {
37  
38      /**
39       * Default constructor for ThumbnailAction.
40       */
41      public ThumbnailAction() {
42          super();
43      }
44  
45      // ===================================================================================
46      //                                                                           Attribute
47      //
48      /**
49       * HTTP servlet response for streaming thumbnail images.
50       */
51      @Resource
52      protected HttpServletResponse response;
53  
54      // ===================================================================================
55      //                                                                               Hook
56      //                                                                              ======
57  
58      // ===================================================================================
59      //                                                                      Search Execute
60      //                                                                      ==============
61      /**
62       * Serves a thumbnail image for the specified document.
63       *
64       * @param form the thumbnail request form containing document ID and query parameters
65       * @return ActionResponse containing the thumbnail image or 404 if not found
66       */
67      @Execute
68      public ActionResponse index(final ThumbnailForm form) {
69          validate(form, messages -> {}, () -> asHtml(virtualHost(path_Error_ErrorJsp)));
70          if (isLoginRequired()) {
71              return redirectToLogin();
72          }
73  
74          final Map<String, Object> doc =
75                  searchHelper.getDocumentByDocId(form.docId, queryFieldConfig.getResponseFields(), getUserBean()).orElse(null);
76          final String url = DocumentUtil.getValue(doc, fessConfig.getIndexFieldThumbnail(), String.class);
77          if (StringUtil.isBlank(form.queryId) || StringUtil.isBlank(url) || !thumbnailSupport) {
78              // 404
79              throw responseManager.new404("Thumbnail for " + form.docId + " is not found.");
80          }
81  
82          final File thumbnailFile = thumbnailManager.getThumbnailFile(doc);
83          if (thumbnailFile == null) {
84              if (fessConfig.isThumbnailEnabled()) {
85                  thumbnailManager.offer(doc);
86              }
87              // 404
88              throw responseManager.new404("Thumbnail for " + form.docId + " is under generating.");
89          }
90  
91          return asStream(form.docId).contentType(getImageMimeType(thumbnailFile)).stream(out -> {
92              try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(thumbnailFile))) {
93                  out.write(in);
94              }
95          });
96      }
97  
98      /**
99       * Determines the MIME type of an image file based on its file extension.
100      *
101      * @param imageFile the image file
102      * @return the MIME type string
103      */
104     protected String getImageMimeType(final File imageFile) {
105         final String path = imageFile.getAbsolutePath();
106         if (path.endsWith(".png")) {
107             return "image/png";
108         }
109         if (path.endsWith(".gif")) {
110             return "image/gif";
111         }
112         if (path.endsWith(".jpg") || path.endsWith(".jpeg")) {
113             return "image/jpeg";
114         }
115         return "application/octet-stream";
116     }
117 }