Skip to content

Commit

Permalink
Refactor: RepositoryAccess facade
Browse files Browse the repository at this point in the history
  • Loading branch information
petrpodsed committed Dec 28, 2024
1 parent d6bf8c3 commit c7a152b
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import com.qbizm.kramerius.imp.jaxb.DigitalObject;
import cz.incad.kramerius.StreamHeadersObserver;
import cz.incad.kramerius.fedora.RepositoryAccess;
import cz.incad.kramerius.fedora.impl.tmp.ContentFormat;
import cz.incad.kramerius.fedora.impl.tmp.UnsupportedContentFormatException;
import cz.incad.kramerius.fedora.om.repository.AkubraRepository;
import cz.incad.kramerius.fedora.om.repository.RepositoryDatastream;
import cz.incad.kramerius.fedora.om.repository.RepositoryException;
Expand Down Expand Up @@ -33,12 +35,14 @@

import javax.annotation.Nullable;
import javax.xml.bind.JAXBException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPathExpressionException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeParseException;
import java.util.*;
Expand Down Expand Up @@ -91,30 +95,6 @@ public boolean isPidAvailable(String pid) throws IOException, RepositoryExceptio
boolean exists = this.repositoryApi.objectExists(pid);
return exists;
}
@Override
public InputStream getFoxml(String pid, boolean archive) throws IOException {
try {
if (archive){
DigitalObject obj = manager.readObjectCloneFromStorage(pid);
manager.resolveArchivedDatastreams(obj);
return this.manager.marshallObject(obj);
}else {
return this.manager.retrieveObject(pid);
}
} catch (Exception e) {
throw new IOException(e);
}
}
@Override
public org.dom4j.Document getFoxml(String pid) throws RepositoryException, IOException {
Lock readLock = AkubraDOManager.getReadLock(pid);
try {
RepositoryObject object = akubraRepositoryImpl.getObject(pid);
return Utils.inputstreamToDocument(object.getFoxml(), true);
} finally {
readLock.unlock();
}
}
//-------- get object property
@Override
public String getProperty(String pid, String propertyName) throws IOException, RepositoryException {
Expand Down Expand Up @@ -187,70 +167,6 @@ public List<String> getDatastreamNames(String pid) throws RepositoryException, I
readLock.unlock();
}
}
// TODO here we always use AkubraUtils.getStreamContent but we have also AkubraObject.AkubraDatastream for fetching stream content
@Override
public InputStream getDataStream(String pid, String datastreamName) throws IOException {
try {
pid = makeSureObjectPid(pid);
if (this.accessLog != null && this.accessLog.isReportingAccess(pid, datastreamName)) {
reportAccess(pid, datastreamName);
}
DigitalObject object = manager.readObjectFromStorage(pid);
if (object != null) {
DatastreamVersionType stream = AkubraUtils.getLastStreamVersion(object, datastreamName);
if (stream != null) {
return AkubraUtils.getStreamContent(stream, manager);
} else {
throw new IOException("cannot find stream '" + datastreamName + "' for pid '" + pid + "'");
}
} else {
throw new IOException("cannot find pid '" + pid + "'");
}
} catch (Exception e) {
throw new IOException(e);
}
}
// XML data stream
@Override
public Document getStream(String pid, String streamName) throws IOException {
DigitalObject object = manager.readObjectFromStorage(pid);
if (object != null) {
DatastreamVersionType stream = AkubraUtils.getLastStreamVersion(object, streamName);
if (stream != null) {
if (stream.getXmlContent() != null) {
List<Element> elementList = stream.getXmlContent().getAny();
if (!elementList.isEmpty()) {
return elementList.get(0).getOwnerDocument();
} else {
throw new IOException("Datastream not found: " + pid + " - " + streamName);
}
} else {
throw new IOException("Expected XML datastream: " + pid + " - " + streamName);
}
}
throw new IOException("Datastream not found: " + pid + " - " + streamName);
}
throw new IOException("Object not found: " + pid);
}
@Override
public org.dom4j.Document getDatastreamXml(String pid, String dsId) throws RepositoryException, IOException {
Lock readLock = AkubraDOManager.getReadLock(pid);
try {
RepositoryObject object = akubraRepositoryImpl.getObject(pid);
if (object.streamExists(dsId)) {
org.dom4j.Document foxml = Utils.inputstreamToDocument(object.getFoxml(), true);
org.dom4j.Element dcEl = (org.dom4j.Element) Dom4jUtils.buildXpath(String.format("/foxml:digitalObject/foxml:datastream[@ID='%s']", dsId)).selectSingleNode(foxml);
org.dom4j.Element detached = (org.dom4j.Element) dcEl.detach();
org.dom4j.Document result = DocumentHelper.createDocument();
result.add(detached);
return result;
} else {
return null;
}
} finally {
readLock.unlock();
}
}
@Override
public List<Map<String, String>> getStreamsOfObject(String pid) throws IOException {
try {
Expand Down Expand Up @@ -320,9 +236,120 @@ public Date getStreamLastmodifiedFlag(String pid, String streamName) throws IOEx
}
throw new IOException("Object not found: " + pid);
}
//------ get stream CONTENT
// input data stream
//------------------------------------------------------------------------------------------------------------
// NEW !!!!!!!!!!!!!!!!
public <T> T getStreamContent(String pid, KnownDatastreams dsId, Class<T> returnType) throws IOException, UnsupportedContentFormatException {
// Determine supported formats for the content
ContentFormat supportedFormat = determineSupportedFormat(id);
// Validate the requested format
if ((contentType == String.class && !supportedFormat.supportsString()) ||
(contentType == InputStream.class && !supportedFormat.supportsStream()) ||
(contentType == Document.class && !supportedFormat.supportsXml())) {
throw new UnsupportedContentFormatException("Format not supported for content ID: " + id);
}
// Retrieve content as bytes
byte[] rawContent = fetchContentFromStorage(id);
// Convert content to the requested format
if (contentType == String.class) {
return contentType.cast(new String(rawContent, StandardCharsets.UTF_8));
} else if (contentType == InputStream.class) {
return contentType.cast(new ByteArrayInputStream(rawContent));
} else if (contentType == Document.class) {
return contentType.cast(parseXml(rawContent));
}
throw new IllegalArgumentException("Unsupported content type: " + contentType);
}
public <T> T getFoxml(String pid, KnownDatastreams dsId, Class<T> returnType) throws IOException, UnsupportedContentFormatException {
// Determine supported formats for the content
ContentFormat supportedFormat = determineSupportedFormat(id);
// Validate the requested format
if ((contentType == String.class && !supportedFormat.supportsString()) ||
(contentType == InputStream.class && !supportedFormat.supportsStream()) ||
(contentType == Document.class && !supportedFormat.supportsXml())) {
throw new UnsupportedContentFormatException("Format not supported for content ID: " + id);
}
// Retrieve content as bytes
byte[] rawContent = fetchContentFromStorage(id);
// Convert content to the requested format
if (contentType == String.class) {
return contentType.cast(new String(rawContent, StandardCharsets.UTF_8));
} else if (contentType == InputStream.class) {
return contentType.cast(new ByteArrayInputStream(rawContent));
} else if (contentType == Document.class) {
return contentType.cast(parseXml(rawContent));
}
throw new IllegalArgumentException("Unsupported content type: " + contentType);
}
StreamContentHelper getStreamContentHelper();

// TODO here we always use AkubraUtils.getStreamContent but we have also AkubraObject.AkubraDatastream for fetching stream content
private ContentFormat determineSupportedFormat(String id) {
// Example logic to determine supported formats
if (id.startsWith("streamOnly")) {
return new ContentFormat(false, true, false);
} else {
return new ContentFormat(true, true, true);
}
}
private byte[] fetchContentFromStorage(String id) {
// Mock: Fetch content as bytes from your storage
return ("<xml>Content for ID: " + id + "</xml>").getBytes(StandardCharsets.UTF_8);
}
private Document parseXml(byte[] content) throws IOException {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
return factory.newDocumentBuilder().parse(new ByteArrayInputStream(content));
} catch (Exception e) {
throw new IOException("Failed to parse XML", e);
}
}

// TODO just one method rendering 2 content types; also we can add new par dsId and if null the whole foxml will be returned
// <--- AkubraObject.getFoXml
public org.dom4j.Document getDatastreamXml(String pid, String dsId) throws RepositoryException, IOException {
Lock readLock = AkubraDOManager.getReadLock(pid);
try {
RepositoryObject object = akubraRepositoryImpl.getObject(pid);
if (object.streamExists(dsId)) {
org.dom4j.Document foxml = Utils.inputstreamToDocument(object.getFoxml(), true);
org.dom4j.Element dcEl = (org.dom4j.Element) Dom4jUtils.buildXpath(String.format("/foxml:digitalObject/foxml:datastream[@ID='%s']", dsId)).selectSingleNode(foxml);
org.dom4j.Element detached = (org.dom4j.Element) dcEl.detach();
org.dom4j.Document result = DocumentHelper.createDocument();
result.add(detached);
return result;
} else {
return null;
}
} finally {
readLock.unlock();
}
}
@Override
public InputStream getFoxml(String pid, boolean archive) throws IOException {
try {
if (archive){
DigitalObject obj = manager.readObjectCloneFromStorage(pid);
manager.resolveArchivedDatastreams(obj);
return this.manager.marshallObject(obj);
}else {
return this.manager.retrieveObject(pid);
}
} catch (Exception e) {
throw new IOException(e);
}
}
@Override
public org.dom4j.Document getFoxml(String pid) throws RepositoryException, IOException {
Lock readLock = AkubraDOManager.getReadLock(pid);
try {
RepositoryObject object = akubraRepositoryImpl.getObject(pid);
return Utils.inputstreamToDocument(object.getFoxml(), true);
} finally {
readLock.unlock();
}
}

// <--- AkubraObject.getStream.getContent (6x)
public InputStream getLatestVersionOfDatastream(String pid, String dsId) throws RepositoryException, IOException {
Lock readLock = AkubraDOManager.getReadLock(pid);
try {
Expand All @@ -337,6 +364,62 @@ public InputStream getLatestVersionOfDatastream(String pid, String dsId) throws
readLock.unlock();
}
}
// <-- DigitalObject, AkubraUtils.getLastStreamVersion (3x)
public InputStream getDataStream(String pid, String datastreamName) throws IOException {
try {
pid = makeSureObjectPid(pid);
if (this.accessLog != null && this.accessLog.isReportingAccess(pid, datastreamName)) {
reportAccess(pid, datastreamName);
}
DigitalObject object = manager.readObjectFromStorage(pid);
if (object != null) {
DatastreamVersionType stream = AkubraUtils.getLastStreamVersion(object, datastreamName);
if (stream != null) {
return AkubraUtils.getStreamContent(stream, manager);
} else {
throw new IOException("cannot find stream '" + datastreamName + "' for pid '" + pid + "'");
}
} else {
throw new IOException("cannot find pid '" + pid + "'");
}
} catch (Exception e) {
throw new IOException(e);
}
}

// getLatestVersionOfDatastream (4x)
public org.dom4j.Document getLatestVersionOfInlineXmlDatastream(String pid, String dsId) throws RepositoryException, IOException {
InputStream is = getLatestVersionOfDatastream(pid, dsId);
return is == null ? null : Utils.inputstreamToDocument(is, true);
}
// getLatestVersionOfDatastream (1x)
public String getLatestVersionOfManagedTextDatastream(String pid, String dsId) throws RepositoryException, IOException {
InputStream is = getLatestVersionOfDatastream(pid, dsId);
return is == null ? null : Utils.inputstreamToString(is);
}

// <-- DigitalObject, AkubraUtils.getLastStreamVersion (3x)
public Document getStream(String pid, String streamName) throws IOException {
DigitalObject object = manager.readObjectFromStorage(pid);
if (object != null) {
DatastreamVersionType stream = AkubraUtils.getLastStreamVersion(object, streamName);
if (stream != null) {
if (stream.getXmlContent() != null) {
List<Element> elementList = stream.getXmlContent().getAny();
if (!elementList.isEmpty()) {
return elementList.get(0).getOwnerDocument();
} else {
throw new IOException("Datastream not found: " + pid + " - " + streamName);
}
} else {
throw new IOException("Expected XML datastream: " + pid + " - " + streamName);
}
}
throw new IOException("Datastream not found: " + pid + " - " + streamName);
}
throw new IOException("Object not found: " + pid);
}

@Override
public InputStream getImgFull(String pid) throws IOException, RepositoryException {
this.accessLog.reportAccess(pid, KnownDatastreams.IMG_FULL.toString());
Expand Down Expand Up @@ -385,22 +468,10 @@ public InputStream getSmallThumbnail(String pid) throws IOException {
public InputStream getImageFULL(String pid) throws IOException {
return getDataStream(pid, FedoraUtils.IMG_FULL_STREAM);
}
// text data stream
@Override
public String getLatestVersionOfManagedTextDatastream(String pid, String dsId) throws RepositoryException, IOException {
InputStream is = getLatestVersionOfDatastream(pid, dsId);
return is == null ? null : Utils.inputstreamToString(is);
}
@Override
public String getOcrText(String pid) throws IOException, RepositoryException {
return getLatestVersionOfManagedTextDatastream(pid, KnownDatastreams.OCR_TEXT.toString());
}
// XML data stream
@Override
public org.dom4j.Document getLatestVersionOfInlineXmlDatastream(String pid, String dsId) throws RepositoryException, IOException {
InputStream is = getLatestVersionOfDatastream(pid, dsId);
return is == null ? null : Utils.inputstreamToDocument(is, true);
}
@Override
public org.dom4j.Document getRelsExt(String pid, boolean namespaceAware) throws IOException, RepositoryException {
org.dom4j.Document doc = getLatestVersionOfInlineXmlDatastream(pid, KnownDatastreams.RELS_EXT.toString());
Expand Down Expand Up @@ -458,6 +529,7 @@ public org.dom4j.Document getOcrAlto(String pid, boolean namespaceAware) throws
}
return doc;
}
//----------------------------------------------------------------------------------------------------------------
// --- check stream exists
@Override
public boolean isStreamAvailable(String pid, String dsId) throws IOException, RepositoryException {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package cz.incad.kramerius.fedora.impl.tmp;

public class ContentFormat {
private final boolean supportsString;
private final boolean supportsStream;
private final boolean supportsXml;

public ContentFormat(boolean supportsString, boolean supportsStream, boolean supportsXml) {
this.supportsString = supportsString;
this.supportsStream = supportsStream;
this.supportsXml = supportsXml;
}

public boolean supportsString() {
return supportsString;
}

public boolean supportsStream() {
return supportsStream;
}

public boolean supportsXml() {
return supportsXml;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package cz.incad.kramerius.fedora.impl.tmp;

public class UnsupportedContentFormatException extends Exception {
public UnsupportedContentFormatException(String message) {
super(message);
}
}

0 comments on commit c7a152b

Please sign in to comment.