001/*
002 * Syncany, www.syncany.org
003 * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com>
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU General Public License as published by
007 * the Free Software Foundation, either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU General Public License for more details.
014 *
015 * You should have received a copy of the GNU General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018package org.syncany.database;
019
020import java.io.File;
021import java.util.Date;
022
023import org.syncany.database.FileContent.FileChecksum;
024import org.syncany.database.PartialFileHistory.FileHistoryId;
025
026/**
027 * A file version represents a version of a file at a certain time and captures
028 * all of a file's properties.
029 *
030 * <p>A {@link PartialFileHistory} typically consists of multiple <code>FileVersion</code>s,
031 * each of which is the incarnation of the same file, but with either changed properties,
032 * or changed content.
033 *
034 * <p>The <code>FileVersion</code>'s checksum attribute implicitly links to a {@link FileContent},
035 * which represents the content of a file. Multiple file versions can link to the same file content.
036 *
037 * @see PartialFileHistory
038 * @author Philipp C. Heckel (philipp.heckel@gmail.com)
039 */
040public class FileVersion implements Cloneable {
041        // Optional
042        private FileHistoryId fileHistoryId;
043
044        // Mandatory
045        private Long version; // TODO [low] This can be an Integer. No need for a long!
046        private String path;
047        private FileType type;
048        private FileStatus status;
049        private Long size;
050        private Date lastModified;
051
052        // Mandatory (if type is symlink)
053        private String linkTarget;
054
055        // Optional
056        private FileChecksum checksum;
057        private Date updated;
058        private String posixPermissions;
059        private String dosAttributes;
060
061        public FileVersion() {
062                // Fressen.
063        }
064
065        public FileHistoryId getFileHistoryId() {
066                return fileHistoryId;
067        }
068
069        public void setFileHistoryId(FileHistoryId fileHistoryId) {
070                this.fileHistoryId = fileHistoryId;
071        }
072
073        public Long getVersion() {
074                return version;
075        }
076
077        public void setVersion(Long version) {
078                this.version = version;
079        }
080
081        public FileType getType() {
082                return type;
083        }
084
085        public void setType(FileType type) {
086                this.type = type;
087        }
088
089        public Date getLastModified() {
090                return lastModified;
091        }
092
093        public void setLastModified(Date lastModified) {
094                this.lastModified = lastModified;
095        }
096
097        public Date getUpdated() {
098                return updated;
099        }
100
101        public void setUpdated(Date updated) {
102                this.updated = updated;
103        }
104
105        public FileStatus getStatus() {
106                return status;
107        }
108
109        public void setStatus(FileStatus status) {
110                this.status = status;
111        }
112
113        public String getPath() {
114                return path;
115        }
116
117        public String getName() {
118                return new File(path).getName();
119        }
120
121        public void setPath(String path) {
122                this.path = path;
123        }
124
125        public FileChecksum getChecksum() {
126                return checksum;
127        }
128
129        public void setChecksum(FileChecksum checksum) {
130                this.checksum = checksum;
131        }
132
133        public Long getSize() { // TODO [low] Redundant field 'size', this field should not exist. Instead the content's size should be used. This was introduced as a convenience field.
134                return size;
135        }
136
137        public void setSize(Long size) {
138                this.size = size;
139        }
140
141        public String getLinkTarget() {
142                return linkTarget;
143        }
144
145        public void setLinkTarget(String linkTarget) {
146                this.linkTarget = linkTarget;
147        }
148
149        public String getPosixPermissions() {
150                return posixPermissions;
151        }
152
153        public void setPosixPermissions(String posixPermissions) {
154                this.posixPermissions = posixPermissions;
155        }
156
157        public String getDosAttributes() {
158                return dosAttributes;
159        }
160
161        public void setDosAttributes(String dosAttributes) {
162                this.dosAttributes = dosAttributes;
163        }
164
165        @Override
166        public String toString() {
167                return "FileVersion [version=" + version + ", path=" + path + ", type=" + type + ", status=" + status + ", size=" + size + ", lastModified="
168                                + lastModified + ", linkTarget=" + linkTarget + ", checksum=" + checksum + ", updated="
169                                + updated + ", posixPermissions=" + posixPermissions + ", dosAttributes=" + dosAttributes + "]";
170        }
171
172        @Override
173        public FileVersion clone() {
174                try {
175                        FileVersion clone = (FileVersion) super.clone();
176
177                        clone.setChecksum(getChecksum());
178                        clone.setLastModified(getLastModified());
179                        clone.setUpdated(getUpdated());
180                        clone.setPath(getPath());
181                        clone.setType(getType());
182                        clone.setVersion(getVersion());
183                        clone.setSize(getSize());
184                        clone.setDosAttributes(getDosAttributes());
185                        clone.setPosixPermissions(getPosixPermissions());
186                        clone.setLinkTarget(getLinkTarget());
187                        clone.setStatus(getStatus());
188
189                        return clone;
190                }
191                catch (Exception ex) {
192                        throw new RuntimeException(ex);
193                }
194        }
195
196        @Override
197        public int hashCode() {
198                final int prime = 31;
199                int result = 1;
200                result = prime * result + ((checksum == null) ? 0 : checksum.hashCode());
201                result = prime * result + ((dosAttributes == null) ? 0 : dosAttributes.hashCode());
202                result = prime * result + ((lastModified == null) ? 0 : lastModified.hashCode());
203                result = prime * result + ((linkTarget == null) ? 0 : linkTarget.hashCode());
204                result = prime * result + ((path == null) ? 0 : path.hashCode());
205                result = prime * result + ((posixPermissions == null) ? 0 : posixPermissions.hashCode());
206                result = prime * result + ((size == null) ? 0 : size.hashCode());
207                result = prime * result + ((status == null) ? 0 : status.hashCode());
208                result = prime * result + ((type == null) ? 0 : type.hashCode());
209                result = prime * result + ((updated == null) ? 0 : updated.hashCode());
210                result = prime * result + ((version == null) ? 0 : version.hashCode());
211                return result;
212        }
213
214        @Override
215        public boolean equals(Object obj) {
216                if (this == obj) {
217                        return true;
218                }
219                if (obj == null) {
220                        return false;
221                }
222                if (!(obj instanceof FileVersion)) {
223                        return false;
224                }
225                FileVersion other = (FileVersion) obj;
226                if (checksum == null) {
227                        if (other.checksum != null) {
228                                return false;
229                        }
230                }
231                else if (!checksum.equals(other.checksum)) {
232                        return false;
233                }
234                if (dosAttributes == null) {
235                        if (other.dosAttributes != null) {
236                                return false;
237                        }
238                }
239                else if (!dosAttributes.equals(other.dosAttributes)) {
240                        return false;
241                }
242                if (lastModified == null) {
243                        if (other.lastModified != null) {
244                                return false;
245                        }
246                }
247                else if (!lastModified.equals(other.lastModified)) {
248                        return false;
249                }
250                if (linkTarget == null) {
251                        if (other.linkTarget != null) {
252                                return false;
253                        }
254                }
255                else if (!linkTarget.equals(other.linkTarget)) {
256                        return false;
257                }
258                if (path == null) {
259                        if (other.path != null) {
260                                return false;
261                        }
262                }
263                else if (!path.equals(other.path)) {
264                        return false;
265                }
266                if (posixPermissions == null) {
267                        if (other.posixPermissions != null) {
268                                return false;
269                        }
270                }
271                else if (!posixPermissions.equals(other.posixPermissions)) {
272                        return false;
273                }
274                if (size == null) {
275                        if (other.size != null) {
276                                return false;
277                        }
278                }
279                else if (!size.equals(other.size)) {
280                        return false;
281                }
282                if (status != other.status) {
283                        return false;
284                }
285                if (type != other.type) {
286                        return false;
287                }
288                if (updated == null) {
289                        if (other.updated != null) {
290                                return false;
291                        }
292                }
293                else if (!updated.equals(other.updated)) {
294                        return false;
295                }
296                if (version == null) {
297                        if (other.version != null) {
298                                return false;
299                        }
300                }
301                else if (!version.equals(other.version)) {
302                        return false;
303                }
304                return true;
305        }
306
307        public enum FileStatus {
308                NEW("NEW"),
309                CHANGED("CHANGED"),
310                RENAMED("RENAMED"),
311                DELETED("DELETED");
312
313                private String name;
314
315                private FileStatus(String name) {
316                        this.name = name;
317                }
318
319                public boolean equalsName(String otherName) {
320                        return (otherName == null) ? false : name.equals(otherName);
321                }
322
323                @Override
324                public String toString() {
325                        return name;
326                }
327        }
328
329        /**
330         * A {@link FileVersion} can be of either one of the types in this enum.
331         * Types are treated differently during the index and synchronization process.
332         */
333        public enum FileType {
334                FILE("FILE"),
335                FOLDER("FOLDER"),
336                SYMLINK("SYMLINK");
337
338                private String name;
339
340                private FileType(String name) {
341                        this.name = name;
342                }
343
344                public boolean equalsName(String otherName) {
345                        return (otherName == null) ? false : name.equals(otherName);
346                }
347
348                @Override
349                public String toString() {
350                        return name;
351                }
352        }
353}