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