001package co.codewizards.cloudstore.local.persistence;
002
003import static co.codewizards.cloudstore.core.util.Util.*;
004
005import java.util.HashSet;
006import java.util.Set;
007
008import javax.jdo.annotations.Discriminator;
009import javax.jdo.annotations.DiscriminatorStrategy;
010import javax.jdo.annotations.Index;
011import javax.jdo.annotations.Indices;
012import javax.jdo.annotations.Inheritance;
013import javax.jdo.annotations.InheritanceStrategy;
014import javax.jdo.annotations.NullValue;
015import javax.jdo.annotations.PersistenceCapable;
016import javax.jdo.annotations.Persistent;
017import javax.jdo.annotations.Queries;
018import javax.jdo.annotations.Query;
019
020import co.codewizards.cloudstore.core.oio.File;
021
022@PersistenceCapable
023@Inheritance(strategy=InheritanceStrategy.SUPERCLASS_TABLE)
024@Discriminator(strategy=DiscriminatorStrategy.VALUE_MAP, value="NormalFile")
025@Indices({
026        @Index(name="NormalFile_sha1_length", members={"sha1", "length"})
027})
028@Queries({
029        @Query(name="getNormalFiles_sha1_length", value="SELECT WHERE this.sha1 == :sha1 && this.length == :length")
030})
031public class NormalFile extends RepoFile {
032
033        private long length;
034
035        @Persistent(nullValue=NullValue.EXCEPTION)
036        private String sha1;
037
038        private boolean inProgress;
039
040        @Persistent(mappedBy="normalFile", dependentElement="true")
041        private Set<FileChunk> fileChunks;
042
043        public NormalFile() { }
044
045        /**
046         * Gets the file size in bytes.
047         * <p>
048         * It reflects the {@link File#length() File.length} property.
049         * @return the file size in bytes.
050         */
051        public long getLength() {
052                return length;
053        }
054        public void setLength(final long length) {
055                if (! equal(this.length, length))
056                        this.length = length;
057        }
058        /**
059         * Gets the <a href="http://en.wikipedia.org/wiki/SHA-1">SHA-1</a> of the file.
060         * @return the <a href="http://en.wikipedia.org/wiki/SHA-1">SHA-1</a> of the file.
061         */
062        public String getSha1() {
063                return sha1;
064        }
065        public void setSha1(final String sha) {
066                if (! equal(this.sha1, sha))
067                        this.sha1 = sha;
068        }
069
070        /**
071         * Is this file in progress of being synced?
072         * <p>
073         * If yes, it is ignored in change-sets in order to prevent inconsistent data to propagate further.
074         * <p>
075         * TODO We should later implement a mechanism that parks all modifications locally (not in the DB, but in the
076         * meta-directory) before applying them to the file in one transaction.
077         * @return <code>true</code>, if it is currently in progress of being synced; <code>false</code> otherwise.
078         */
079        public boolean isInProgress() {
080                return inProgress;
081        }
082        public void setInProgress(final boolean inProgress) {
083                if (! equal(this.inProgress, inProgress))
084                        this.inProgress = inProgress;
085        }
086
087        public Set<FileChunk> getFileChunks() {
088                // TODO (1) This should be a SortedSet (a TreeSet), but for whatever reason, this does not work anymore
089                // and causes ClassCastExceptions :-(
090                // TODO (2) this should return a decorator which automatically calls FileChunk.makeReadOnly() when
091                // enlisting a new instance!
092                if (fileChunks == null)
093                        fileChunks = new HashSet<>();
094
095                return fileChunks;
096        }
097}