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 List<OcflVersionInfo> listVersions(final String resourceId) {
116        return listVersionsTimer.record(() -> inner.listVersions(resourceId));
117    }
118
119    @Override
120    public Stream<ResourceHeaders> streamResourceHeaders() {
121        return inner.streamResourceHeaders();
122    }
123
124    @Override
125    public void versionCreationTimestamp(final OffsetDateTime timestamp) {
126        inner.versionCreationTimestamp(timestamp);
127    }
128
129    @Override
130    public void versionAuthor(final String name, final String address) {
131        inner.versionAuthor(name, address);
132    }
133
134    @Override
135    public void versionMessage(final String message) {
136        inner.versionMessage(message);
137    }
138
139    @Override
140    public void commitType(final CommitType commitType) {
141        inner.commitType(commitType);
142    }
143
144    @Override
145    public void commit() {
146        commitTimer.record(inner::commit);
147    }
148
149    @Override
150    public void abort() {
151        inner.abort();
152    }
153
154    @Override
155    public void rollback() {
156        inner.rollback();
157    }
158
159    @Override
160    public boolean isOpen() {
161        return inner.isOpen();
162    }
163
164    @Override
165    public void close() {
166        inner.close();
167    }
168}