1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.viewer.resources;
20
21 import java.io.Closeable;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.nio.channels.SeekableByteChannel;
25 import java.nio.file.Files;
26 import java.nio.file.StandardOpenOption;
27 import java.util.Optional;
28 import java.util.Spliterator;
29 import java.util.Spliterators;
30 import java.util.stream.StreamSupport;
31
32 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
33 import org.apache.commons.compress.archivers.zip.ZipFile;
34 import org.apache.commons.io.IOUtils;
35 import org.mycore.access.MCRAccessManager;
36 import org.mycore.common.MCRSession;
37 import org.mycore.common.MCRSessionMgr;
38 import org.mycore.common.MCRTransactionHelper;
39 import org.mycore.datamodel.niofs.MCRPath;
40 import org.mycore.frontend.MCRFrontendUtil;
41 import org.mycore.frontend.jersey.MCRStaticContent;
42 import org.mycore.frontend.servlets.MCRServlet;
43
44 import jakarta.servlet.http.HttpServletRequest;
45 import jakarta.servlet.http.HttpServletResponse;
46 import jakarta.ws.rs.GET;
47 import jakarta.ws.rs.Path;
48 import jakarta.ws.rs.PathParam;
49 import jakarta.ws.rs.WebApplicationException;
50 import jakarta.ws.rs.core.Context;
51 import jakarta.ws.rs.core.Response;
52 import jakarta.ws.rs.core.StreamingOutput;
53
54 @Path("/epub")
55 @MCRStaticContent
56 public class MCREpubZipResource {
57
58 public static final String EPUB_SPLIT = ".epub/";
59
60 @Context
61 HttpServletRequest request;
62
63 @Context
64 private HttpServletResponse response;
65
66 private static void suppressedClose(Closeable... closeus) {
67 for (Closeable closeme : closeus) {
68 if (closeme != null) {
69 try {
70 closeme.close();
71 } catch (IOException ignored) {
72 }
73 }
74 }
75 }
76
77 @GET
78 @Path("/{derivateID}/{epubFilePathAndPathInEpub:.+}")
79 public Response extract(
80 @PathParam("derivateID") String derivateID,
81 @PathParam("epubFilePathAndPathInEpub") String epubFileAndSubpath) {
82 java.nio.file.Path epubPath = null;
83
84 final String[] split = epubFileAndSubpath.split(EPUB_SPLIT, 2);
85
86 if (split.length != 2) {
87 throw new WebApplicationException("The path seems to be wrong: " + epubFileAndSubpath,
88 Response.Status.BAD_REQUEST);
89 }
90
91 final String epubFile = split[0] + EPUB_SPLIT.substring(0, EPUB_SPLIT.length() - 1);
92 final String pathInEpub = split[1];
93
94 MCRSession session = null;
95 try {
96 MCRSessionMgr.unlock();
97 session = MCRServlet.getSession(request);
98 MCRSessionMgr.setCurrentSession(session);
99 MCRFrontendUtil.configureSession(session, request, response);
100 if (!MCRAccessManager.checkPermission(derivateID, MCRAccessManager.PERMISSION_READ)) {
101 throw new WebApplicationException("No rights to read " + derivateID, Response.Status.FORBIDDEN);
102 }
103 epubPath = MCRPath.getPath(derivateID, epubFile).toPhysicalPath();
104 } catch (IOException e) {
105 throw new WebApplicationException("Error while resolving physical path of " + derivateID + ":" + epubFile,
106 e);
107 } finally {
108 try {
109 if (session != null && MCRTransactionHelper.isTransactionActive()) {
110 if (MCRTransactionHelper.transactionRequiresRollback()) {
111 MCRTransactionHelper.rollbackTransaction();
112 } else {
113 MCRTransactionHelper.commitTransaction();
114 }
115 }
116 } finally {
117 MCRSessionMgr.releaseCurrentSession();
118 MCRSessionMgr.lock();
119 }
120 }
121
122 if (!Files.exists(epubPath)) {
123 throw new WebApplicationException("The file " + derivateID + ":" + epubFile + " is not present!",
124 Response.Status.NOT_FOUND);
125 }
126
127
128
129
130
131
132
133 SeekableByteChannel epubStream = null;
134 InputStream zipFileStream = null;
135 ZipFile zipFile = null;
136 boolean responsible = true;
137
138 try {
139 epubStream = Files.newByteChannel(epubPath, StandardOpenOption.READ);
140 zipFile = new ZipFile(epubStream);
141
142 final Optional<ZipArchiveEntry> entryOfFileInEpub = StreamSupport
143 .stream(Spliterators.spliteratorUnknownSize(zipFile.getEntries().asIterator(), Spliterator.ORDERED),
144 false)
145 .filter(entry -> !entry.isDirectory())
146 .filter(entry -> Optional.ofNullable(entry.getName()).filter(pathInEpub::equals).isPresent())
147 .findFirst();
148
149 final ZipArchiveEntry zipArchiveEntry = entryOfFileInEpub
150 .orElseThrow(() -> new WebApplicationException("EPUB does not contain: " + pathInEpub,
151 Response.Status.NOT_FOUND));
152
153 zipFileStream = zipFile.getInputStream(zipArchiveEntry);
154
155 final InputStream finalZipFileStream = zipFileStream;
156 final Closeable finalZipFile = zipFile;
157 final Closeable finalEpubStream = epubStream;
158
159 StreamingOutput out = output -> {
160 try {
161 IOUtils.copy(finalZipFileStream, output);
162 } catch (IOException e) {
163
164 } finally {
165 suppressedClose(finalZipFileStream, finalZipFile, finalEpubStream);
166 }
167 };
168 responsible = false;
169 return Response.ok(out).build();
170 } catch (IOException e) {
171 throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR);
172 } finally {
173 if (responsible) {
174
175 suppressedClose(zipFileStream, zipFile, epubStream);
176 }
177 }
178 }
179 }