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    public 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
084    /**
085     * Get the identifier for the entry's store
086     * @return the store identifier
087     */
088    @Override
089    public String getStoreIdentifier() {
090        return storeIdentifier;
091    }
092
093    @Override
094    public boolean equals(final Object obj) {
095        if (obj instanceof FixityResult) {
096            final FixityResult that = (FixityResult) obj;
097            return computedSize == that.getComputedSize() &&
098                    computedChecksum.equals(that.getComputedChecksum()) &&
099                    equalsNullAware(usedAlgorithm, that.getUsedAlgorithm());
100        }
101        return false;
102    }
103
104    private boolean equalsNullAware(final Object a, final Object b) {
105        return (a == null && b == null) ||
106                (a != null && a.equals(b)) ||
107                (b != null && b.equals(a));
108    }
109
110    @Override
111    public int hashCode() {
112        return hash(computedSize, computedChecksum);
113    }
114
115    @Override
116    public String toString() {
117        return "Fixity: checksum: " + computedChecksum + " / " + computedSize;
118    }
119
120    /**
121     * Check if the fixity result matches the given checksum URI
122     * @param checksum the checksum uri
123     * @return true if the checksums match
124     */
125    @Override
126    public boolean matches(final URI checksum) {
127        return computedChecksum.equals(checksum);
128    }
129
130    /**
131     * Check if the fixity result matches the given size
132     * @param size the size
133     * @return true if fixity result matches the given size
134     */
135    @Override
136    public boolean matches(final long size) {
137        return computedSize == size;
138    }
139
140    /**
141     * Does the fixity entry match the given size and checksum?
142     * @param size bitstream size in bytes
143     * @param checksum checksum URI in the form urn:DIGEST:RESULT
144     * @return true if both conditions matched
145     */
146    @Override
147    public boolean matches(final long size, final URI checksum) {
148        return matches(size) && matches(checksum);
149    }
150
151    /**
152     * @return the status
153     */
154    @Override
155    public Set<FixityState> getStatus(final long size, final URI checksum) {
156
157        final Set<FixityState> status = EnumSet.noneOf(FixityState.class);
158
159
160        if (matches(size, checksum)) {
161            status.add(FixityState.SUCCESS);
162        } else {
163            if (!matches(size)) {
164                status.add(FixityState.BAD_SIZE);
165            }
166
167            if (!matches(checksum)) {
168                status.add(FixityState.BAD_CHECKSUM);
169            }
170        }
171
172        return status;
173    }
174
175    /**
176     * @return the computedSize
177     */
178    @Override
179    public long getComputedSize() {
180        return computedSize;
181    }
182
183    /**
184     * @return the computedChecksum
185     */
186    @Override
187    public URI getComputedChecksum() {
188        return computedChecksum;
189    }
190
191    @Override
192    public String getUsedAlgorithm() {
193        return usedAlgorithm;
194    }
195}