001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
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.DataAccess;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.util.StringBundler;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.portal.security.auth.FullNameGenerator;
025    import com.liferay.portal.security.auth.FullNameGeneratorFactory;
026    import com.liferay.portal.verify.model.VerifiableAuditedModel;
027    
028    import java.sql.Connection;
029    import java.sql.PreparedStatement;
030    import java.sql.ResultSet;
031    import java.sql.Timestamp;
032    
033    import java.util.ArrayList;
034    import java.util.Collection;
035    import java.util.List;
036    import java.util.Map;
037    
038    /**
039     * @author Michael C. Han
040     * @author Shinn Lok
041     */
042    public class VerifyAuditedModel extends VerifyProcess {
043    
044            public void verify(VerifiableAuditedModel ... verifiableAuditedModels)
045                    throws Exception {
046    
047                    List<String> unverifiedTableNames = new ArrayList<String>();
048    
049                    for (VerifiableAuditedModel verifiableAuditedModel :
050                                    verifiableAuditedModels) {
051    
052                            unverifiedTableNames.add(verifiableAuditedModel.getTableName());
053                    }
054    
055                    List<VerifyAuditedModelRunnable> verifyAuditedModelRunnables =
056                            new ArrayList<VerifyAuditedModelRunnable>(
057                                    unverifiedTableNames.size());
058    
059                    while (!unverifiedTableNames.isEmpty()) {
060                            int count = unverifiedTableNames.size();
061    
062                            for (VerifiableAuditedModel verifiableAuditedModel :
063                                            verifiableAuditedModels) {
064    
065                                    if (unverifiedTableNames.contains(
066                                                    verifiableAuditedModel.getJoinByTableName()) ||
067                                            !unverifiedTableNames.contains(
068                                                    verifiableAuditedModel.getTableName())) {
069    
070                                            continue;
071                                    }
072    
073                                    VerifyAuditedModelRunnable verifyAuditedModelRunnable =
074                                            new VerifyAuditedModelRunnable(verifiableAuditedModel);
075    
076                                    verifyAuditedModelRunnables.add(verifyAuditedModelRunnable);
077    
078                                    unverifiedTableNames.remove(
079                                            verifiableAuditedModel.getTableName());
080                            }
081    
082                            if (unverifiedTableNames.size() == count) {
083                                    throw new VerifyException(
084                                            "Circular dependency detected " + unverifiedTableNames);
085                            }
086                    }
087    
088                    doVerify(verifyAuditedModelRunnables);
089            }
090    
091            @Override
092            protected void doVerify() throws Exception {
093                    Map<String, VerifiableAuditedModel> verifiableAuditedModelsMap =
094                            PortalBeanLocatorUtil.locate(VerifiableAuditedModel.class);
095    
096                    Collection<VerifiableAuditedModel> verifiableAuditedModels =
097                            verifiableAuditedModelsMap.values();
098    
099                    verify(
100                            verifiableAuditedModels.toArray(
101                                    new VerifiableAuditedModel[verifiableAuditedModels.size()]));
102            }
103    
104            protected Object[] getAuditedModelArray(
105                            String tableName, String pkColumnName, long primKey)
106                    throws Exception {
107    
108                    Connection con = null;
109                    PreparedStatement ps = null;
110                    ResultSet rs = null;
111    
112                    try {
113                            con = DataAccess.getUpgradeOptimizedConnection();
114    
115                            ps = con.prepareStatement(
116                                    "select companyId, userId, createDate, modifiedDate from " +
117                                            tableName + " where " + pkColumnName + " = ?");
118    
119                            ps.setLong(1, primKey);
120    
121                            rs = ps.executeQuery();
122    
123                            if (rs.next()) {
124                                    long companyId = rs.getLong("companyId");
125                                    long userId = rs.getLong("userId");
126                                    Timestamp createDate = rs.getTimestamp("createDate");
127                                    Timestamp modifiedDate = rs.getTimestamp("modifiedDate");
128    
129                                    return new Object[] {
130                                            companyId, userId, getUserName(userId), createDate,
131                                            modifiedDate
132                                    };
133                            }
134    
135                            if (_log.isDebugEnabled()) {
136                                    _log.debug("Unable to find " + tableName + " " + primKey);
137                            }
138    
139                            return null;
140                    }
141                    finally {
142                            DataAccess.cleanUp(con, ps, rs);
143                    }
144            }
145    
146            protected Object[] getDefaultUserArray(Connection con, long companyId)
147                    throws Exception {
148    
149                    PreparedStatement ps = null;
150                    ResultSet rs = null;
151    
152                    try {
153                            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                            rs = ps.executeQuery();
161    
162                            if (rs.next()) {
163                                    long userId = rs.getLong("userId");
164                                    String firstName = rs.getString("firstName");
165                                    String middleName = rs.getString("middleName");
166                                    String lastName = rs.getString("lastName");
167    
168                                    FullNameGenerator fullNameGenerator =
169                                            FullNameGeneratorFactory.getInstance();
170    
171                                    String userName = fullNameGenerator.getFullName(
172                                            firstName, middleName, lastName);
173    
174                                    Timestamp createDate = new Timestamp(
175                                            System.currentTimeMillis());
176    
177                                    return new Object[] {
178                                            companyId, userId, userName, createDate, createDate
179                                    };
180                            }
181    
182                            return null;
183                    }
184                    finally {
185                            DataAccess.cleanUp(null, ps, rs);
186                    }
187            }
188    
189            protected String getUserName(long userId) throws Exception {
190                    Connection con = null;
191                    PreparedStatement ps = null;
192                    ResultSet rs = null;
193    
194                    try {
195                            con = DataAccess.getUpgradeOptimizedConnection();
196    
197                            ps = con.prepareStatement(
198                                    "select firstName, middleName, lastName from User_ where " +
199                                            "userId = ?");
200    
201                            ps.setLong(1, userId);
202    
203                            rs = ps.executeQuery();
204    
205                            if (rs.next()) {
206                                    String firstName = rs.getString("firstName");
207                                    String middleName = rs.getString("middleName");
208                                    String lastName = rs.getString("lastName");
209    
210                                    FullNameGenerator fullNameGenerator =
211                                            FullNameGeneratorFactory.getInstance();
212    
213                                    return fullNameGenerator.getFullName(
214                                            firstName, middleName, lastName);
215                            }
216    
217                            return StringPool.BLANK;
218                    }
219                    finally {
220                            DataAccess.cleanUp(con, ps, rs);
221                    }
222            }
223    
224            protected void verifyAuditedModel(
225                            String tableName, String primaryKeyColumnName, long primKey,
226                            Object[] auditedModelArray, boolean updateDates)
227                    throws Exception {
228    
229                    Connection con = null;
230                    PreparedStatement ps = null;
231    
232                    try {
233                            con = DataAccess.getUpgradeOptimizedConnection();
234    
235                            long companyId = (Long)auditedModelArray[0];
236    
237                            if (auditedModelArray[2] == null) {
238                                    auditedModelArray = getDefaultUserArray(con, companyId);
239    
240                                    if (auditedModelArray == null) {
241                                            return;
242                                    }
243                            }
244    
245                            long userId = (Long)auditedModelArray[1];
246                            String userName = (String)auditedModelArray[2];
247                            Timestamp createDate = (Timestamp)auditedModelArray[3];
248                            Timestamp modifiedDate = (Timestamp)auditedModelArray[4];
249    
250                            StringBundler sb = new StringBundler(7);
251    
252                            sb.append("update ");
253                            sb.append(tableName);
254                            sb.append(" set companyId = ?, userId = ?, userName = ?");
255    
256                            if (updateDates) {
257                                    sb.append(", createDate = ?, modifiedDate = ?");
258                            }
259    
260                            sb.append(" where ");
261                            sb.append(primaryKeyColumnName);
262                            sb.append(" = ?");
263    
264                            ps = con.prepareStatement(sb.toString());
265    
266                            ps.setLong(1, companyId);
267                            ps.setLong(2, userId);
268                            ps.setString(3, userName);
269    
270                            if (updateDates) {
271                                    ps.setTimestamp(4, createDate);
272                                    ps.setTimestamp(5, modifiedDate);
273                                    ps.setLong(6, primKey);
274                            }
275                            else {
276                                    ps.setLong(4, primKey);
277                            }
278    
279                            ps.executeUpdate();
280                    }
281                    catch (Exception e) {
282                            if (_log.isWarnEnabled()) {
283                                    _log.warn("Unable to verify model " + tableName, e);
284                            }
285                    }
286                    finally {
287                            DataAccess.cleanUp(con, ps);
288                    }
289            }
290    
291            protected void verifyAuditedModel(
292                            VerifiableAuditedModel verifiableAuditedModel)
293                    throws Exception {
294    
295                    Connection con = null;
296                    PreparedStatement ps = null;
297                    ResultSet rs = null;
298    
299                    try {
300                            con = DataAccess.getUpgradeOptimizedConnection();
301    
302                            StringBundler sb = new StringBundler(8);
303    
304                            sb.append("select ");
305                            sb.append(verifiableAuditedModel.getPrimaryKeyColumnName());
306                            sb.append(", companyId");
307    
308                            if (verifiableAuditedModel.getJoinByTableName() != null) {
309                                    sb.append(StringPool.COMMA_AND_SPACE);
310                                    sb.append(verifiableAuditedModel.getJoinByTableName());
311                            }
312    
313                            sb.append(" from ");
314                            sb.append(verifiableAuditedModel.getTableName());
315                            sb.append(" where userName is null order by companyId");
316    
317                            ps = con.prepareStatement(sb.toString());
318    
319                            rs = ps.executeQuery();
320    
321                            Object[] auditedModelArray = null;
322    
323                            long previousCompanyId = 0;
324    
325                            while (rs.next()) {
326                                    long companyId = rs.getLong("companyId");
327                                    long primKey = rs.getLong(
328                                            verifiableAuditedModel.getPrimaryKeyColumnName());
329    
330                                    if (verifiableAuditedModel.getJoinByTableName() != null) {
331                                            long relatedPrimKey = rs.getLong(
332                                                    verifiableAuditedModel.getJoinByTableName());
333    
334                                            auditedModelArray = getAuditedModelArray(
335                                                    verifiableAuditedModel.getRelatedModelName(),
336                                                    verifiableAuditedModel.getRelatedPKColumnName(),
337                                                    relatedPrimKey);
338                                    }
339                                    else if (previousCompanyId != companyId) {
340                                            auditedModelArray = getDefaultUserArray(con, companyId);
341    
342                                            previousCompanyId = companyId;
343                                    }
344    
345                                    if (auditedModelArray == null) {
346                                            continue;
347                                    }
348    
349                                    verifyAuditedModel(
350                                            verifiableAuditedModel.getTableName(),
351                                            verifiableAuditedModel.getPrimaryKeyColumnName(), primKey,
352                                            auditedModelArray, verifiableAuditedModel.isUpdateDates());
353                            }
354                    }
355                    finally {
356                            DataAccess.cleanUp(con, ps, rs);
357                    }
358            }
359    
360            private static final Log _log = LogFactoryUtil.getLog(
361                    VerifyAuditedModel.class);
362    
363            private class VerifyAuditedModelRunnable extends ThrowableAwareRunnable {
364    
365                    public VerifyAuditedModelRunnable(
366                            VerifiableAuditedModel verifiableAuditedModel) {
367    
368                            _verifiableAuditedModel = verifiableAuditedModel;
369                    }
370    
371                    @Override
372                    protected void doRun() throws Exception {
373                            verifyAuditedModel(_verifiableAuditedModel);
374                    }
375    
376                    private final VerifiableAuditedModel _verifiableAuditedModel;
377    
378            }
379    
380    }