1   package com.trendmicro.grid.acl.ds.jpa;
2   
3   import com.trendmicro.grid.acl.ds.ReportReceiver;
4   import com.trendmicro.grid.acl.ds.jpa.entities.JpaFileDetails;
5   import com.trendmicro.grid.acl.ds.jpa.entities.JpaFileReport;
6   import com.trendmicro.grid.acl.ds.jpa.util.FileQueryConfigurator;
7   import com.trendmicro.grid.acl.l0.datatypes.FileReport;
8   import net.sf.tinyjee.config.PropertySection;
9   import net.sf.tinyjee.util.Hex;
10  import org.slf4j.Logger;
11  import org.slf4j.LoggerFactory;
12  import org.springframework.stereotype.Repository;
13  import org.springframework.transaction.annotation.Transactional;
14  
15  import javax.annotation.PostConstruct;
16  import javax.annotation.Resource;
17  import javax.persistence.EntityManager;
18  import javax.persistence.PersistenceContext;
19  import javax.persistence.Query;
20  import java.util.ArrayList;
21  import java.util.Collection;
22  import java.util.Iterator;
23  
24  import static com.trendmicro.grid.acl.ds.config.DataSourcePropertySection.KEY_IGNORE_STATISTICS_RECORDING;
25  import static com.trendmicro.grid.acl.ds.config.DataSourcePropertySection.getPropertySection;
26  import static com.trendmicro.grid.acl.ds.jpa.AbstractReceivedResultsHandler.getValue;
27  
28  /**
29   * Implements ReportReceiver using JPA.
30   *
31   * @author juergen_kellerer, 2010-06-08
32   * @version 1.0
33   */
34  @Repository
35  @Transactional(readOnly = false)
36  public class JpaReportReceiver implements ReportReceiver {
37  
38  	private static final Logger log = LoggerFactory.getLogger(JpaReportReceiver.class);
39  
40  	@PersistenceContext(unitName = "CoreDB")
41  	EntityManager em;
42  
43  	@Resource
44  	JpaFileRepository fileRepository;
45  
46  	boolean ignoreStatisticsRecording;
47  
48  	@PostConstruct
49  	void configure() {
50  		PropertySection section = getPropertySection();
51  		ignoreStatisticsRecording = getValue(section, KEY_IGNORE_STATISTICS_RECORDING);
52  	}
53  
54  	@Override
55  	public void receiveFileReports(Collection<FileReport> fileReports) {
56  		final boolean debug = log.isDebugEnabled();
57  		final FileQueryConfigurator<Integer> queryConfigurator = fileRepository.getReferenceQueryConfigurator();
58  		final Query updateQuery = em.createNamedQuery("FileReport.UpdateAccessCount");
59  
60  		// Fetch all required references first to allow hibernate to
61  		// do better batch updates in the next section.
62  		final Collection<JpaFileDetails> contentReferences = new ArrayList<JpaFileDetails>(fileReports.size());
63  		for (FileReport report : fileReports)
64  			contentReferences.add(fileRepository.getReference(queryConfigurator, report));
65  
66  		final Iterator<JpaFileDetails> referenceIterator = contentReferences.iterator();
67  		for (FileReport report : fileReports) {
68  			boolean entrySkipped = false;
69  			final byte[] sha1 = report.getSHA1Hash();
70  			final JpaFileDetails fileDetails = referenceIterator.next();
71  
72  			if (fileDetails != null) {
73  				final JpaFileReport jpaReport = new JpaFileReport(fileDetails, report);
74  				int updateCount = updateQuery.setParameter("accessCount", jpaReport.getAccessCount()).
75  						setParameter("reportId", jpaReport.getReportId()).executeUpdate();
76  
77  				if (updateCount == 0) {
78  					if (debug)
79  						log.debug("Creating a new report entry '{}' for file '{}'", jpaReport.getTimePeriod(), Hex.encode(sha1));
80  
81  					if (!ignoreStatisticsRecording) {
82  						em.persist(jpaReport);
83  						em.flush();
84  						em.detach(jpaReport);
85  					}
86  
87  				} else {
88  					if (log.isTraceEnabled()) {
89  						log.trace("Incremented the access count of the existing report entry '{}' for file '{}', by {}", new Object[]{
90  								jpaReport.getTimePeriod(), Hex.encode(sha1), report.getAmount()});
91  					}
92  				}
93  			} else
94  				entrySkipped = true;
95  
96  			if (entrySkipped) {
97  				if (debug)
98  					log.debug("Omitting storage of report for unknown file '{}' as the MD5 hash is missing.", Hex.encode(sha1));
99  			}
100 		}
101 		if (!ignoreStatisticsRecording)
102 			em.flush();
103 	}
104 }