Skip to content

Commit

Permalink
Merge branch 'develop': tape handling
Browse files Browse the repository at this point in the history
  • Loading branch information
joschrew committed Jan 31, 2024
2 parents a511910 + 31206ce commit ca1c019
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ protected void configure(HttpSecurity http) throws Exception {
.and()
.authorizeRequests()
.antMatchers("/export/**",
"/export-full/**",
"/download",
"/download-file/**",
"/login",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,13 @@ public ResponseEntity<?> fullExportRequest(
.body(new ResponseMessage(HttpStatus.ACCEPTED, "Your request is being processed."));
}

@ApiOperation(value = "Export the cold archive which was already moved to the hard drive.",
authorizations = { @Authorization(value = "basicAuth"), @Authorization(value = "bearer")})
@ApiOperation(value = "Export the cold archive which was already moved to the hard drive.")
@ApiResponses({
@ApiResponse(code = 200, message = "An archive with the specified identifier was found.", response = byte[].class),
@ApiResponse(code = 404, message = "An archive with the specified identifier was not found.", response = ResponseMessage.class),
@ApiResponse(code = 409, message = "The archive is still on tape. A full export request must be made first.", response = ResponseMessage.class)
})
@GetMapping(value = "/full-export", produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE, MediaType.APPLICATION_JSON_VALUE })
@GetMapping(value = "/export-full", produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE, MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<StreamingResponseBody> fullExport(
@ApiParam(value = "The PID or the PPN of the work.", required = true) @RequestParam String id,
@ApiParam(value = "Is this an internal ID or not (PID, PPN).", required = true) @RequestParam(defaultValue = "false") boolean isInternal) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,23 @@ public ResponseEntity<?> search(
if (StringUtils.isNotBlank(id)) {
Detail detail = elasticsearchService.getDetailsForPid(id);
if (detail == null) {
throw new HttpClientErrorException(HttpStatus.NOT_FOUND, ErrMsg.RECORD_NOT_FOUND);
} else {
return ResponseEntity.ok(detail);
Archive archive = ArchiveRepository.getLatestVersion(archiveRepository, id);
//Archive archive = null;
if (archive != null && archive.getPid() != null) {
detail = elasticsearchService.getDetailsForPid(archive.getPid());
if (detail == null) {
throw new HttpClientErrorException(
HttpStatus.INTERNAL_SERVER_ERROR,
"No search entry for a PID found which is registered in the mongdb and does not have a "
+ "next version"
);
}
detail.setInfoForPreviousPid(id);
} else {
throw new HttpClientErrorException(HttpStatus.NOT_FOUND, ErrMsg.RECORD_NOT_FOUND);
}
}
return ResponseEntity.ok(detail);
} else {
ResultSet resultSet = elasticsearchService.facetSearch(searchterm, limit, offset,
extended, isGT, metadatasearch, fulltextsearch, sort, field, value);
Expand Down
24 changes: 22 additions & 2 deletions src/main/java/ola/hd/longtermstorage/model/Detail.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,20 @@ public class Detail {
private boolean isGT;
@Field(type = FieldType.Text)
private FileTree fileTree;

public Detail(String PID, String ID, String title, String subtitle, String placeOfPublish, int yearOfPublish, String publisher, String creator, String genre, String label, String classification, String copyright, String license, String licenseURL, String owner, String ownerURL, boolean isGT, FileTree fileTree) {
/**
* If an ocrd-zip is updated with a newer version, currently the indexer replaces the search entry when the
* identifier in the metsfile didn't change. In this case the info for the latest version of this OCRD-ZIP should be
* returned and the PID for which the information was originally queried should be inserted here
*/
@Field(type = FieldType.Text)
private String infoForPreviousPid;

public Detail(
String PID, String ID, String title, String subtitle, String placeOfPublish, int yearOfPublish,
String publisher, String creator, String genre, String label, String classification, String copyright,
String license, String licenseURL, String owner, String ownerURL, boolean isGT, FileTree fileTree,
String infoForPreviousPid
) {
this.PID = PID;
this.ID = ID;
this.title = title;
Expand Down Expand Up @@ -215,4 +227,12 @@ public void setFileTree(FileTree fileTree) {
this.fileTree = fileTree;
}

public String getInfoForPreviousPid() {
return infoForPreviousPid;
}

public void setInfoForPreviousPid(String infoForPreviousPid) {
this.infoForPreviousPid = infoForPreviousPid;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,40 @@
import ola.hd.longtermstorage.domain.Archive;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;

@Repository
public interface ArchiveRepository extends MongoRepository<Archive, String> {

Archive findByPid(String pid);
Archive findByOnlineIdOrOfflineId(String onlineId, String offlineId);

/**
* Tries to find one of the latest versions of an archive.
*
* "One of the latest": If an archive (in the chain) has more than one next version, the first one of these is
* returned. So this function can lead to unwanted behaviour. However the normal case, a linear chain of next
* versions, is handled correctly
*
* @param archiveRepository
* @param archive
* @return
*/
public static Archive getLatestVersion(ArchiveRepository archiveRepository, String pid) {
Archive archive = archiveRepository.findByPid(pid);
if (archive == null) {
return null;
} else if (CollectionUtils.isEmpty(archive.getNextVersions())) {
return archive;
} else {
return getLatestVersion(archiveRepository, archive);
}
}

private static Archive getLatestVersion(ArchiveRepository archiveRepository, Archive archive) {
if (CollectionUtils.isEmpty(archive.getNextVersions())) {
return archive;
}
return ArchiveRepository.getLatestVersion(archiveRepository, archive.getNextVersions().get(0));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ ImportResult importZipFile(Path extractedDir,
*
* @param identifier The identifier of the archive
* @param type Full export or quick export
* @param nal To indicate if the identifier is an internal ID or not (PID, PPN,...)
* @param isInternal To indicate if the identifier is an internal ID or not (PID, PPN,...)
* @return The {@link Response} object to get the stream and close it properly.
* @throws IOException Thrown if something's wrong when connecting to the archive system
*/
Expand Down
47 changes: 39 additions & 8 deletions src/main/java/ola/hd/longtermstorage/service/CdstarService.java
Original file line number Diff line number Diff line change
Expand Up @@ -526,14 +526,16 @@ public Response export(String identifier, String type, boolean isInternal) throw
public void downloadFiles(String archiveId, String[] paths, OutputStream outputStream, boolean isInternal) throws IOException {

if (!isInternal) {
archiveId = this.getArchiveIdFromIdentifier(archiveId, onlineProfile);
archiveId = this.mapPidToArchiveId(archiveId, mirrorProfile, onlineProfile);
if (archiveId == null || archiveId.equals(NOT_FOUND)) {
throw new HttpClientErrorException(HttpStatus.NOT_FOUND, ErrMsg.ARCHIVE_NOT_FOUND);
}
}


// Set the base URL up to the archive level
String baseUrl = url + vault + "/" + archiveId;

// TODO: check the archive state. Throw an exception if the archive is in "archived" state

OkHttpClient client = new OkHttpClient();

// Build the GET request
Expand Down Expand Up @@ -637,9 +639,6 @@ private void updateProfile(String archiveId, String newProfile) throws IOExcepti
}
}

/* TODO: todo: this is not reliable, because we have archives(don't know why) without pid in
* cdstar-metadata. Must be changed: ask mongodb for archive-id from pid, at least as backup
* if pid in cdstar not found*/
private String getArchiveIdFromIdentifier(String identifier, String profile) throws IOException {
String fullUrl = url + vault;

Expand Down Expand Up @@ -796,7 +795,7 @@ public boolean isArchiveOnDisk(String identifier) throws IOException {
public String getArchiveInfo(String id, boolean withFile, int limit, int offset, boolean internalId) throws IOException {

if (!internalId) {
id = this.getArchiveIdFromIdentifier(id, onlineProfile);
id = this.mapPidToArchiveId(id, mirrorProfile, onlineProfile, offlineProfile);
}

String fullUrl = url + vault + "/" + id + "?with=meta";
Expand Down Expand Up @@ -835,7 +834,7 @@ public String getArchiveInfo(String id, boolean withFile, int limit, int offset,
public HttpFile getFile(String id, String path, boolean infoOnly, boolean internalId) throws IOException {

if (!internalId) {
id = this.getArchiveIdFromIdentifier(id, onlineProfile);
id = this.mapPidToArchiveId(id, mirrorProfile, onlineProfile);
}

String fullUrl = url + vault + "/" + id + "/" + path;
Expand Down Expand Up @@ -936,4 +935,36 @@ public Response exportFile(String pid, String path) throws IOException{
}

}

/**
* Get the archive-id (Id in Cdstar) for a PID
*
* When querying cdstart with a pid it must be mapped to an internalId: Every ocrd-zip is saved
* in an online and an offline archive (in Cdstar) when created. Offline archives can be moved
* to mirror archives (move from tape to disc). Uploading Ocrd-zips with previous versions
* deletes the online archive of that. So every pid **can** point to 3 different types of
* archives.
*
* This function searches for the archives of a pid with the provided profiles in order and
* returns the first archiveId found.
*
* example: `mapArchiveIdToPid("xyz", "default", "cold")`. This call would at first try to find
* an archive with the "xyz" as identifier and with the profile "default". If found the
* cdstar-id is returned. If not found it searches for an archive with the "xyz" identifier and
* the profile "cold"
*
* @param pid
* @param profiles - profiles to search in order
* @return
* @throws IOException
*/
private String mapPidToArchiveId(String pid, String...profiles) throws IOException {
for (String profile: profiles ) {
String cdstarId = this.getArchiveIdFromIdentifier(pid, profile);
if (cdstarId != null && cdstarId != NOT_FOUND) {
return cdstarId;
}
}
return NOT_FOUND;
}
}

0 comments on commit ca1c019

Please sign in to comment.