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                            Connection con, String tableName, String pkColumnName, long primKey)
105                    throws Exception {
106    
107                    PreparedStatement ps = null;
108                    ResultSet rs = null;
109    
110                    try {
111                            ps = con.prepareStatement(
112                                    "select companyId, userId, createDate, modifiedDate from " +
113                                            tableName + " where " + pkColumnName + " = ?");
114    
115                            ps.setLong(1, primKey);
116    
117                            rs = ps.executeQuery();
118    
119                            if (rs.next()) {
120                                    long companyId = rs.getLong("companyId");
121                                    long userId = rs.getLong("userId");
122                                    Timestamp createDate = rs.getTimestamp("createDate");
123                                    Timestamp modifiedDate = rs.getTimestamp("modifiedDate");
124    
125                                    return new Object[] {
126                                            companyId, userId, getUserName(con, userId), createDate,
127                                            modifiedDate
128                                    };
129                            }
130    
131                            if (_log.isDebugEnabled()) {
132                                    _log.debug("Unable to find " + tableName + " " + primKey);
133                            }
134    
135                            return null;
136                    }
137                    finally {
138                            DataAccess.cleanUp(null, ps, rs);
139                    }
140            }
141    
142            protected Object[] getDefaultUserArray(Connection con, long companyId)
143                    throws Exception {
144    
145                    PreparedStatement ps = null;
146                    ResultSet rs = null;
147    
148                    try {
149                            ps = con.prepareStatement(
150                                    "select userId, firstName, middleName, lastName from User_" +
151                                            " where companyId = ? and defaultUser = ?");
152    
153                            ps.setLong(1, companyId);
154                            ps.setBoolean(2, true);
155    
156                            rs = ps.executeQuery();
157    
158                            if (rs.next()) {
159                                    long userId = rs.getLong("userId");
160                                    String firstName = rs.getString("firstName");
161                                    String middleName = rs.getString("middleName");
162                                    String lastName = rs.getString("lastName");
163    
164                                    FullNameGenerator fullNameGenerator =
165                                            FullNameGeneratorFactory.getInstance();
166    
167                                    String userName = fullNameGenerator.getFullName(
168                                            firstName, middleName, lastName);
169    
170                                    Timestamp createDate = new Timestamp(
171                                            System.currentTimeMillis());
172    
173                                    return new Object[] {
174                                            companyId, userId, userName, createDate, createDate
175                                    };
176                            }
177    
178                            return null;
179                    }
180                    finally {
181                            DataAccess.cleanUp(null, ps, rs);
182                    }
183            }
184    
185            protected String getUserName(Connection con, long userId) throws Exception {
186                    PreparedStatement ps = null;
187                    ResultSet rs = null;
188    
189                    try {
190                            ps = con.prepareStatement(
191                                    "select firstName, middleName, lastName from User_ where " +
192                                            "userId = ?");
193    
194                            ps.setLong(1, userId);
195    
196                            rs = ps.executeQuery();
197    
198                            if (rs.next()) {
199                                    String firstName = rs.getString("firstName");
200                                    String middleName = rs.getString("middleName");
201                                    String lastName = rs.getString("lastName");
202    
203                                    FullNameGenerator fullNameGenerator =
204                                            FullNameGeneratorFactory.getInstance();
205    
206                                    return fullNameGenerator.getFullName(
207                                            firstName, middleName, lastName);
208                            }
209    
210                            return StringPool.BLANK;
211                    }
212                    finally {
213                            DataAccess.cleanUp(null, ps, rs);
214                    }
215            }
216    
217            protected void verifyAuditedModel(
218                            Connection con, String tableName, String primaryKeyColumnName,
219                            long primKey, Object[] auditedModelArray, boolean updateDates)
220                    throws Exception {
221    
222                    PreparedStatement ps = null;
223    
224                    try {
225                            long companyId = (Long)auditedModelArray[0];
226    
227                            if (auditedModelArray[2] == null) {
228                                    auditedModelArray = getDefaultUserArray(con, companyId);
229    
230                                    if (auditedModelArray == null) {
231                                            return;
232                                    }
233                            }
234    
235                            long userId = (Long)auditedModelArray[1];
236                            String userName = (String)auditedModelArray[2];
237                            Timestamp createDate = (Timestamp)auditedModelArray[3];
238                            Timestamp modifiedDate = (Timestamp)auditedModelArray[4];
239    
240                            StringBundler sb = new StringBundler(7);
241    
242                            sb.append("update ");
243                            sb.append(tableName);
244                            sb.append(" set companyId = ?, userId = ?, userName = ?");
245    
246                            if (updateDates) {
247                                    sb.append(", createDate = ?, modifiedDate = ?");
248                            }
249    
250                            sb.append(" where ");
251                            sb.append(primaryKeyColumnName);
252                            sb.append(" = ?");
253    
254                            ps = con.prepareStatement(sb.toString());
255    
256                            ps.setLong(1, companyId);
257                            ps.setLong(2, userId);
258                            ps.setString(3, userName);
259    
260                            if (updateDates) {
261                                    ps.setTimestamp(4, createDate);
262                                    ps.setTimestamp(5, modifiedDate);
263                                    ps.setLong(6, primKey);
264                            }
265                            else {
266                                    ps.setLong(4, primKey);
267                            }
268    
269                            ps.executeUpdate();
270                    }
271                    catch (Exception e) {
272                            if (_log.isWarnEnabled()) {
273                                    _log.warn("Unable to verify model " + tableName, e);
274                            }
275                    }
276                    finally {
277                            DataAccess.cleanUp(ps);
278                    }
279            }
280    
281            protected void verifyAuditedModel(
282                            VerifiableAuditedModel verifiableAuditedModel)
283                    throws Exception {
284    
285                    PreparedStatement ps = null;
286                    ResultSet rs = null;
287    
288                    try (Connection con = DataAccess.getUpgradeOptimizedConnection()) {
289                            StringBundler sb = new StringBundler(8);
290    
291                            sb.append("select ");
292                            sb.append(verifiableAuditedModel.getPrimaryKeyColumnName());
293                            sb.append(", companyId");
294    
295                            if (verifiableAuditedModel.getJoinByTableName() != null) {
296                                    sb.append(StringPool.COMMA_AND_SPACE);
297                                    sb.append(verifiableAuditedModel.getJoinByTableName());
298                            }
299    
300                            sb.append(" from ");
301                            sb.append(verifiableAuditedModel.getTableName());
302                            sb.append(" where userName is null order by companyId");
303    
304                            ps = con.prepareStatement(sb.toString());
305    
306                            rs = ps.executeQuery();
307    
308                            Object[] auditedModelArray = null;
309    
310                            long previousCompanyId = 0;
311    
312                            while (rs.next()) {
313                                    long companyId = rs.getLong("companyId");
314                                    long primKey = rs.getLong(
315                                            verifiableAuditedModel.getPrimaryKeyColumnName());
316    
317                                    if (verifiableAuditedModel.getJoinByTableName() != null) {
318                                            long relatedPrimKey = rs.getLong(
319                                                    verifiableAuditedModel.getJoinByTableName());
320    
321                                            auditedModelArray = getAuditedModelArray(
322                                                    con, verifiableAuditedModel.getRelatedModelName(),
323                                                    verifiableAuditedModel.getRelatedPKColumnName(),
324                                                    relatedPrimKey);
325                                    }
326                                    else if (previousCompanyId != companyId) {
327                                            auditedModelArray = getDefaultUserArray(con, companyId);
328    
329                                            previousCompanyId = companyId;
330                                    }
331    
332                                    if (auditedModelArray == null) {
333                                            continue;
334                                    }
335    
336                                    verifyAuditedModel(
337                                            con, verifiableAuditedModel.getTableName(),
338                                            verifiableAuditedModel.getPrimaryKeyColumnName(), primKey,
339                                            auditedModelArray, verifiableAuditedModel.isUpdateDates());
340                            }
341                    }
342                    finally {
343                            DataAccess.cleanUp(null, ps, rs);
344                    }
345            }
346    
347            private static final Log _log = LogFactoryUtil.getLog(
348                    VerifyAuditedModel.class);
349    
350            private class VerifyAuditedModelRunnable extends ThrowableAwareRunnable {
351    
352                    public VerifyAuditedModelRunnable(
353                            VerifiableAuditedModel verifiableAuditedModel) {
354    
355                            _verifiableAuditedModel = verifiableAuditedModel;
356                    }
357    
358                    @Override
359                    protected void doRun() throws Exception {
360                            verifyAuditedModel(_verifiableAuditedModel);
361                    }
362    
363                    private final VerifiableAuditedModel _verifiableAuditedModel;
364    
365            }
366    
367    }