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 listVersionsTimer = Metrics.timer(METRIC_NAME, OPERATION, "listVersions"); 047 private static final Timer commitTimer = Metrics.timer(METRIC_NAME, OPERATION, "commit"); 048 049 /** 050 * @param inner the session to wrap 051 */ 052 public FcrepoOcflObjectSessionWrapper(final OcflObjectSession inner) { 053 this.inner = inner; 054 } 055 056 @Override 057 public String sessionId() { 058 return inner.sessionId(); 059 } 060 061 @Override 062 public String ocflObjectId() { 063 return inner.ocflObjectId(); 064 } 065 066 @Override 067 public ResourceHeaders writeResource(final ResourceHeaders headers, final InputStream content) { 068 return MetricsHelper.time(writeTimer, () -> { 069 return exec(() -> inner.writeResource(headers, content)); 070 }); 071 } 072 073 @Override 074 public void writeHeaders(final ResourceHeaders headers) { 075 writeHeadersTimer.record(() -> { 076 exec(() -> inner.writeHeaders(headers)); 077 }); 078 } 079 080 @Override 081 public void deleteContentFile(final ResourceHeaders headers) { 082 deleteContentTimer.record(() -> { 083 exec(() -> inner.deleteContentFile(headers)); 084 }); 085 } 086 087 @Override 088 public void deleteResource(final String resourceId) { 089 deleteResourceTimer.record(() -> { 090 exec(() -> inner.deleteResource(resourceId)); 091 }); 092 } 093 094 @Override 095 public boolean containsResource(final String resourceId) { 096 return MetricsHelper.time(containsResourceTimer, () -> { 097 return exec(() -> inner.containsResource(resourceId)); 098 }); 099 } 100 101 @Override 102 public ResourceHeaders readHeaders(final String resourceId) { 103 return MetricsHelper.time(readHeadersTimer, () -> { 104 return exec(() -> inner.readHeaders(resourceId)); 105 }); 106 } 107 108 @Override 109 public ResourceHeaders readHeaders(final String resourceId, final String versionNumber) { 110 return MetricsHelper.time(readHeadersTimer, () -> { 111 return exec(() -> inner.readHeaders(resourceId, versionNumber)); 112 }); 113 } 114 115 @Override 116 public ResourceContent readContent(final String resourceId) { 117 return MetricsHelper.time(readContentTimer, () -> { 118 return exec(() -> inner.readContent(resourceId)); 119 }); 120 } 121 122 @Override 123 public ResourceContent readContent(final String resourceId, final String versionNumber) { 124 return MetricsHelper.time(readContentTimer, () -> { 125 return exec(() -> inner.readContent(resourceId, versionNumber)); 126 }); 127 } 128 129 @Override 130 public List<OcflVersionInfo> listVersions(final String resourceId) { 131 return MetricsHelper.time(listVersionsTimer, () -> { 132 return exec(() -> inner.listVersions(resourceId)); 133 }); 134 } 135 136 @Override 137 public Stream<ResourceHeaders> streamResourceHeaders() { 138 return exec(inner::streamResourceHeaders); 139 } 140 141 @Override 142 public void versionCreationTimestamp(final OffsetDateTime timestamp) { 143 inner.versionCreationTimestamp(timestamp); 144 } 145 146 @Override 147 public void versionAuthor(final String name, final String address) { 148 inner.versionAuthor(name, address); 149 } 150 151 @Override 152 public void versionMessage(final String message) { 153 inner.versionMessage(message); 154 } 155 156 @Override 157 public void invalidateCache(final String resourceId) { 158 inner.invalidateCache(resourceId); 159 } 160 161 @Override 162 public void commitType(final CommitType commitType) { 163 inner.commitType(commitType); 164 } 165 166 @Override 167 public void commit() { 168 commitTimer.record(() -> { 169 exec(inner::commit); 170 }); 171 } 172 173 @Override 174 public void rollback() { 175 exec(inner::rollback); 176 } 177 178 @Override 179 public void abort() { 180 exec(inner::abort); 181 } 182 183 @Override 184 public boolean isOpen() { 185 return inner.isOpen(); 186 } 187 188 @Override 189 public void close() { 190 exec(inner::close); 191 } 192 193 private <T> T exec(final Callable<T> callable) throws PersistentStorageException { 194 try { 195 return callable.call(); 196 } catch (final NotFoundException e) { 197 throw new PersistentItemNotFoundException(e.getMessage(), e); 198 } catch (final Exception e) { 199 throw new PersistentStorageException(e.getMessage(), e); 200 } 201 } 202 203 private void exec(final CheckedRunnable runnable) throws PersistentStorageException { 204 try { 205 runnable.run(); 206 } catch (final NotFoundException e) { 207 throw new PersistentItemNotFoundException(e.getMessage(), e); 208 } catch (final Exception e) { 209 throw new PersistentStorageException(e.getMessage(), e); 210 } 211 } 212 213}