001/* 002 * Copyright 2019 DuraSpace, Inc. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.fcrepo.migration.handlers.ocfl; 018 019import edu.wisc.library.ocfl.api.MutableOcflRepository; 020import edu.wisc.library.ocfl.api.model.ObjectVersionId; 021import edu.wisc.library.ocfl.core.OcflRepositoryBuilder; 022import edu.wisc.library.ocfl.core.extension.storage.layout.config.HashedNTupleLayoutConfig; 023import edu.wisc.library.ocfl.core.path.mapper.LogicalPathMappers; 024import edu.wisc.library.ocfl.core.storage.filesystem.FileSystemOcflStorage; 025import org.apache.commons.io.IOUtils; 026import org.apache.commons.lang3.SystemUtils; 027import org.fcrepo.storage.ocfl.InteractionModel; 028import org.fcrepo.storage.ocfl.OcflObjectSession; 029import org.fcrepo.storage.ocfl.OcflObjectSessionFactory; 030import org.fcrepo.storage.ocfl.ResourceContent; 031import org.fcrepo.storage.ocfl.ResourceHeaders; 032import org.junit.Before; 033import org.junit.Rule; 034import org.junit.Test; 035import org.junit.rules.TemporaryFolder; 036 037import java.io.IOException; 038import java.nio.file.Files; 039import java.nio.file.Path; 040 041import static org.junit.Assert.assertEquals; 042import static org.junit.Assert.assertTrue; 043 044/** 045 * @author pwinckles 046 */ 047public class PlainOcflObjectSessionTest { 048 049 @Rule 050 public TemporaryFolder tempDir = new TemporaryFolder(); 051 052 private Path ocflRoot; 053 private Path staging; 054 055 private MutableOcflRepository ocflRepo; 056 private OcflObjectSessionFactory plainSessionFactory; 057 058 private static final String AG_ID = "info:fedora/foo"; 059 060 @Before 061 public void setup() throws IOException { 062 ocflRoot = tempDir.newFolder("ocfl").toPath(); 063 staging = tempDir.newFolder("staging").toPath(); 064 065 final var logicalPathMapper = SystemUtils.IS_OS_WINDOWS ? 066 LogicalPathMappers.percentEncodingWindowsMapper() : LogicalPathMappers.percentEncodingLinuxMapper(); 067 068 ocflRepo = new OcflRepositoryBuilder() 069 .defaultLayoutConfig(new HashedNTupleLayoutConfig()) 070 .logicalPathMapper(logicalPathMapper) 071 .storage(FileSystemOcflStorage.builder().repositoryRoot(ocflRoot).build()) 072 .workDir(staging) 073 .buildMutable(); 074 075 plainSessionFactory = new PlainOcflObjectSessionFactory(ocflRepo, staging, 076 "testing", "fedoraAdmin", "info:fedora/fedoraAdmin", false); 077 } 078 079 @Test 080 public void writeBinary() throws IOException { 081 final var dsId = "bar"; 082 final var resourceId = AG_ID + "/" + dsId; 083 final var content = binary(resourceId, "test"); 084 085 final var session = newSession(); 086 087 write(content, session); 088 089 session.commit(); 090 091 assertEquals("test", 092 IOUtils.toString(ocflRepo.getObject(ObjectVersionId.head(AG_ID)).getFile(dsId).getStream())); 093 } 094 095 @Test 096 public void writeRdf() throws IOException { 097 final var dsId = "baz"; 098 final var resourceId = AG_ID + "/" + dsId + "/fcr:metadata"; 099 final var content = rdf(resourceId, "desc"); 100 101 final var session = newSession(); 102 103 write(content, session); 104 105 session.commit(); 106 107 assertEquals("desc", 108 IOUtils.toString(ocflRepo.getObject(ObjectVersionId.head(AG_ID)) 109 .getFile(dsId + "~fcr-desc.nt").getStream())); 110 } 111 112 @Test 113 public void writeAg() throws IOException { 114 final var content = rdf(AG_ID, "ag"); 115 116 final var session = newSession(); 117 118 write(content, session); 119 120 session.commit(); 121 122 assertEquals("ag", 123 IOUtils.toString(ocflRepo.getObject(ObjectVersionId.head(AG_ID)) 124 .getFile("fcr-container.nt").getStream())); 125 } 126 127 @Test 128 public void worksOnWindows() throws IOException { 129 final var dsId = "bar:baz"; 130 final var resourceId = AG_ID + "/" + dsId; 131 final var content = binary(resourceId, "test"); 132 133 final var session = newSession(); 134 135 write(content, session); 136 137 session.commit(); 138 139 assertEquals("test", 140 IOUtils.toString(ocflRepo.getObject(ObjectVersionId.head(AG_ID)).getFile(dsId).getStream())); 141 } 142 143 @Test 144 public void cleanupOnAbort() { 145 final var dsId = "bar:baz"; 146 final var resourceId = AG_ID + "/" + dsId; 147 final var content = binary(resourceId, "test"); 148 149 final var session = newSession(); 150 151 write(content, session); 152 153 session.abort(); 154 155 assertTrue(Files.notExists(staging.resolve(session.sessionId()))); 156 } 157 158 private void write(final ResourceContent content, final OcflObjectSession session) { 159 session.writeResource(content.getHeaders(), content.getContentStream().get()); 160 } 161 162 private OcflObjectSession newSession() { 163 return plainSessionFactory.newSession(AG_ID); 164 } 165 166 private ResourceContent ag(final String resourceId, final String content) { 167 final var headers = headers(resourceId); 168 headers.withInteractionModel(InteractionModel.BASIC_CONTAINER.getUri()); 169 headers.withArchivalGroup(true); 170 return new ResourceContent(IOUtils.toInputStream(content), headers.build()); 171 } 172 173 private ResourceContent binary(final String resourceId, final String content) { 174 final var headers = headers(resourceId); 175 headers.withInteractionModel(InteractionModel.NON_RDF.getUri()); 176 return new ResourceContent(IOUtils.toInputStream(content), headers.build()); 177 } 178 179 private ResourceContent rdf(final String resourceId, final String content) { 180 final var headers = headers(resourceId); 181 headers.withInteractionModel(InteractionModel.NON_RDF_DESCRIPTION.getUri()); 182 return new ResourceContent(IOUtils.toInputStream(content), headers.build()); 183 } 184 185 private ResourceHeaders.Builder headers(final String resourceId) { 186 final var headers = ResourceHeaders.builder(); 187 headers.withId(resourceId); 188 headers.withParent(AG_ID); 189 return headers; 190 } 191 192}