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}