1 package com.trendmicro.grid.acl.ds.jpa;
2
3 import com.trendmicro.grid.acl.ds.jpa.entities.JpaFileDetails;
4 import com.trendmicro.grid.acl.ds.jpa.entities.JpaFileHistory;
5 import com.trendmicro.grid.acl.ds.jpa.entities.JpaFileInformation;
6 import com.trendmicro.grid.acl.ds.jpa.util.FileDetailsMap;
7 import com.trendmicro.grid.acl.l0.datatypes.FileDetails;
8 import com.trendmicro.grid.acl.l0.datatypes.FileIdentifier;
9 import com.trendmicro.grid.acl.l0.datatypes.FileInformation;
10 import com.trendmicro.grid.acl.l0.datatypes.PackageMember;
11 import net.sf.tinyjee.config.PropertySection;
12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory;
14
15 import javax.persistence.Query;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.List;
19
20 import static com.trendmicro.grid.acl.ds.config.DataSourcePropertySection.KEY_UPDATE_TIMESTAMPS_WHEN_CONTENT_IS_SAME;
21 import static com.trendmicro.grid.acl.ds.config.DataSourcePropertySection.getPropertySection;
22
23
24
25
26
27
28
29 public abstract class AbstractReceivedFileContentsHandler<T> extends AbstractReceivedResultsHandler<T> {
30
31 private static final Logger log = LoggerFactory.getLogger(AbstractReceivedFileContentsHandler.class);
32
33 private final JpaFileRepository fileRepository;
34
35 private final boolean presetAlwaysUpdateTimestamps;
36
37
38
39
40
41
42 protected AbstractReceivedFileContentsHandler(JpaFileRepository fileRepository) {
43 PropertySection section = getPropertySection();
44
45 this.fileRepository = fileRepository;
46 presetAlwaysUpdateTimestamps = getValue(section, KEY_UPDATE_TIMESTAMPS_WHEN_CONTENT_IS_SAME);
47 }
48
49
50
51
52
53
54
55
56 protected Collection<JpaFileDetails> createOrUpdateFileReferences(final StorageContext context,
57 final Collection<PackageMember> members) {
58
59 final List<Object[]> timeUpdates = new ArrayList<Object[]>(members.size());
60 final FileDetailsMap<JpaFileDetails> existingDetailsMap = new FileDetailsMap<JpaFileDetails>(members.size());
61 final Collection<JpaFileDetails> fileRefs = new ArrayList<JpaFileDetails>(members.size());
62
63
64 final List<FileIdentifier> ids = new ArrayList<FileIdentifier>(members.size());
65 for (PackageMember member : members)
66 ids.add(member.getIdentifier());
67 for (JpaFileDetails fileDetails : fileRepository.getJpaFileDetailsList(ids))
68 if (fileDetails != null)
69 existingDetailsMap.put(fileDetails.getIdentifier(), fileDetails);
70
71 for (PackageMember member : members) {
72 FileDetails details = member.getDetails();
73 if (details == null)
74 details = new FileDetails(member.getIdentifier(), member.getInformation(), null);
75
76 fileRefs.add(doCreateOrUpdateFileReference(context, details, existingDetailsMap, timeUpdates, false));
77 }
78
79
80 handleTimeUpdates(context, timeUpdates);
81
82 return fileRefs;
83 }
84
85
86
87
88
89
90
91
92
93
94 protected JpaFileDetails createOrUpdateFileReference(final StorageContext context, final FileDetails details, boolean forceTimeUpdates) {
95 final List<Object[]> timeUpdates = new ArrayList<Object[]>(1);
96 final FileDetailsMap<JpaFileDetails> existingDetailsMap = new FileDetailsMap<JpaFileDetails>(1);
97 existingDetailsMap.put(details.getIdentifier(), fileRepository.getFileDetails(details.getIdentifier()));
98
99 JpaFileDetails fileDetails = doCreateOrUpdateFileReference(context, details, existingDetailsMap, timeUpdates, forceTimeUpdates);
100
101
102 handleTimeUpdates(context, timeUpdates);
103
104 return fileDetails;
105 }
106
107
108 private JpaFileDetails doCreateOrUpdateFileReference(final StorageContext context,
109 final FileDetails details,
110 final FileDetailsMap<JpaFileDetails> existingDetailsMap,
111 List<Object[]> timeUpdates, boolean forceTimeUpdates) {
112
113 boolean needsTimeUpdate = false;
114 JpaFileDetails existingDetails = existingDetailsMap.get(details.getIdentifier());
115
116 if (existingDetails == null) {
117 if (log.isTraceEnabled())
118 log.trace("Creating new file-content entry: {}", details);
119 existingDetails = fileRepository.createFileDetails(details);
120 existingDetailsMap.put(details.getIdentifier(), existingDetails);
121
122 } else if (!context.ignoreAllUpdates) {
123
124 boolean ignoreMetadata = context.ignoreNullMetadataUpdates && isNull(details.getMetadata());
125 if (JpaFileHistory.wasChanged(existingDetails, details, ignoreMetadata)) {
126 if (log.isTraceEnabled())
127 log.trace("Updating file-content to: {}", details);
128
129
130 if (context.enableHistoryRecording) existingDetails.alignRevisionWithSession(context.em);
131
132
133 if (existingDetails.getInformation().isUnknown()) {
134 log.info("TMACL-01850:Received processing result on file {} (tagged with {}) that was " +
135 "previously collected through reports and marked as 'unknown'.", details.getIdentifier(),
136 details.getInformation().getTags());
137 existingDetails.getInformation().setUnknown(false);
138 }
139
140
141 JpaFileHistory history = new JpaFileHistory(existingDetails);
142
143
144 if (context.enableHistoryRecording) {
145 if (log.isTraceEnabled())
146 log.trace("Storing new file-content history entry: {}", history);
147 context.em.persist(history);
148 } else {
149 if (log.isTraceEnabled())
150 log.trace("enableHistoryRecording is set to {}. Disregarding file-content history entry: {}", context.enableHistoryRecording, history);
151 }
152
153 existingDetails.setMetadata(details.getMetadata());
154
155 final JpaFileInformation info = existingDetails.getInformation();
156 info.setTags(details.getInformation().getTags());
157 info.setLastRetrieved(details.getInformation().getLastRetrieved());
158 info.setLastProcessed(details.getInformation().getLastProcessed());
159 } else
160 needsTimeUpdate = true;
161 }
162
163 if (needsTimeUpdate) {
164 final JpaFileInformation existingInfo = existingDetails.getInformation();
165 final FileInformation info = details.getInformation();
166 final boolean alwaysUpdateTimestamps = !context.ignoreAllUpdates && (presetAlwaysUpdateTimestamps || forceTimeUpdates);
167
168 needsTimeUpdate = alwaysUpdateTimestamps ? (
169 isAfter(existingInfo.getLastProcessed(), info.getLastProcessed()) ||
170 isAfter(existingInfo.getLastRetrieved(), info.getLastRetrieved())
171 ) : existingInfo.getLastProcessed() == null || existingInfo.getLastRetrieved() == null;
172
173 if (needsTimeUpdate) {
174 timeUpdates.add(new Object[]{
175 details.getInformation().getLastRetrieved(),
176 details.getInformation().getLastProcessed(),
177 existingDetails.getPrimaryKey()});
178 }
179 }
180
181 return existingDetails;
182 }
183
184
185 private void handleTimeUpdates(final StorageContext context, List<Object[]> timeUpdates) {
186 if (timeUpdates == null || timeUpdates.isEmpty() || context.ignoreAllUpdates)
187 return;
188
189 final Query updateQuery = context.em.createNamedQuery("FileContents.UpdateModificationDates");
190 for (Object[] timeUpdate : timeUpdates) {
191 updateQuery.setParameter("lastRetrieved", timeUpdate[0]).
192 setParameter("lastProcessed", timeUpdate[1]).
193 setParameter("fileId", timeUpdate[2]).executeUpdate();
194 }
195 }
196 }