1   package com.trendmicro.grid.acl.ds.jpa.entities;
2   
3   import com.trendmicro.grid.acl.Limits;
4   import com.trendmicro.grid.acl.l0.datatypes.FileDetails;
5   import com.trendmicro.grid.acl.metadata.Metadata;
6   import org.hibernate.annotations.Type;
7   
8   import javax.persistence.*;
9   import java.io.Serializable;
10  import java.util.Arrays;
11  import java.util.Date;
12  
13  import static com.trendmicro.grid.acl.ds.jpa.util.JpaUtils.metadataDiffers;
14  import static com.trendmicro.grid.acl.ds.jpa.util.JpaUtils.tagsDiffer;
15  import static net.sf.tinyjee.util.Assert.assertNotNull;
16  
17  /**
18   * Implements a read and writeable history entry for the FILE_CONTENT_HISTORY table.
19   *
20   * @author juergen_kellerer, 2010-06-07
21   * @version 1.0
22   */
23  @NamedQueries({
24  		@NamedQuery(name = "FileContentHistory.SelectMaxRevisionForPackage",
25  				query = "SELECT MAX(h.historyId.revision) " +
26  						"FROM FILE_CONTENT_HISTORY h WHERE historyId.parent = :parent"),
27  		@NamedQuery(name = "FileContentHistory.SelectFileHistoryDetailsByFileContent",
28  						query = "SELECT h " +
29  								"FROM FILE_CONTENT_HISTORY h WHERE historyId.parent = :parent")
30  })
31  @Entity(name = "FILE_CONTENT_HISTORY")
32  public class JpaFileHistory implements Serializable {
33  
34  	private static final long serialVersionUID = -4911356794856270325L;
35  
36  	/**
37  	 * Returns true if history relevant values differ.
38  	 *
39  	 * @param existingDetails the existing details.
40  	 * @param details		 the updated details.
41  	 * @param ignoreMetadata  whether metadata is compared or not.
42  	 * @return true if history relevant values differ.
43  	 */
44  	public static boolean wasChanged(JpaFileDetails existingDetails, FileDetails details, boolean ignoreMetadata) {
45  		return (!ignoreMetadata && metadataDiffers(existingDetails, details)) ||
46  				tagsDiffer(existingDetails.getInformation(), details.getInformation()) ||
47  				existingDetails.getInformation().isUnknown();
48  	}
49  
50  	@EmbeddedId
51  	private ID historyId;
52  
53  	@Temporal(TemporalType.TIMESTAMP)
54  	@Column(name = "CREATED", nullable = false)
55  	private Date created = new Date();
56  
57  	@Column(name = "UNKNOWN", nullable = false)
58  	private boolean unknown;
59  
60  	@Type(type = "taglist")
61  	@Column(name = "TAGS", length = Limits.MAX_TAG_STRING_LENGTH, nullable = true)
62  	String[] tags;
63  
64  	@Type(type = "metadata")
65  	@Basic(fetch = FetchType.LAZY)
66  	@Column(name = "META_DATA", length = Limits.MAX_SERIALIZED_METADATA_LENGTH)
67  	Metadata metadata;
68  
69  	public JpaFileHistory() {
70  	}
71  
72  	/**
73  	 * Creates a new history entry for the given file content entry.
74  	 *
75  	 * @param fileDetails the instance of fileDetails to create the history from.
76  	 */
77  	public JpaFileHistory(JpaFileDetails fileDetails) {
78  		this.historyId = new ID(fileDetails);
79  
80  		final JpaFileInformation info = fileDetails.getInformation();
81  		unknown = info.isUnknown();
82  		tags = info.getTagsAsArray();
83  		metadata = fileDetails.getMetadata();
84  
85  		// Clone all mutable types to avoid side effects.
86  		if (tags != null)
87  			tags = tags.clone();
88  		if (metadata != null)
89  			metadata = metadata.clone();
90  	}
91  
92  	public ID getHistoryId() {
93  		return historyId;
94  	}
95  
96  	public Date getCreated() {
97  		return created;
98  	}
99  
100 	public boolean isUnknown() {
101 		return unknown;
102 	}
103 
104 	public String[] getTags() {
105 		return tags;
106 	}
107 
108 	public Metadata getMetadata() {
109 		return metadata;
110 	}
111 
112 	@Override
113 	public boolean equals(Object o) {
114 		if (this == o) return true;
115 		if (!(o instanceof JpaFileHistory)) return false;
116 
117 		JpaFileHistory that = (JpaFileHistory) o;
118 		return !(historyId != null ? !historyId.equals(that.historyId) : that.historyId != null);
119 	}
120 
121 	@Override
122 	public int hashCode() {
123 		return historyId != null ? historyId.hashCode() : 0;
124 	}
125 
126 	/**
127 	 * Implements the primary key of the table "FILE_CONTENT_HISTORY".
128 	 */
129 	@Embeddable
130 	public static class ID implements Serializable {
131 
132 		private static final long serialVersionUID = -8535664911794270325L;
133 
134 		@ManyToOne(optional = false)
135 		@JoinColumn(name = "FILE_CONTENT_ID", nullable = false, updatable = false)
136 		private JpaFileDetails parent;
137 
138 		@Column(name = "REVISION", nullable = false, updatable = false)
139 		private int revision;
140 
141 		public ID() {
142 		}
143 
144 		public ID(JpaFileDetails parent) {
145 			assertNotNull("JpaFileDetails", parent);
146 			this.parent = parent;
147 			this.revision = parent.getRevision();
148 
149 			// increment the revision after creating the history instance.
150 			parent.setRevision(revision + 1);
151 		}
152 
153 		public JpaFileDetails getParent() {
154 			return parent;
155 		}
156 
157 		public int getRevision() {
158 			return revision;
159 		}
160 
161 		@Override
162 		public boolean equals(Object o) {
163 			if (this == o) return true;
164 			if (!(o instanceof ID)) return false;
165 			ID id = (ID) o;
166 			return revision == id.revision && parent.equals(id.parent);
167 		}
168 
169 		@Override
170 		public int hashCode() {
171 			int result = parent.hashCode();
172 			result = 31 * result + revision;
173 			return result;
174 		}
175 
176 		@Override
177 		public String toString() {
178 			return "ID{" +
179 					"fileDetails=" + parent +
180 					", revision=" + revision +
181 					'}';
182 		}
183 	}
184 
185 	@Override
186 	public String toString() {
187 		return "JpaFileHistory{" +
188 				"historyId=" + historyId +
189 				", created=" + created +
190 				", unknown=" + unknown +
191 				", tags=" + (tags == null ? null : Arrays.asList(tags)) +
192 				", metadata=" + metadata +
193 				'}';
194 	}
195 }