001/*
002 * Copyright 2021 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 */
016package org.fcrepo.migration.handlers.ocfl;
017
018import java.io.InputStream;
019import java.time.OffsetDateTime;
020import java.util.List;
021import java.util.stream.Stream;
022
023import io.micrometer.core.instrument.Metrics;
024import io.micrometer.core.instrument.Timer;
025import org.fcrepo.storage.ocfl.CommitType;
026import org.fcrepo.storage.ocfl.OcflObjectSession;
027import org.fcrepo.storage.ocfl.OcflVersionInfo;
028import org.fcrepo.storage.ocfl.ResourceContent;
029import org.fcrepo.storage.ocfl.ResourceHeaders;
030
031/**
032 * A wrapper similar to the FcrepoOcflObjectSessionWrapper to time operations
033 *
034 * @author mikejritter
035 */
036public class OcflObjectSessionWrapper implements OcflObjectSession {
037
038    private final OcflObjectSession inner;
039
040    private static final String METRIC_NAME = "fcrepo.storage.ocfl.object";
041    private static final String OPERATION = "operation";
042    private static final Timer writeTimer = Metrics.timer(METRIC_NAME, OPERATION, "write");
043    private static final Timer writeHeadersTimer = Metrics.timer(METRIC_NAME, OPERATION, "writeHeaders");
044    private static final Timer deleteContentTimer = Metrics.timer(METRIC_NAME, OPERATION, "deleteContent");
045    private static final Timer deleteResourceTimer = Metrics.timer(METRIC_NAME, OPERATION, "deleteResource");
046    private static final Timer readHeadersTimer = Metrics.timer(METRIC_NAME, OPERATION, "readHeaders");
047    private static final Timer readContentTimer = Metrics.timer(METRIC_NAME, OPERATION, "readContent");
048    private static final Timer listVersionsTimer = Metrics.timer(METRIC_NAME, OPERATION, "listVersions");
049    private static final Timer containsResourceTimer = Metrics.timer(METRIC_NAME, OPERATION, "containsResource");
050    private static final Timer commitTimer = Metrics.timer(METRIC_NAME, OPERATION, "commit");
051
052
053    public OcflObjectSessionWrapper(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        // The ocfl write further down expects content to be nullable, so if it is null just continue to pass it down
070        final var countingStream = content != null ? new CountingInputStream(content) : null;
071        return writeTimer.record(() -> inner.writeResource(headers, countingStream));
072    }
073
074    @Override
075    public void writeHeaders(final ResourceHeaders headers) {
076        writeHeadersTimer.record(() -> inner.writeHeaders(headers));
077    }
078
079    @Override
080    public void deleteContentFile(final ResourceHeaders headers) {
081        deleteContentTimer.record(() -> inner.deleteContentFile(headers));
082    }
083
084    @Override
085    public void deleteResource(final String resourceId) {
086        deleteResourceTimer.record(() -> inner.deleteResource(resourceId));
087    }
088
089    @Override
090    public boolean containsResource(final String resourceId) {
091        return containsResourceTimer.record(() -> inner.containsResource(resourceId));
092    }
093
094    @Override
095    public ResourceHeaders readHeaders(final String resourceId) {
096        return readHeadersTimer.record(() -> inner.readHeaders(resourceId));
097    }
098
099    @Override
100    public ResourceHeaders readHeaders(final String resourceId, final String versionNumber) {
101        return readHeadersTimer.record(() -> inner.readHeaders(resourceId, versionNumber));
102    }
103
104    @Override
105    public ResourceContent readContent(final String resourceId) {
106        return readContentTimer.record(() -> inner.readContent(resourceId));
107    }
108
109    @Override
110    public ResourceContent readContent(final String resourceId, final String versionNumber) {
111        return readContentTimer.record(() -> inner.readContent(resourceId, versionNumber));
112    }
113
114    @Override
115    public ResourceContent readRange(final String resourceId, final String versionNumber,
116                                     final long startPosition, final long endPosition) {
117        return readContentTimer.record(() -> inner.readRange(resourceId, versionNumber,
118                                                        startPosition, endPosition));
119    }
120
121    @Override
122    public ResourceContent readRange(final String resourceId, final long startPosition, final long endPosition) {
123        return readContentTimer.record(() -> inner.readRange(resourceId, null, startPosition, endPosition));
124    }
125
126    @Override
127    public List<OcflVersionInfo> listVersions(final String resourceId) {
128        return listVersionsTimer.record(() -> inner.listVersions(resourceId));
129    }
130
131    @Override
132    public Stream<ResourceHeaders> streamResourceHeaders() {
133        return inner.streamResourceHeaders();
134    }
135
136    @Override
137    public void versionCreationTimestamp(final OffsetDateTime timestamp) {
138        inner.versionCreationTimestamp(timestamp);
139    }
140
141    @Override
142    public void versionAuthor(final String name, final String address) {
143        inner.versionAuthor(name, address);
144    }
145
146    @Override
147    public void versionMessage(final String message) {
148        inner.versionMessage(message);
149    }
150
151    @Override
152    public void invalidateCache(final String objectId) {
153        inner.invalidateCache(objectId);
154    }
155
156    @Override
157    public void commitType(final CommitType commitType) {
158        inner.commitType(commitType);
159    }
160
161    @Override
162    public void commit() {
163        commitTimer.record(inner::commit);
164    }
165
166    @Override
167    public void abort() {
168        inner.abort();
169    }
170
171    @Override
172    public void rollback() {
173        inner.rollback();
174    }
175
176    @Override
177    public boolean isOpen() {
178        return inner.isOpen();
179    }
180
181    @Override
182    public void close() {
183        inner.close();
184    }
185}