001
014
015 package com.liferay.portal.verify;
016
017 import com.liferay.portal.kernel.bean.PortalBeanLocatorUtil;
018 import com.liferay.portal.kernel.concurrent.ThrowableAwareRunnable;
019 import com.liferay.portal.kernel.dao.jdbc.AutoBatchPreparedStatementUtil;
020 import com.liferay.portal.kernel.dao.jdbc.DataAccess;
021 import com.liferay.portal.kernel.log.Log;
022 import com.liferay.portal.kernel.log.LogFactoryUtil;
023 import com.liferay.portal.kernel.security.auth.FullNameGenerator;
024 import com.liferay.portal.kernel.security.auth.FullNameGeneratorFactory;
025 import com.liferay.portal.kernel.util.LoggingTimer;
026 import com.liferay.portal.kernel.util.StringBundler;
027 import com.liferay.portal.kernel.util.StringPool;
028 import com.liferay.portal.kernel.verify.model.VerifiableAuditedModel;
029
030 import java.sql.Connection;
031 import java.sql.PreparedStatement;
032 import java.sql.ResultSet;
033 import java.sql.SQLException;
034 import java.sql.Timestamp;
035
036 import java.util.ArrayList;
037 import java.util.Collection;
038 import java.util.List;
039 import java.util.Map;
040
041
045 public class VerifyAuditedModel extends VerifyProcess {
046
047 public void verify(VerifiableAuditedModel... verifiableAuditedModels)
048 throws Exception {
049
050 List<String> unverifiedTableNames = new ArrayList<>();
051
052 for (VerifiableAuditedModel verifiableAuditedModel :
053 verifiableAuditedModels) {
054
055 unverifiedTableNames.add(verifiableAuditedModel.getTableName());
056 }
057
058 List<VerifyAuditedModelRunnable> verifyAuditedModelRunnables =
059 new ArrayList<>(unverifiedTableNames.size());
060
061 while (!unverifiedTableNames.isEmpty()) {
062 int count = unverifiedTableNames.size();
063
064 for (VerifiableAuditedModel verifiableAuditedModel :
065 verifiableAuditedModels) {
066
067 if (unverifiedTableNames.contains(
068 verifiableAuditedModel.getJoinByTableName()) ||
069 !unverifiedTableNames.contains(
070 verifiableAuditedModel.getTableName())) {
071
072 continue;
073 }
074
075 VerifyAuditedModelRunnable verifyAuditedModelRunnable =
076 new VerifyAuditedModelRunnable(verifiableAuditedModel);
077
078 verifyAuditedModelRunnables.add(verifyAuditedModelRunnable);
079
080 unverifiedTableNames.remove(
081 verifiableAuditedModel.getTableName());
082 }
083
084 if (unverifiedTableNames.size() == count) {
085 throw new VerifyException(
086 "Circular dependency detected " + unverifiedTableNames);
087 }
088 }
089
090 doVerify(verifyAuditedModelRunnables);
091 }
092
093 @Override
094 protected void doVerify() throws Exception {
095 Map<String, VerifiableAuditedModel> verifiableAuditedModelsMap =
096 PortalBeanLocatorUtil.locate(VerifiableAuditedModel.class);
097
098 Collection<VerifiableAuditedModel> verifiableAuditedModels =
099 verifiableAuditedModelsMap.values();
100
101 verify(
102 verifiableAuditedModels.toArray(
103 new VerifiableAuditedModel[verifiableAuditedModels.size()]));
104 }
105
106 protected Object[] getAuditedModelArray(
107 Connection con, String tableName, String pkColumnName, long primKey,
108 boolean allowAnonymousUser, long previousUserId)
109 throws Exception {
110
111 try (PreparedStatement ps = con.prepareStatement(
112 "select companyId, userId, createDate, modifiedDate from " +
113 tableName + " where " + pkColumnName + " = ?")) {
114
115 ps.setLong(1, primKey);
116
117 try (ResultSet rs = ps.executeQuery()) {
118 if (rs.next()) {
119 long companyId = rs.getLong("companyId");
120
121 long userId = 0;
122 String userName = null;
123
124 if (allowAnonymousUser) {
125 userId = previousUserId;
126 userName = "Anonymous";
127 }
128 else {
129 userId = rs.getLong("userId");
130 userName = getUserName(con, userId);
131 }
132
133 Timestamp createDate = rs.getTimestamp("createDate");
134 Timestamp modifiedDate = rs.getTimestamp("modifiedDate");
135
136 return new Object[] {
137 companyId, userId, userName, createDate, modifiedDate
138 };
139 }
140
141 if (_log.isDebugEnabled()) {
142 _log.debug("Unable to find " + tableName + " " + primKey);
143 }
144
145 return null;
146 }
147 }
148 }
149
150 protected Object[] getDefaultUserArray(Connection con, long companyId)
151 throws Exception {
152
153 try (PreparedStatement ps = con.prepareStatement(
154 "select userId, firstName, middleName, lastName from User_" +
155 " where companyId = ? and defaultUser = ?")) {
156
157 ps.setLong(1, companyId);
158 ps.setBoolean(2, true);
159
160 try (ResultSet rs = ps.executeQuery()) {
161 if (rs.next()) {
162 long userId = rs.getLong("userId");
163 String firstName = rs.getString("firstName");
164 String middleName = rs.getString("middleName");
165 String lastName = rs.getString("lastName");
166
167 FullNameGenerator fullNameGenerator =
168 FullNameGeneratorFactory.getInstance();
169
170 String userName = fullNameGenerator.getFullName(
171 firstName, middleName, lastName);
172
173 Timestamp createDate = new Timestamp(
174 System.currentTimeMillis());
175
176 return new Object[] {
177 companyId, userId, userName, createDate, createDate
178 };
179 }
180
181 return null;
182 }
183 }
184 }
185
186 protected String getUserName(Connection con, long userId) throws Exception {
187 try (PreparedStatement ps = con.prepareStatement(
188 "select firstName, middleName, lastName from User_ where " +
189 "userId = ?")) {
190
191 ps.setLong(1, userId);
192
193 try (ResultSet rs = ps.executeQuery()) {
194 if (rs.next()) {
195 String firstName = rs.getString("firstName");
196 String middleName = rs.getString("middleName");
197 String lastName = rs.getString("lastName");
198
199 FullNameGenerator fullNameGenerator =
200 FullNameGeneratorFactory.getInstance();
201
202 return fullNameGenerator.getFullName(
203 firstName, middleName, lastName);
204 }
205
206 return StringPool.BLANK;
207 }
208 }
209 }
210
211 protected void verifyAuditedModel(
212 Connection con, PreparedStatement ps, String tableName,
213 long primKey, Object[] auditedModelArray, boolean updateDates)
214 throws Exception {
215
216 try {
217 long companyId = (Long)auditedModelArray[0];
218
219 if (auditedModelArray[2] == null) {
220 auditedModelArray = getDefaultUserArray(con, companyId);
221
222 if (auditedModelArray == null) {
223 return;
224 }
225 }
226
227 long userId = (Long)auditedModelArray[1];
228 String userName = (String)auditedModelArray[2];
229 Timestamp createDate = (Timestamp)auditedModelArray[3];
230 Timestamp modifiedDate = (Timestamp)auditedModelArray[4];
231
232 ps.setLong(1, companyId);
233 ps.setLong(2, userId);
234 ps.setString(3, userName);
235
236 if (updateDates) {
237 ps.setTimestamp(4, createDate);
238 ps.setTimestamp(5, modifiedDate);
239 ps.setLong(6, primKey);
240 }
241 else {
242 ps.setLong(4, primKey);
243 }
244
245 ps.addBatch();
246 }
247 catch (Exception e) {
248 if (_log.isWarnEnabled()) {
249 _log.warn("Unable to verify model " + tableName, e);
250 }
251 }
252 }
253
254 protected void verifyAuditedModel(
255 VerifiableAuditedModel verifiableAuditedModel)
256 throws Exception {
257
258 try (LoggingTimer loggingTimer = new LoggingTimer(
259 verifiableAuditedModel.getTableName())) {
260
261 StringBundler sb = new StringBundler(8);
262
263 sb.append("select ");
264 sb.append(verifiableAuditedModel.getPrimaryKeyColumnName());
265 sb.append(", companyId, userId");
266
267 if (verifiableAuditedModel.getJoinByTableName() != null) {
268 sb.append(StringPool.COMMA_AND_SPACE);
269 sb.append(verifiableAuditedModel.getJoinByTableName());
270 }
271
272 sb.append(" from ");
273 sb.append(verifiableAuditedModel.getTableName());
274 sb.append(" where userName is null order by companyId");
275
276 Object[] auditedModelArray = null;
277
278 long previousCompanyId = 0;
279
280 try (Connection con = DataAccess.getUpgradeOptimizedConnection();
281 PreparedStatement ps1 = con.prepareStatement(sb.toString());
282 ResultSet rs = ps1.executeQuery();
283 PreparedStatement ps2 =
284 AutoBatchPreparedStatementUtil.autoBatch(
285 _createPreparedStatement(
286 con, verifiableAuditedModel.getTableName(),
287 verifiableAuditedModel.
288 getPrimaryKeyColumnName(),
289 verifiableAuditedModel.isUpdateDates()))) {
290
291 while (rs.next()) {
292 long companyId = rs.getLong("companyId");
293 long primKey = rs.getLong(
294 verifiableAuditedModel.getPrimaryKeyColumnName());
295 long previousUserId = rs.getLong("userId");
296
297 if (verifiableAuditedModel.getJoinByTableName()
298 != null) {
299
300 long relatedPrimKey = rs.getLong(
301 verifiableAuditedModel.getJoinByTableName());
302
303 auditedModelArray = getAuditedModelArray(
304 con, verifiableAuditedModel.getRelatedModelName(),
305 verifiableAuditedModel.getRelatedPKColumnName(),
306 relatedPrimKey,
307 verifiableAuditedModel.isAnonymousUserAllowed(),
308 previousUserId);
309 }
310 else if (previousCompanyId != companyId) {
311 auditedModelArray = getDefaultUserArray(con, companyId);
312
313 previousCompanyId = companyId;
314 }
315
316 if (auditedModelArray == null) {
317 continue;
318 }
319
320 verifyAuditedModel(
321 con, ps2, verifiableAuditedModel.getTableName(),
322 primKey, auditedModelArray,
323 verifiableAuditedModel.isUpdateDates());
324 }
325
326 ps2.executeBatch();
327 }
328 }
329 }
330
331 private PreparedStatement _createPreparedStatement(
332 Connection con, String tableName, String primaryKeyColumnName,
333 boolean updateDates)
334 throws SQLException {
335
336 StringBundler sb = new StringBundler(7);
337
338 sb.append("update ");
339 sb.append(tableName);
340 sb.append(" set companyId = ?, userId = ?, userName = ?");
341
342 if (updateDates) {
343 sb.append(", createDate = ?, modifiedDate = ?");
344 }
345
346 sb.append(" where ");
347 sb.append(primaryKeyColumnName);
348 sb.append(" = ?");
349
350 return con.prepareStatement(sb.toString());
351 }
352
353 private static final Log _log = LogFactoryUtil.getLog(
354 VerifyAuditedModel.class);
355
356 private class VerifyAuditedModelRunnable extends ThrowableAwareRunnable {
357
358 public VerifyAuditedModelRunnable(
359 VerifiableAuditedModel verifiableAuditedModel) {
360
361 _verifiableAuditedModel = verifiableAuditedModel;
362 }
363
364 @Override
365 protected void doRun() throws Exception {
366 verifyAuditedModel(_verifiableAuditedModel);
367 }
368
369 private final VerifiableAuditedModel _verifiableAuditedModel;
370
371 }
372
373 }