1   package com.trendmicro.grid.acl.ds.jpa.entities;
2   
3   import com.trendmicro.grid.acl.Limits;
4   import com.trendmicro.grid.acl.ds.datatypes.SharedFileMetadata;
5   import com.trendmicro.grid.acl.ds.datatypes.SharedPackageDetails;
6   import com.trendmicro.grid.acl.ds.jpa.util.NameValidator;
7   import com.trendmicro.grid.acl.l0.datatypes.FileMetadata;
8   import com.trendmicro.grid.acl.metadata.Metadata;
9   import org.hibernate.annotations.Type;
10  import org.hibernate.search.annotations.DocumentId;
11  import org.hibernate.search.annotations.Indexed;
12  import org.hibernate.search.annotations.IndexedEmbedded;
13  
14  import javax.persistence.*;
15  
16  import static com.trendmicro.grid.acl.ds.jpa.QueryHints.*;
17  import static com.trendmicro.grid.acl.ds.jpa.QueryHints.CACHE_STORE_MODE;
18  import static com.trendmicro.grid.acl.ds.jpa.QueryHints.V_USE;
19  
20  /**
21   * Binds PackageDetails to the table "PACKAGES".
22   *
23   * @author juergen_kellerer, 2010-06-10
24   * @version 1.0
25   */
26  @NamedQueries({
27  		// getPackageNamesInFamily
28  		@NamedQuery(name = "Packages.GetPackageNamesInFamily", query = "" +
29  				"SELECT p.packageInformation.name FROM PACKAGES p " +
30  				"WHERE p.packageInformation.name LIKE concat(:familyName, '%')",
31  				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
32  						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
33  
34  		// getPackageFileIdentifiersByName
35  		@NamedQuery(name = "Packages.GetPackageFileIdentifierByName", query = "" +
36  				"SELECT p.packageFileDetails.identifier FROM PACKAGES p " +
37  				"WHERE p.packageInformation.name = :name",
38  				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
39  						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
40  
41  		// getFilesContainedInPackage
42  		@NamedQuery(name = "Packages.SelectFilesContainedInPackageBySHA1", query = "" +
43  				"SELECT pf.id.fileName, pf.id.fileDetails.identifier FROM PACKAGE_FILES pf " +
44  				"WHERE 	pf.id.packageDetails.packageFileDetails.identifier.sha1 = :sha1",
45  				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
46  						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
47  		@NamedQuery(name = "Packages.SelectFilesContainedInPackageByMD5", query = "" +
48  				"SELECT pf.id.fileName, pf.id.fileDetails.identifier FROM PACKAGE_FILES pf " +
49  				"WHERE 	pf.id.packageDetails.packageFileDetails.identifier.md5 = :md5",
50  				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
51  						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
52  		@NamedQuery(name = "Packages.SelectFilesContainedInPackageBySHA1AndMD5", query = "" +
53  				"SELECT pf.id.fileName, pf.id.fileDetails.identifier FROM PACKAGE_FILES pf " +
54  				"WHERE 	pf.id.packageDetails.packageFileDetails.identifier.sha1 = :sha1 AND " +
55  				"		pf.id.packageDetails.packageFileDetails.identifier.md5 = :md5",
56  				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
57  						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
58  		@NamedQuery(name = "Packages.SelectFilesContainedInPackageByName", query = "" +
59  				"SELECT pf.id.fileName, pf.id.fileDetails.identifier FROM PACKAGE_FILES pf " +
60  				"WHERE 	pf.id.packageDetails.packageInformation.name = :name",
61  				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
62  						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
63  
64  		@NamedQuery(name = "Packages.SelectFilesContainedInPackageByPrimaryKey", query = "" +
65  				"SELECT pf, pf.id.fileDetails.identifier FROM PACKAGE_FILES pf " +
66  				"WHERE 	pf.id.packageDetails = :packageDetails"),
67  
68  		// getReferencingPackageNames
69  		@NamedQuery(name = "Packages.SelectReferencingPackageNamesBySHA1", query = "" +
70  				"SELECT pf.id.packageDetails.packageInformation.name FROM PACKAGE_FILES pf " +
71  				"WHERE 	pf.id.fileDetails.identifier.sha1 = :sha1",
72  				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
73  						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
74  		@NamedQuery(name = "Packages.SelectReferencingPackageNamesByMD5", query = "" +
75  				"SELECT pf.id.packageDetails.packageInformation.name FROM PACKAGE_FILES pf " +
76  				"WHERE 	pf.id.fileDetails.identifier.md5 = :md5",
77  				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
78  						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
79  		@NamedQuery(name = "Packages.SelectReferencingPackageNamesBySHA1AndMD5", query = "" +
80  				"SELECT pf.id.packageDetails.packageInformation.name FROM PACKAGE_FILES pf " +
81  				"WHERE 	pf.id.fileDetails.identifier.sha1 = :sha1 AND " +
82  				"		pf.id.fileDetails.identifier.md5 = :md5",
83  				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
84  						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
85  		@NamedQuery(name = "Packages.SelectReferencingPackageNamesByName", query = "" +
86  				"SELECT pf.id.packageDetails.packageInformation.name FROM PACKAGE_FILES pf, PACKAGES p " +
87  				"WHERE 	p.packageFileDetails = pf.id.fileDetails AND " +
88  				"		p.packageInformation.name = :name",
89  				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
90  						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
91  
92  		// getPackagesContaindInPackage
93  		@NamedQuery(name = "Packages.SelectPackagesContainedInPackageBySHA1", query = "" +
94  				"SELECT p.packageInformation.name FROM PACKAGE_FILES pf, PACKAGES p " +
95  				"WHERE 	p.packageFileDetails = pf.id.fileDetails AND " +
96  				"		pf.id.packageDetails.packageFileDetails.identifier.sha1 = :sha1",
97  				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
98  						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
99  		@NamedQuery(name = "Packages.SelectPackagesContainedInPackageByMD5", query = "" +
100 				"SELECT p.packageInformation.name FROM PACKAGE_FILES pf, PACKAGES p " +
101 				"WHERE 	p.packageFileDetails = pf.id.fileDetails AND " +
102 				"		pf.id.packageDetails.packageFileDetails.identifier.md5 = :md5",
103 				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
104 						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
105 		@NamedQuery(name = "Packages.SelectPackagesContainedInPackageBySHA1AndMD5", query = "" +
106 				"SELECT p.packageInformation.name FROM PACKAGE_FILES pf, PACKAGES p " +
107 				"WHERE 	p.packageFileDetails = pf.id.fileDetails AND " +
108 				"		pf.id.packageDetails.packageFileDetails.identifier.sha1 = :sha1 AND " +
109 				"		pf.id.packageDetails.packageFileDetails.identifier.md5 = :md5",
110 				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
111 						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
112 		@NamedQuery(name = "Packages.SelectPackagesContainedInPackageByName", query = "" +
113 				"SELECT p.packageInformation.name FROM PACKAGE_FILES pf, PACKAGES p " +
114 				"WHERE 	p.packageFileDetails = pf.id.fileDetails AND " +
115 				"		pf.id.packageDetails.packageInformation.name = :name",
116 				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
117 						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
118 
119 		// getPackageInformationList
120 		@NamedQuery(name = "Packages.SelectPackageInformationBySHA1", query = "" +
121 				"SELECT p.packageInformation, p.packageFileDetails.information FROM PACKAGES p " +
122 				"WHERE p.packageFileDetails.identifier.sha1 = :sha1",
123 				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
124 						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
125 		@NamedQuery(name = "Packages.SelectPackageInformationByMD5", query = "" +
126 				"SELECT p.packageInformation, p.packageFileDetails.information FROM PACKAGES p " +
127 				"WHERE p.packageFileDetails.identifier.md5 = :md5",
128 				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
129 						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
130 		@NamedQuery(name = "Packages.SelectPackageInformationBySHA1AndMD5", query = "" +
131 				"SELECT p.packageInformation, p.packageFileDetails.information FROM PACKAGES p " +
132 				"WHERE 	p.packageFileDetails.identifier.sha1 = :sha1 AND " +
133 				"		p.packageFileDetails.identifier.md5 = :md5",
134 				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
135 						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
136 		@NamedQuery(name = "Packages.SelectPackageInformationByName", query = "" +
137 				"SELECT p.packageInformation, p.packageFileDetails.information FROM PACKAGES p " +
138 				"WHERE p.packageInformation.name = :name",
139 				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
140 						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
141 
142 
143 		// getPackageDetailsList
144 		@NamedQuery(name = "Packages.SelectPackageDetailsPrimaryKeyBySHA1", query = "" +
145 				"SELECT p.id FROM PACKAGES p " +
146 				"WHERE p.packageFileDetails.identifier.sha1 = :sha1",
147 				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
148 						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
149 		@NamedQuery(name = "Packages.SelectPackageDetailsPrimaryKeyByMD5", query = "" +
150 				"SELECT p.id FROM PACKAGES p " +
151 				"WHERE p.packageFileDetails.identifier.md5 = :md5",
152 				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
153 						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
154 		@NamedQuery(name = "Packages.SelectPackageDetailsPrimaryKeyBySHA1AndMD5", query = "" +
155 				"SELECT p.id FROM PACKAGES p " +
156 				"WHERE 	p.packageFileDetails.identifier.sha1 = :sha1 AND " +
157 				"		p.packageFileDetails.identifier.md5 = :md5",
158 				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
159 						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)}),
160 
161 
162 		@NamedQuery(name = "Packages.SelectPackageDetailsPrimaryKeyByName", query = "" +
163 				"SELECT p.id FROM PACKAGES p " +
164 				"WHERE p.packageInformation.name = :name",
165 				hints = {@QueryHint(name = CACHEABLE, value = V_YES),
166 						@QueryHint(name = CACHE_RETRIEVE_MODE, value = V_USE), @QueryHint(name = CACHE_STORE_MODE, value = V_USE)})
167 })
168 @Indexed
169 @Cacheable
170 @Entity(name = "PACKAGES")
171 public class JpaPackageDetails extends SharedPackageDetails {
172 
173 	private static final long serialVersionUID = -5180279323995023946L;
174 
175 	private int primaryKey, revision = 1;
176 	private JpaFileDetails packageFileDetails;
177 
178 	public JpaPackageDetails() {
179 	}
180 
181 	public JpaPackageDetails(JpaPackageFamily packageFamily,
182 							 JpaPackageInformation packageInformation, Metadata metadata,
183 							 JpaFileDetails packageFileDetails) {
184 		super(packageFamily, packageInformation, metadata == null ? null : metadata.clone(), null);
185 
186 		NameValidator.getInstance().validatePackageName(
187 				packageFamily.getVendor().getName(), packageInformation.getName());
188 
189 		this.packageFileDetails = packageFileDetails;
190 		updateFileMetadata();
191 	}
192 
193 	@Id
194 	@DocumentId
195 	@GeneratedValue
196 	@Column(name = "PACKAGE_ID")
197 	public int getPrimaryKey() {
198 		return primaryKey;
199 	}
200 
201 	public void setPrimaryKey(int primaryKey) {
202 		this.primaryKey = primaryKey;
203 	}
204 
205 	@Column(name = "REVISION", nullable = false)
206 	public int getRevision() {
207 		return revision;
208 	}
209 
210 	public void setRevision(int revision) {
211 		this.revision = revision;
212 	}
213 
214 	/**
215 	 * Selects the current max revision that is stored in the history tables.
216 	 * <p/>
217 	 * NOTE: Data replication or bugs may cause revision numbers to get out of track.
218 	 * This implementation synchronizes the revision to ensure an insert doesn't fail
219 	 * on a unique key constraint.
220 	 *
221 	 * @param entityManager the entity manager to use for the operation.
222 	 */
223 	public void alignRevisionWithSession(EntityManager entityManager) {
224 		if (primaryKey != 0) {
225 			Integer maxRevision = entityManager.createNamedQuery(
226 					"PackageHistory.SelectMaxRevisionForPackage", Integer.class).
227 					setParameter("parent", this).getSingleResult();
228 			final Integer maxRevisionFiles = entityManager.createNamedQuery(
229 					"PackageFilesHistory.SelectMaxRevisionForPackage", Integer.class).
230 					setParameter("packageDetails", this).getSingleResult();
231 
232 			if (maxRevision == null)
233 				maxRevision = maxRevisionFiles;
234 
235 			if (maxRevision != null) {
236 				if (maxRevisionFiles != null && maxRevisionFiles > maxRevision)
237 					maxRevision = maxRevisionFiles;
238 				setRevision(maxRevision + 1);
239 			} else
240 				setRevision(1);
241 		}
242 	}
243 
244 	@Override
245 	@ManyToOne(optional = false, cascade = CascadeType.REMOVE)
246 	@JoinColumn(name = "PACKAGE_FAMILY_ID", nullable = false)
247 	public JpaPackageFamily getPackageFamily() {
248 		return (JpaPackageFamily) packageFamily;
249 	}
250 
251 	public void setPackageFamily(JpaPackageFamily packageFamily) {
252 		this.packageFamily = packageFamily;
253 	}
254 
255 	@Override
256 	@Embedded
257 	@IndexedEmbedded
258 	public JpaPackageInformation getPackageInformation() {
259 		return (JpaPackageInformation) packageInformation;
260 	}
261 
262 	public void setPackageInformation(JpaPackageInformation packageInformation) {
263 		this.packageInformation = packageInformation;
264 		fillPackageFileInformation();
265 	}
266 
267 	@IndexedEmbedded(depth = 2)
268 	@JoinColumn(name = "FILE_CONTENT_ID")
269 	@ManyToOne(optional = false, fetch = FetchType.EAGER)
270 	public JpaFileDetails getPackageFileDetails() {
271 		return packageFileDetails;
272 	}
273 
274 	public void setPackageFileDetails(JpaFileDetails packageFileDetails) {
275 		this.packageFileDetails = packageFileDetails;
276 
277 		// Set depending elements.
278 		updateFileMetadata();
279 		fillPackageFileInformation();
280 	}
281 
282 	private void updateFileMetadata() {
283 		if (packageFileDetails != null)
284 			fileMetadata = new FileMetadata(packageFileDetails.getIdentifier(), packageFileDetails.getMetadata());
285 		else
286 			fileMetadata = null;
287 	}
288 
289 	private void fillPackageFileInformation() {
290 		if (packageFileDetails != null) {
291 			final JpaPackageInformation info = (JpaPackageInformation) packageInformation;
292 			if (info != null)
293 				info.setPackageFileInformation(packageFileDetails.getInformation());
294 		}
295 	}
296 
297 	@Override
298 	@Type(type = "metadata")
299 	@Basic(fetch = FetchType.EAGER)
300 	@Column(name = "META_DATA", length = Limits.MAX_SERIALIZED_METADATA_LENGTH)
301 	public Metadata getMetadata() {
302 		return super.getMetadata();
303 	}
304 
305 	@Override
306 	public void setMetadata(Metadata metadata) { //NOSONAR - Override is required as hook for JPA.
307 		super.setMetadata(metadata == null ? null : metadata.clone());
308 	}
309 
310 	/**
311 	 * {@inheritDoc}
312 	 */
313 	@Override
314 	public String toString() {
315 		return "JpaPackageDetails{" +
316 				"primaryKey=" + primaryKey +
317 				", revision=" + revision +
318 				", packageInformation=" + packageInformation +
319 				", metadata=" + metadata +
320 				", packageFamily=" + packageFamily +
321 				'}';
322 	}
323 }