/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.verify; import com.liferay.portal.kernel.concurrent.ThrowableAwareRunnable; import com.liferay.portal.kernel.concurrent.ThrowableAwareRunnablesExecutorUtil; import com.liferay.portal.kernel.dao.db.BaseDBProcess; import com.liferay.portal.kernel.dao.jdbc.DataAccess; import com.liferay.portal.kernel.exception.BulkException; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.model.ReleaseConstants; import com.liferay.portal.kernel.util.ClassLoaderUtil; import com.liferay.portal.kernel.util.ClassUtil; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.util.PropsValues; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * This abstract class should be extended for startup processes that verify the * integrity of the database. They can be added as part of * <code>VerifyProcessSuite</code> or be executed independently by being set in * the portal.properties file. Each of these processes should not cause any * problems if run multiple times. * * @author Alexander Chow * @author Hugo Huijser */ public abstract class VerifyProcess extends BaseDBProcess { public static final int ALWAYS = -1; public static final int NEVER = 0; public static final int ONCE = 1; public void verify() throws VerifyException { long start = System.currentTimeMillis(); if (_log.isInfoEnabled()) { _log.info("Verifying " + ClassUtil.getClassName(this)); } try (Connection con = DataAccess.getUpgradeOptimizedConnection()) { connection = con; doVerify(); } catch (Exception e) { throw new VerifyException(e); } finally { connection = null; if (_log.isInfoEnabled()) { _log.info( "Completed verification process " + ClassUtil.getClassName(this) + " in " + (System.currentTimeMillis() - start) + "ms"); } } } public void verify(VerifyProcess verifyProcess) throws VerifyException { verifyProcess.verify(); } protected void doVerify() throws Exception { } protected void doVerify( Collection<? extends ThrowableAwareRunnable> throwableAwareRunnables) throws Exception { if ((throwableAwareRunnables.size() < PropsValues.VERIFY_PROCESS_CONCURRENCY_THRESHOLD) && !isForceConcurrent(throwableAwareRunnables)) { for (ThrowableAwareRunnable throwableAwareRunnable : throwableAwareRunnables) { throwableAwareRunnable.run(); } List<Throwable> throwables = new ArrayList<>(); for (ThrowableAwareRunnable throwableAwareRunnable : throwableAwareRunnables) { if (throwableAwareRunnable.hasException()) { throwables.add(throwableAwareRunnable.getThrowable()); } } if (!throwables.isEmpty()) { Class<?> clazz = getClass(); throw new BulkException( "Verification error: " + clazz.getName(), throwables); } } else { ThrowableAwareRunnablesExecutorUtil.execute( throwableAwareRunnables); } } /** * @return the portal build number before {@link * com.liferay.portal.tools.DBUpgrader} has a chance to update it to * the value in {@link * com.liferay.portal.kernel.util.ReleaseInfo#getBuildNumber} */ protected int getBuildNumber() throws Exception { try (PreparedStatement ps = connection.prepareStatement( "select buildNumber from Release_ where servletContextName = " + "?")) { ps.setString(1, ReleaseConstants.DEFAULT_SERVLET_CONTEXT_NAME); try (ResultSet rs = ps.executeQuery()) { rs.next(); return rs.getInt(1); } } } protected Set<String> getPortalTableNames() throws Exception { if (_portalTableNames != null) { return _portalTableNames; } ClassLoader classLoader = ClassLoaderUtil.getContextClassLoader(); String sql = StringUtil.read( classLoader, "com/liferay/portal/tools/sql/dependencies/portal-tables.sql"); Matcher matcher = _createTablePattern.matcher(sql); Set<String> tableNames = new HashSet<>(); while (matcher.find()) { String match = matcher.group(1); tableNames.add(StringUtil.toLowerCase(match)); } _portalTableNames = tableNames; return tableNames; } protected boolean isForceConcurrent( Collection<? extends ThrowableAwareRunnable> throwableAwareRunnables) { return false; } protected boolean isPortalTableName(String tableName) throws Exception { Set<String> portalTableNames = getPortalTableNames(); return portalTableNames.contains(StringUtil.toLowerCase(tableName)); } private static final Log _log = LogFactoryUtil.getLog(VerifyProcess.class); private final Pattern _createTablePattern = Pattern.compile( "create table (\\S*) \\("); private Set<String> _portalTableNames; }