001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.kernel.modeshape.utils;
019
020import org.fcrepo.kernel.api.utils.FixityResult;
021
022import static java.util.Objects.hash;
023
024import java.net.URI;
025import java.util.EnumSet;
026import java.util.Set;
027
028/**
029 * Structure for presenting the results of a fixity check
030 * (and any repair operations that may have occurred)
031 *
032 * @author bbpennel
033 */
034public class FixityResultImpl implements FixityResult {
035
036    /**
037     * the size computed by the fixity check
038     */
039    private final long computedSize;
040
041    /**
042     * the checksum computed by the fixity check
043     */
044    private final URI computedChecksum;
045
046    private final String storeIdentifier;
047
048    private final String usedAlgorithm;
049
050    /**
051     * Prepare a fixity result given the computed checksum and size
052     * @param size the given size
053     * @param checksum the given checksum
054     */
055    public FixityResultImpl(final long size, final URI checksum) {
056        this("comparison-only-identifier", size, checksum);
057    }
058
059    /**
060     *
061     * @param storeIdentifier the store identifier
062     * @param size the size
063     * @param checksum the checksum
064     */
065    private FixityResultImpl(final String storeIdentifier, final long size, final URI checksum) {
066        this(storeIdentifier, size, checksum, null);
067    }
068
069    /**
070     *
071     * @param storeIdentifier the store identifier
072     * @param size the size
073     * @param checksum the checksum
074     * @param algorithm the algorithm used to calculate the checksum
075     */
076    public FixityResultImpl(final String storeIdentifier, final long size, final URI checksum, final String algorithm) {
077        this.storeIdentifier = storeIdentifier;
078        computedSize = size;
079        computedChecksum = checksum;
080        usedAlgorithm = algorithm;
081    }
082
083    @Override
084    public boolean equals(final Object obj) {
085        if (obj instanceof FixityResult) {
086            final FixityResult that = (FixityResult) obj;
087            return computedSize == that.getComputedSize() &&
088                    computedChecksum.equals(that.getComputedChecksum()) &&
089                    equalsNullAware(usedAlgorithm, that.getUsedAlgorithm());
090        }
091        return false;
092    }
093
094    private boolean equalsNullAware(final Object a, final Object b) {
095        return (a == null && b == null) ||
096                (a != null && a.equals(b)) ||
097                (b != null && b.equals(a));
098    }
099
100    @Override
101    public int hashCode() {
102        return hash(computedSize, computedChecksum);
103    }
104
105    @Override
106    public String toString() {
107        return "Fixity: checksum: " + computedChecksum + " / " + computedSize;
108    }
109
110    /**
111     * Check if the fixity result matches the given checksum URI
112     * @param checksum the checksum uri
113     * @return true if the checksums match
114     */
115    @Override
116    public boolean matches(final URI checksum) {
117        return computedChecksum.equals(checksum);
118    }
119
120    /**
121     * Check if the fixity result matches the given size
122     * @param size the size
123     * @return true if fixity result matches the given size
124     */
125    @Override
126    public boolean matches(final long size) {
127        return computedSize == size;
128    }
129
130    /**
131     * Does the fixity entry match the given size and checksum?
132     * @param size bitstream size in bytes
133     * @param checksum checksum URI in the form urn:DIGEST:RESULT
134     * @return true if both conditions matched
135     */
136    @Override
137    public boolean matches(final long size, final URI checksum) {
138        return matches(size) && matches(checksum);
139    }
140
141    /**
142     * @return the status
143     */
144    @Override
145    public Set<FixityState> getStatus(final long size, final URI checksum) {
146
147        final Set<FixityState> status = EnumSet.noneOf(FixityState.class);
148
149
150        if (matches(size, checksum)) {
151            status.add(FixityState.SUCCESS);
152        } else {
153            if (!matches(size)) {
154                status.add(FixityState.BAD_SIZE);
155            }
156
157            if (!matches(checksum)) {
158                status.add(FixityState.BAD_CHECKSUM);
159            }
160        }
161
162        return status;
163    }
164
165    /**
166     * @return the computedSize
167     */
168    @Override
169    public long getComputedSize() {
170        return computedSize;
171    }
172
173    /**
174     * @return the computedChecksum
175     */
176    @Override
177    public URI getComputedChecksum() {
178        return computedChecksum;
179    }
180
181    @Override
182    public String getUsedAlgorithm() {
183        return usedAlgorithm;
184    }
185}