001package co.codewizards.cloudstore.local.persistence;
002
003import static co.codewizards.cloudstore.core.util.Util.*;
004
005import java.util.Date;
006
007import javax.jdo.JDOHelper;
008import javax.jdo.annotations.IdGeneratorStrategy;
009import javax.jdo.annotations.IdentityType;
010import javax.jdo.annotations.Inheritance;
011import javax.jdo.annotations.InheritanceStrategy;
012import javax.jdo.annotations.NullValue;
013import javax.jdo.annotations.PersistenceCapable;
014import javax.jdo.annotations.Persistent;
015import javax.jdo.annotations.PrimaryKey;
016
017/**
018 * Base class of all persistence-capable (a.k.a. entity) classes.
019 * @author Marco หงุ่ยตระกูล-Schulze - marco at codewizards dot co
020 */
021@PersistenceCapable(identityType=IdentityType.APPLICATION)
022@Inheritance(strategy=InheritanceStrategy.SUBCLASS_TABLE)
023public abstract class Entity implements AutoTrackChanged
024{
025        @PrimaryKey
026        @Persistent(valueStrategy=IdGeneratorStrategy.NATIVE)
027        private long id = -1;
028
029        // We always initialise this, though the value might be overwritten when DataNucleus loads
030        // the object's data from the DB. There's no need to defer the Date instantiation.
031        // Creating 1 million instances of Date costs less than 68 ms (I tested creating them and
032        // putting them into a LinkedList (preventing optimizer short-cuts), so the LinkedList
033        // overhead is included in this time).
034        @Persistent(nullValue=NullValue.EXCEPTION)
035        private Date created = new Date();
036
037        @Persistent(nullValue=NullValue.EXCEPTION)
038        private Date changed = new Date();
039
040        /**
041         * Get the unique identifier of this object.
042         * <p>
043         * This identifier is unique per entity type (the first sub-class of this class
044         * having an own table - which is usually the direct sub-class of {@link Entity}).
045         * <p>
046         * This identifier is assigned when the object is persisted into the DB.
047         * @return the unique identifier of this object.
048         */
049        public long getId() {
050                return id;
051        }
052
053        @Override
054        public boolean equals(Object obj) {
055                if (this == obj) {
056                        return true;
057                }
058                if (obj == null) {
059                        return false;
060                }
061
062                Object thisOid = JDOHelper.getObjectId(this);
063                if (thisOid == null) {
064                        return false;
065                }
066
067                Object otherOid = JDOHelper.getObjectId(obj);
068                return thisOid.equals(otherOid);
069        }
070
071        @Override
072        public int hashCode() {
073                Object thisOid = JDOHelper.getObjectId(this);
074                if (thisOid == null) {
075                        return super.hashCode();
076                }
077                return thisOid.hashCode();
078        }
079
080        @Override
081        public String toString() {
082                return String.format("%s[%s]", getClass().getSimpleName(), JDOHelper.getObjectId(this));
083        }
084
085        /**
086         * Gets the timestamp of the creation of this entity.
087         * @return the timestamp of the creation of this entity. Never <code>null</code>.
088         */
089        public Date getCreated() {
090                return created;
091        }
092        /**
093         * Sets the timestamp of the creation of this entity.
094         * <p>
095         * <b>Important: You should normally never invoke this method!</b> The {@code created} property
096         * is supposed to be read-only (assigned once during object creation and never again).
097         * This setter merely exists for extraordinary, unforeseen use cases as well as tests.
098         * @param created the timestamp of the creation of this entity. Must not be <code>null</code>.
099         */
100        protected void setCreated(Date created) {
101                assertNotNull("created", created);
102                this.created = created;
103        }
104
105        @Override
106        public Date getChanged() {
107                return changed;
108        }
109        @Override
110        public void setChanged(Date changed) {
111                assertNotNull("created", created);
112                this.changed = changed;
113        }
114
115}