View Javadoc
1   /*
2    * This file is part of ***  M y C o R e  ***
3    * See http://www.mycore.de/ for details.
4    *
5    * MyCoRe is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * MyCoRe is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with MyCoRe.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package org.mycore.datamodel.ifs;
20  
21  import java.io.IOException;
22  import java.nio.file.Files;
23  import java.nio.file.NoSuchFileException;
24  import java.nio.file.attribute.BasicFileAttributes;
25  import java.util.Arrays;
26  import java.util.regex.Pattern;
27  
28  import javax.xml.transform.TransformerException;
29  
30  import org.apache.logging.log4j.LogManager;
31  import org.apache.logging.log4j.Logger;
32  import org.jdom2.Document;
33  import org.mycore.access.MCRAccessManager;
34  import org.mycore.common.content.MCRContent;
35  import org.mycore.common.content.MCRJDOMContent;
36  import org.mycore.common.content.MCRPathContent;
37  import org.mycore.datamodel.metadata.MCRObjectID;
38  import org.mycore.datamodel.niofs.MCRPath;
39  import org.mycore.datamodel.niofs.MCRPathXML;
40  import org.mycore.frontend.servlets.MCRContentServlet;
41  import org.xml.sax.SAXException;
42  
43  import jakarta.servlet.http.HttpServletRequest;
44  import jakarta.servlet.http.HttpServletResponse;
45  
46  /**
47   * This servlet delivers the contents of an MCRFilesystemNode to the client
48   * browser. If the node is a ordinary MCRFile, the contents of that file will be
49   * sent to the browser. If the node is an MCRFile with a MCRAudioVideoExtender,
50   * the message that starts the associated streaming player will be delivered. If
51   * the node is a MCRDirectory, the contents of that directory will be forwareded
52   * to MCRLayoutService as XML data to display a detailed directory listing.
53   * 
54   * @author Frank Lützenkirchen
55   * @author Jens Kupferschmidt
56   * @author Thomas Scheffler (yagee)
57   * @author A.Schaar
58   * @author Robert Stephan
59   * 
60   * @version $Revision$ $Date$
61   */
62  public class MCRFileNodeServlet extends MCRContentServlet {
63      private static final long serialVersionUID = 1L;
64  
65      private static Logger LOGGER = LogManager.getLogger(MCRFileNodeServlet.class);
66  
67      private static Pattern patternDerivateID = Pattern.compile(".+_derivate_[0-9]+");
68  
69      /* (non-Javadoc)
70       * @see org.mycore.frontend.servlets.MCRContentServlet#getContent(jakarta.servlet.http.HttpServletRequest, jakarta.servlet.http.HttpServletResponse)
71       */
72      @Override
73      public MCRContent getContent(HttpServletRequest request, HttpServletResponse response) throws IOException {
74          if (!isParametersValid(request, response)) {
75              return null;
76          }
77          String ownerID = getOwnerID(request);
78          if (ownerID != null && ownerID.length() > 0) {
79              //make sure, that numberpart of ownerID has correct length 
80              ownerID = MCRObjectID.getInstance(ownerID).toString();
81          }
82          if (!MCRAccessManager.checkDerivateContentPermission(MCRObjectID.getInstance(ownerID),
83              MCRAccessManager.PERMISSION_READ)) {
84              LOGGER.info("AccessForbidden to {}", request.getPathInfo());
85              response.sendError(HttpServletResponse.SC_FORBIDDEN);
86              return null;
87          }
88          String path = getPath(request);
89          MCRPath mcrPath = MCRPath.getPath(ownerID, path);
90          BasicFileAttributes attr;
91          try {
92              attr = Files.readAttributes(mcrPath, BasicFileAttributes.class);
93          } catch (NoSuchFileException e) {
94              String msg = e.getMessage();
95              if (msg == null) {
96                  msg = "File or directory not found: " + mcrPath;
97              }
98              response.sendError(HttpServletResponse.SC_NOT_FOUND, msg);
99              return null;
100         }
101         if (attr.isDirectory()) {
102             try {
103                 return sendDirectory(request, response, mcrPath);
104             } catch (TransformerException | SAXException e) {
105                 throw new IOException(e);
106             }
107         }
108         if (attr.isRegularFile()) {
109             return sendFile(request, response, mcrPath);
110         }
111         response.sendError(HttpServletResponse.SC_NOT_FOUND, "Not a file or directory: " + mcrPath);
112         return null;
113     }
114 
115     private boolean isParametersValid(HttpServletRequest request, HttpServletResponse response) throws IOException {
116         String requestPath = request.getPathInfo();
117         LOGGER.debug("request path = {}", requestPath);
118 
119         if (requestPath == null) {
120             response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Error: HTTP request path is null");
121             return false;
122         }
123         return true;
124     }
125 
126     /**
127      *  retrieves the derivate ID of the owning derivate from request path.
128      *  Attention: derivateID is not always at the first position in path 
129      *  @param request - the http request object
130      */
131     public static String getOwnerID(HttpServletRequest request) {
132         String pI = request.getPathInfo();
133         return Arrays.stream(pI.split("/"))
134             .filter(fragment -> patternDerivateID.matcher(fragment).matches())
135             .findFirst()
136             .orElse("");
137     }
138 
139     /**
140      *  Retrieves the path of the file to display from request path.
141      *  @param request - the http request object
142      */
143     protected String getPath(HttpServletRequest request) {
144         String pI = request.getPathInfo();
145         String ownerID = getOwnerID(request);
146         int pos = pI.indexOf(ownerID) + ownerID.length() + 1;
147         if (pos - 1 >= pI.length()) {
148             return "/";
149         }
150         String path = pI.substring(pos);
151         if (path.endsWith("/")) {
152             path = path.substring(0, path.length() - 1);
153         }
154         if (path.length() == 0) {
155             return "/";
156         }
157         return path;
158     }
159 
160     private MCRContent sendFile(HttpServletRequest request, HttpServletResponse response, MCRPath mcrPath) {
161         // TODO: Does MCRFileNodeServlet really has to handle IFS1 AudioVideoExtender support? (last rev: 30037))
162         return new MCRPathContent(mcrPath);
163     }
164 
165     /**
166      * Sends the contents of an MCRDirectory as XML data to the client
167      * @throws SAXException 
168      * @throws TransformerException 
169      */
170     private MCRContent sendDirectory(HttpServletRequest request, HttpServletResponse response, MCRPath mcrPath)
171         throws IOException, TransformerException, SAXException {
172         Document directoryXML = MCRPathXML.getDirectoryXML(mcrPath);
173         MCRJDOMContent source = new MCRJDOMContent(directoryXML);
174         source.setLastModified(Files.getLastModifiedTime(mcrPath).toMillis());
175         String fileName = mcrPath.getNameCount() == 0 ? mcrPath.getOwner() : mcrPath.getFileName().toString();
176         source.setName(fileName);
177         return getLayoutService().getTransformedContent(request, response, source);
178     }
179 
180 }