001/* 002 * The contents of this file are subject to the license and copyright 003 * detailed in the LICENSE and NOTICE files at the root of the source 004 * tree. 005 */ 006 007package org.fcrepo.persistence.ocfl.impl; 008 009import io.micrometer.core.instrument.Metrics; 010import io.micrometer.core.instrument.Timer; 011import org.fcrepo.common.lang.CheckedRunnable; 012import org.fcrepo.common.metrics.MetricsHelper; 013import org.fcrepo.persistence.api.exceptions.PersistentItemNotFoundException; 014import org.fcrepo.persistence.api.exceptions.PersistentStorageException; 015import org.fcrepo.storage.ocfl.CommitType; 016import org.fcrepo.storage.ocfl.OcflObjectSession; 017import org.fcrepo.storage.ocfl.OcflVersionInfo; 018import org.fcrepo.storage.ocfl.ResourceContent; 019import org.fcrepo.storage.ocfl.ResourceHeaders; 020import org.fcrepo.storage.ocfl.exception.NotFoundException; 021 022import java.io.InputStream; 023import java.time.OffsetDateTime; 024import java.util.List; 025import java.util.concurrent.Callable; 026import java.util.stream.Stream; 027 028/** 029 * Wrapper around an OcflObjectSession to convert exceptions into fcrepo exceptions and time operations 030 * 031 * @author pwinckles 032 */ 033public class FcrepoOcflObjectSessionWrapper implements OcflObjectSession { 034 035 private final OcflObjectSession inner; 036 037 private static final String METRIC_NAME = "fcrepo.storage.ocfl.object"; 038 private static final String OPERATION = "operation"; 039 private static final Timer writeTimer = Metrics.timer(METRIC_NAME, OPERATION, "write"); 040 private static final Timer writeHeadersTimer = Metrics.timer(METRIC_NAME, OPERATION, "writeHeaders"); 041 private static final Timer deleteContentTimer = Metrics.timer(METRIC_NAME, OPERATION, "deleteContent"); 042 private static final Timer deleteResourceTimer = Metrics.timer(METRIC_NAME, OPERATION, "deleteResource"); 043 private static final Timer containsResourceTimer = Metrics.timer(METRIC_NAME, OPERATION, "containsResource"); 044 private static final Timer readHeadersTimer = Metrics.timer(METRIC_NAME, OPERATION, "readHeaders"); 045 private static final Timer readContentTimer = Metrics.timer(METRIC_NAME, OPERATION, "readContent"); 046 private static final Timer readRangeTimer = Metrics.timer(METRIC_NAME, OPERATION, "readRange"); 047 private static final Timer listVersionsTimer = Metrics.timer(METRIC_NAME, OPERATION, "listVersions"); 048 private static final Timer commitTimer = Metrics.timer(METRIC_NAME, OPERATION, "commit"); 049 050 /** 051 * @param inner the session to wrap 052 */ 053 public FcrepoOcflObjectSessionWrapper(final OcflObjectSession inner) { 054 this.inner = inner; 055 } 056 057 @Override 058 public String sessionId() { 059 return inner.sessionId(); 060 } 061 062 @Override 063 public String ocflObjectId() { 064 return inner.ocflObjectId(); 065 } 066 067 @Override 068 public ResourceHeaders writeResource(final ResourceHeaders headers, final InputStream content) { 069 return MetricsHelper.time(writeTimer, () -> { 070 return exec(() -> inner.writeResource(headers, content)); 071 }); 072 } 073 074 @Override 075 public void writeHeaders(final ResourceHeaders headers) { 076 writeHeadersTimer.record(() -> { 077 exec(() -> inner.writeHeaders(headers)); 078 }); 079 } 080 081 @Override 082 public void deleteContentFile(final ResourceHeaders headers) { 083 deleteContentTimer.record(() -> { 084 exec(() -> inner.deleteContentFile(headers)); 085 }); 086 } 087 088 @Override 089 public void deleteResource(final String resourceId) { 090 deleteResourceTimer.record(() -> { 091 exec(() -> inner.deleteResource(resourceId)); 092 }); 093 } 094 095 @Override 096 public boolean containsResource(final String resourceId) { 097 return MetricsHelper.time(containsResourceTimer, () -> { 098 return exec(() -> inner.containsResource(resourceId)); 099 }); 100 } 101 102 @Override 103 public ResourceHeaders readHeaders(final String resourceId) { 104 return MetricsHelper.time(readHeadersTimer, () -> { 105 return exec(() -> inner.readHeaders(resourceId)); 106 }); 107 } 108 109 @Override 110 public ResourceHeaders readHeaders(final String resourceId, final String versionNumber) { 111 return MetricsHelper.time(readHeadersTimer, () -> { 112 return exec(() -> inner.readHeaders(resourceId, versionNumber)); 113 }); 114 } 115 116 @Override 117 public ResourceContent readContent(final String resourceId) { 118 return MetricsHelper.time(readContentTimer, () -> { 119 return exec(() -> inner.readContent(resourceId)); 120 }); 121 } 122 123 @Override 124 public ResourceContent readContent(final String resourceId, final String versionNumber) { 125 return MetricsHelper.time(readContentTimer, () -> { 126 return exec(() -> inner.readContent(resourceId, versionNumber)); 127 }); 128 } 129 130 @Override 131 public ResourceContent readRange(final String resourceId, final long start, final long end) { 132 return MetricsHelper.time(readRangeTimer, () -> 133 exec(() -> inner.readRange(resourceId, start, end))); 134 } 135 136 @Override 137 public ResourceContent readRange(final String resourceId, final String versionNumber, 138 final long start, final long end) { 139 return MetricsHelper.time(readRangeTimer, () -> 140 exec(() -> inner.readRange(resourceId, versionNumber, start, end))); 141 } 142 143 @Override 144 public List<OcflVersionInfo> listVersions(final String resourceId) { 145 return MetricsHelper.time(listVersionsTimer, () -> { 146 return exec(() -> inner.listVersions(resourceId)); 147 }); 148 } 149 150 @Override 151 public Stream<ResourceHeaders> streamResourceHeaders() { 152 return exec(inner::streamResourceHeaders); 153 } 154 155 @Override 156 public void versionCreationTimestamp(final OffsetDateTime timestamp) { 157 inner.versionCreationTimestamp(timestamp); 158 } 159 160 @Override 161 public void versionAuthor(final String name, final String address) { 162 inner.versionAuthor(name, address); 163 } 164 165 @Override 166 public void versionMessage(final String message) { 167 inner.versionMessage(message); 168 } 169 170 @Override 171 public void invalidateCache(final String resourceId) { 172 inner.invalidateCache(resourceId); 173 } 174 175 @Override 176 public void commitType(final CommitType commitType) { 177 inner.commitType(commitType); 178 } 179 180 @Override 181 public void commit() { 182 commitTimer.record(() -> { 183 exec(inner::commit); 184 }); 185 } 186 187 @Override 188 public void rollback() { 189 exec(inner::rollback); 190 } 191 192 @Override 193 public void abort() { 194 exec(inner::abort); 195 } 196 197 @Override 198 public boolean isOpen() { 199 return inner.isOpen(); 200 } 201 202 @Override 203 public void close() { 204 exec(inner::close); 205 } 206 207 private <T> T exec(final Callable<T> callable) throws PersistentStorageException { 208 try { 209 return callable.call(); 210 } catch (final NotFoundException e) { 211 throw new PersistentItemNotFoundException(e.getMessage(), e); 212 } catch (final Exception e) { 213 throw new PersistentStorageException(e.getMessage(), e); 214 } 215 } 216 217 private void exec(final CheckedRunnable runnable) throws PersistentStorageException { 218 try { 219 runnable.run(); 220 } catch (final NotFoundException e) { 221 throw new PersistentItemNotFoundException(e.getMessage(), e); 222 } catch (final Exception e) { 223 throw new PersistentStorageException(e.getMessage(), e); 224 } 225 } 226 227}