Skip to content

Commit

Permalink
Merge pull request #3774 from inception-project/feature/3773-Support-…
Browse files Browse the repository at this point in the history
…loading-resources-from-documents-that-are-actually-archives

#3773 - Support loading resources from documents that are actually archives
  • Loading branch information
reckart authored Feb 3, 2023
2 parents deade4c + 852c53b commit 9e3131c
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@

import static de.tudarmstadt.ukp.clarin.webanno.support.ZipUtils.zipFolder;
import static java.io.File.createTempFile;
import static java.util.Collections.unmodifiableSet;
import static org.apache.commons.io.FileUtils.copyFile;
import static org.apache.commons.io.FilenameUtils.getExtension;
import static org.apache.commons.io.FilenameUtils.normalize;
import static org.apache.commons.lang3.StringUtils.prependIfMissing;
import static org.apache.uima.fit.factory.AnalysisEngineFactory.createEngine;
import static org.apache.uima.fit.factory.CollectionReaderFactory.createReader;
import static org.apache.uima.fit.factory.ConfigurationParameterFactory.addConfigurationParameters;
Expand All @@ -29,9 +33,12 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
Expand All @@ -55,6 +62,10 @@

public interface FormatSupport
{
Set<String> DEFAULT_PERMITTED_RESOURCE_EXTENSIONS = unmodifiableSet(
Set.of("apng", "avif", "gif", "jpg", "jpeg", "jfif", "pjpeg", "pjp", "png", "svg",
"webp", "bmp", "tif", "tiff"));

/**
* Returns the format identifier which is stored in in {@link SourceDocument#setFormat(String)}.
*
Expand Down Expand Up @@ -95,6 +106,26 @@ default boolean isProneToInconsistencies()
return true;
}

default boolean hasResources()
{
return false;
}

default boolean isAccessibelResource(File aDocFile, String aResourcePath)
{
return DEFAULT_PERMITTED_RESOURCE_EXTENSIONS.contains(getExtension(aResourcePath));
}

default InputStream openResourceStream(File aDocFile, String aResourcePath) throws IOException
{
if (!hasResources() || !isAccessibelResource(aDocFile, aResourcePath)) {
throw new FileNotFoundException("Resource not found [" + aResourcePath + "]");
}

var path = prependIfMissing(normalize(aResourcePath, isProneToInconsistencies()), "/");
return new URL("jar:" + aDocFile.toURI().toURL() + "!" + path).openStream();
}

/**
* @return format-specific CSS style-sheets that styleable editors should load.
*/
Expand Down
4 changes: 4 additions & 0 deletions inception/inception-external-editor/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
<groupId>de.tudarmstadt.ukp.inception.app</groupId>
<artifactId>inception-api-schema</artifactId>
</dependency>
<dependency>
<groupId>de.tudarmstadt.ukp.inception.app</groupId>
<artifactId>inception-api-formats</artifactId>
</dependency>
<dependency>
<groupId>de.tudarmstadt.ukp.inception.app</groupId>
<artifactId>inception-model</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
import java.security.Principal;
import java.util.Optional;

import javax.servlet.http.HttpServletRequest;

import org.springframework.core.io.InputStreamResource;
import org.springframework.http.ResponseEntity;

import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument;
Expand All @@ -35,4 +38,8 @@ public interface XHtmlXmlDocumentViewController
ResponseEntity<String> getDocument(long aProjectId, long aDocumentId, Optional<String> aEditor,
Principal aPrincipal)
throws Exception;

ResponseEntity<InputStreamResource> getResource(long aProjectId, long aDocumentId,
HttpServletRequest aRequest, Principal aPrincipal)
throws Exception;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,29 @@
*/
package de.tudarmstadt.ukp.inception.externaleditor.xhtml;

import static java.lang.invoke.MethodHandles.lookup;
import static org.apache.commons.lang3.StringUtils.substringAfter;
import static org.slf4j.LoggerFactory.getLogger;
import static org.springframework.http.HttpStatus.OK;

import java.io.FileNotFoundException;
import java.io.StringWriter;
import java.security.Principal;
import java.util.Locale;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.uima.cas.CAS;
import org.dkpro.core.api.xml.type.XmlDocument;
import org.dkpro.core.api.xml.type.XmlElement;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
Expand Down Expand Up @@ -60,7 +70,12 @@ public class XHtmlXmlDocumentViewControllerImpl
extends XmlDocumentViewControllerImplBase
implements XHtmlXmlDocumentViewController
{
private static final String GET_DOCUMENT_PATH = "/p/{projectId}/xml/{documentId}";
private static final Logger LOG = getLogger(lookup().lookupClass());

private static final String RESOURCE_ELEMENT = "/res/";
private static final String GET_DOCUMENT_PATH = "/p/{projectId}/d/{documentId}/xml";
private static final String GET_RESOURCE_PATH = "/p/{projectId}/d/{documentId}"
+ RESOURCE_ELEMENT + "**";

private static final String XHTML_NS_URI = "http://www.w3.org/1999/xhtml";
private static final String HTML = "html";
Expand Down Expand Up @@ -178,6 +193,43 @@ public ResponseEntity<String> getDocument(@PathVariable("projectId") long aProje
}
}

@PreAuthorize("@documentAccess.canViewAnnotationDocument(#aProjectId, #aDocumentId, #principal.name)")
@Override
@GetMapping(path = GET_RESOURCE_PATH)
public ResponseEntity<InputStreamResource> getResource(
@PathVariable("projectId") long aProjectId,
@PathVariable("documentId") long aDocumentId, HttpServletRequest aRequest,
Principal principal)
throws Exception
{
var srcDoc = documentService.getSourceDocument(aProjectId, aDocumentId);

var maybeFormatSupport = formatRegistry.getFormatById(srcDoc.getFormat());
if (!maybeFormatSupport.isPresent()) {
return ResponseEntity.notFound().build();
}

var srcDocFile = documentService.getSourceDocumentFile(srcDoc);
var path = aRequest.getServletPath();
var resource = substringAfter(path, RESOURCE_ELEMENT);

var formatSupport = maybeFormatSupport.get();

try {
var inputStream = formatSupport.openResourceStream(srcDocFile, resource);
HttpHeaders httpHeaders = new HttpHeaders();
return new ResponseEntity<>(new InputStreamResource(inputStream), httpHeaders, OK);
}
catch (FileNotFoundException e) {
LOG.error("Resource [{}] for document {} not found", resource, srcDoc);
return ResponseEntity.notFound().build();
}
catch (Exception e) {
LOG.error("Unable to load resource [{}] for document {}", resource, srcDoc, e);
return ResponseEntity.notFound().build();
}
}

private ResponseEntity<String> toResponse(StringWriter aOut)
{
return ResponseEntity.ok() //
Expand Down

0 comments on commit 9e3131c

Please sign in to comment.