/** * 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.upgrade.v6_2_0; import com.liferay.portal.kernel.json.JSONException; import com.liferay.portal.kernel.json.JSONFactoryUtil; import com.liferay.portal.kernel.json.JSONObject; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.upgrade.UpgradeProcess; import com.liferay.portal.kernel.util.LoggingTimer; import com.liferay.portal.kernel.util.PortalUtil; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; /** * @author Sergio Sanchez * @author Zsolt Berentey * @author Daniel Sanz */ public class UpgradeSocial extends UpgradeProcess { protected String createExtraData( ExtraDataFactory extraDataFactory, long companyId, long groupId, long userId, long classNameId, long classPK, int type, String extraData) throws Exception { if (extraDataFactory == null) { return null; } try (PreparedStatement preparedStatement = connection.prepareStatement( extraDataFactory.getSQL())) { extraDataFactory.setModelSQLParameters( preparedStatement, groupId, companyId, userId, classNameId, classPK, type, extraData); try (ResultSet resultSet = preparedStatement.executeQuery()) { if (resultSet.next()) { JSONObject extraDataJSONObject = extraDataFactory.createExtraDataJSONObject( resultSet, extraData); return extraDataJSONObject.toString(); } return null; } } } protected Map<Long, String> createExtraDataMap( ExtraDataFactory extraDataFactory) throws Exception { Map<Long, String> extraDataMap = new HashMap<>(); StringBundler sb = new StringBundler(4); sb.append("select activityId, groupId, companyId, userId, "); sb.append("classNameId, classPK, type_, extraData from "); sb.append("SocialActivity where "); sb.append(extraDataFactory.getActivitySQLWhereClause()); try (PreparedStatement preparedStatement = connection.prepareStatement( sb.toString())) { extraDataFactory.setActivitySQLParameters(preparedStatement); try (ResultSet resultSet = preparedStatement.executeQuery()) { while (resultSet.next()) { long activityId = resultSet.getLong("activityId"); long classNameId = resultSet.getLong("classNameId"); long classPK = resultSet.getLong("classPK"); long companyId = resultSet.getLong("companyId"); String extraData = resultSet.getString("extraData"); long groupId = resultSet.getLong("groupId"); int type = resultSet.getInt("type_"); long userId = resultSet.getLong("userId"); String newExtraData = createExtraData( extraDataFactory, groupId, companyId, userId, classNameId, classPK, type, extraData); if (newExtraData != null) { extraDataMap.put(activityId, newExtraData); } } } } return extraDataMap; } @Override protected void doUpgrade() throws Exception { updateJournalActivities(); updateSOSocialActivities(); updateActivities(); } protected void updateActivities() throws Exception { ExtraDataFactory[] extraDataFactories = { new AddAssetCommentExtraDataFactory(), new AddMessageExtraDataFactory(), new BlogsEntryExtraDataFactory(), new BookmarksEntryExtraDataFactory(), new DLFileEntryExtraDataFactory(), new KBArticleExtraDataFactory(), new KBCommentExtraDataFactory(), new KBTemplateExtraDataFactory(), new WikiPageExtraDataFactory() }; for (ExtraDataFactory extraDataFactory : extraDataFactories) { updateActivities(extraDataFactory); } } protected void updateActivities(ExtraDataFactory extraDataFactory) throws Exception { Map<Long, String> extraDataMap = createExtraDataMap(extraDataFactory); for (Map.Entry<Long, String> entry : extraDataMap.entrySet()) { long activityId = entry.getKey(); String extraData = entry.getValue(); try (PreparedStatement preparedStatement = connection.prepareStatement( "update SocialActivity set extraData = ? where " + "activityId = ?")) { preparedStatement.setString(1, extraData); preparedStatement.setLong(2, activityId); preparedStatement.executeUpdate(); } catch (Exception e) { if (_log.isWarnEnabled()) { _log.warn("Unable to update activity " + activityId, e); } } } } protected void updateJournalActivities() throws Exception { try (LoggingTimer loggingTimer = new LoggingTimer()) { long classNameId = PortalUtil.getClassNameId( "com.liferay.portlet.journal.model.JournalArticle"); String[] tableNames = {"SocialActivity", "SocialActivityCounter"}; for (String tableName : tableNames) { StringBundler sb = new StringBundler(7); sb.append("update "); sb.append(tableName); sb.append(" set classPK = (select resourcePrimKey from "); sb.append("JournalArticle where id_ = "); sb.append(tableName); sb.append(".classPK) where classNameId = "); sb.append(classNameId); runSQL(sb.toString()); } } } protected void updateSOSocialActivities() throws Exception { try (LoggingTimer loggingTimer = new LoggingTimer()) { if (!hasTable("SO_SocialActivity")) { return; } try (PreparedStatement preparedStatement = connection.prepareStatement( "select activityId, activitySetId from " + "SO_SocialActivity"); ResultSet resultSet = preparedStatement.executeQuery()) { while (resultSet.next()) { long activityId = resultSet.getLong("activityId"); long activitySetId = resultSet.getLong("activitySetId"); StringBundler sb = new StringBundler(4); sb.append("update SocialActivity set activitySetId = "); sb.append(activitySetId); sb.append(" where activityId = "); sb.append(activityId); runSQL(sb.toString()); } } runSQL("drop table SO_SocialActivity"); } } /** * Defines the necessary methods to generate extra data from a set of social * activities (<code>com.liferay.social.kernel.model.SocialActivity</code> * instances) of any kind. * * <p> * Implementations have to focus on: * </p> * * <ol> * <li> * What is the set of social activities the factory generates extra data * for. See {@link #getActivitySQLWhereClause()} and {@link * #setActivitySQLParameters(PreparedStatement)}. * </li> * <li> * How to obtain the model entities related to such activities. See * {@link #getSQL()} and {@link * #setModelSQLParameters(PreparedStatement, long, long, long, long, * long, int, String)}. * </li> * <li> * How to generate extra data from that model entity. See {@link * #createExtraDataJSONObject(ResultSet, String)}. * </li> * </ol> * * <p> * The ExtraData Framework works with a list of ExtraData factories. for * each one, a query to SocialActivity table is built and run. The extra * data for each <code>SocialActivity</code> tuple returned by the query is * generated by querying the appropriate entity as dictated by the Factory * and building the extra data from that entity tuple. Then the framework * updates the extra data in the original <code>SocialActivity</code> tuple, * so that the Social Activity Interpreters can find what they need after * the upgrade. * </p> */ protected interface ExtraDataFactory { /** * Returns the JSON object containing the extra data. Given a result * from the {@link #getSQL()} and the original extra data in the * <code>SocialActivity</code> tuple pointing to that entity, this * method computes the extra data that will be persisted in the * <code>SocialActivity</code> tuple as a result of the upgrade process. */ public JSONObject createExtraDataJSONObject( ResultSet resultSet, String extraData) throws SQLException; /** * Returns the class name of the entity whose activities the factory * generates extra data for. The class name is useful if the factory * needs to filter activities by class name ID or refer to other * factories' class names. */ public String getActivityClassName(); /** * Returns the "where" clause in the social activity query to select the * <code>SocialActivity</code> tuples the factory generates extra data * for. */ public String getActivitySQLWhereClause(); /** * Returns the SQL query on any model entity which the selected * <code>SocialActivity</code> tuples refer to. Extra data is generated * from the entities returned by this query. */ public String getSQL(); /** * Sets parameters required to run the activity query returned by {@link * #getActivitySQLWhereClause()} in the factory. */ public void setActivitySQLParameters( PreparedStatement preparedStatement) throws SQLException; /** * Sets parameters required to run the entity query returned by {@link * #getSQL()} in the factory, based on fields from the * <code>SocialActivity</code> tuple. */ public void setModelSQLParameters( PreparedStatement preparedStatement, long companyId, long groupId, long userId, long classNameId, long classPK, int type, String extraData) throws SQLException; } private static final Log _log = LogFactoryUtil.getLog(UpgradeSocial.class); private class AddAssetCommentExtraDataFactory implements ExtraDataFactory { @Override public JSONObject createExtraDataJSONObject( ResultSet resultSet, String extraData) throws SQLException { JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject(); long messageId = 0; try { JSONObject jsonObject = JSONFactoryUtil.createJSONObject( extraData); messageId = jsonObject.getLong("messageId"); } catch (JSONException jsone) { // LPS-52675 if (_log.isDebugEnabled()) { _log.debug(jsone, jsone); } } extraDataJSONObject.put("messageId", messageId); extraDataJSONObject.put("title", resultSet.getString("subject")); return extraDataJSONObject; } @Override public String getActivityClassName() { return StringPool.BLANK; } @Override public String getActivitySQLWhereClause() { return "type_ = ?"; } @Override public String getSQL() { return "select subject from MBMessage where messageId = ?"; } @Override public void setActivitySQLParameters( PreparedStatement preparedStatement) throws SQLException { preparedStatement.setInt(1, _TYPE_ADD_COMMENT); } @Override public void setModelSQLParameters( PreparedStatement preparedStatement, long companyId, long groupId, long userId, long classNameId, long classPK, int type, String extraData) throws SQLException { long messageId = 0; try { JSONObject jsonObject = JSONFactoryUtil.createJSONObject( extraData); messageId = jsonObject.getLong("messageId"); } catch (JSONException jsone) { // LPS-52675 if (_log.isDebugEnabled()) { _log.debug(jsone); } } preparedStatement.setLong(1, messageId); } private static final int _TYPE_ADD_COMMENT = 10005; }; private class AddMessageExtraDataFactory implements ExtraDataFactory { @Override public JSONObject createExtraDataJSONObject( ResultSet resultSet, String extraData) throws SQLException { JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject(); extraDataJSONObject.put("title", resultSet.getString("subject")); return extraDataJSONObject; } @Override public String getActivityClassName() { return "com.liferay.portlet.messageboards.model.MBMessage"; } @Override public String getActivitySQLWhereClause() { return "classNameId = ? and (type_ = ? or type_ = ?)"; } @Override public String getSQL() { return "select subject from MBMessage where messageId = ?"; } @Override public void setActivitySQLParameters( PreparedStatement preparedStatement) throws SQLException { preparedStatement.setLong( 1, PortalUtil.getClassNameId(getActivityClassName())); preparedStatement.setInt(2, _ADD_MESSAGE); preparedStatement.setInt(3, _REPLY_MESSAGE); } @Override public void setModelSQLParameters( PreparedStatement preparedStatement, long companyId, long groupId, long userId, long classNameId, long classPK, int type, String extraData) throws SQLException { preparedStatement.setLong(1, classPK); } private static final int _ADD_MESSAGE = 1; private static final int _REPLY_MESSAGE = 2; }; private class BlogsEntryExtraDataFactory implements ExtraDataFactory { @Override public JSONObject createExtraDataJSONObject( ResultSet resultSet, String extraData) throws SQLException { JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject(); extraDataJSONObject.put("title", resultSet.getString("title")); return extraDataJSONObject; } @Override public String getActivityClassName() { return "com.liferay.portlet.blogs.model.BlogsEntry"; } @Override public String getActivitySQLWhereClause() { return "classNameId = ? and (type_ = ? or type_ = ?)"; } @Override public String getSQL() { return "select title from BlogsEntry where entryId = ?"; } @Override public void setActivitySQLParameters( PreparedStatement preparedStatement) throws SQLException { preparedStatement.setLong( 1, PortalUtil.getClassNameId(getActivityClassName())); preparedStatement.setInt(2, _ADD_ENTRY); preparedStatement.setInt(3, _UPDATE_ENTRY); } @Override public void setModelSQLParameters( PreparedStatement preparedStatement, long companyId, long groupId, long userId, long classNameId, long classPK, int type, String extraData) throws SQLException { preparedStatement.setLong(1, classPK); } private static final int _ADD_ENTRY = 2; private static final int _UPDATE_ENTRY = 3; }; private class BookmarksEntryExtraDataFactory implements ExtraDataFactory { @Override public JSONObject createExtraDataJSONObject( ResultSet resultSet, String extraData) throws SQLException { JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject(); extraDataJSONObject.put("title", resultSet.getString("name")); return extraDataJSONObject; } @Override public String getActivityClassName() { return "com.liferay.portlet.bookmarks.model.BookmarksEntry"; } @Override public String getActivitySQLWhereClause() { return "classNameId = ? and (type_ = ? or type_ = ?)"; } @Override public String getSQL() { return "select name from BookmarksEntry where entryId = ?"; } @Override public void setActivitySQLParameters( PreparedStatement preparedStatement) throws SQLException { preparedStatement.setLong( 1, PortalUtil.getClassNameId(getActivityClassName())); preparedStatement.setInt(2, _ADD_ENTRY); preparedStatement.setInt(3, _UPDATE_ENTRY); } @Override public void setModelSQLParameters( PreparedStatement preparedStatement, long companyId, long groupId, long userId, long classNameId, long classPK, int type, String extraData) throws SQLException { preparedStatement.setLong(1, classPK); } private static final int _ADD_ENTRY = 1; private static final int _UPDATE_ENTRY = 2; }; private class DLFileEntryExtraDataFactory implements ExtraDataFactory { @Override public JSONObject createExtraDataJSONObject( ResultSet resultSet, String extraData) throws SQLException { JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject(); extraDataJSONObject.put("title", resultSet.getString("title")); return extraDataJSONObject; } @Override public String getActivityClassName() { return "com.liferay.portlet.documentlibrary.model.DLFileEntry"; } @Override public String getActivitySQLWhereClause() { return "classNameId = ?"; } @Override public String getSQL() { return "select title from DLFileEntry where companyId = ? and " + "groupId = ? and fileEntryId = ?"; } @Override public void setActivitySQLParameters( PreparedStatement preparedStatement) throws SQLException { preparedStatement.setLong( 1, PortalUtil.getClassNameId(getActivityClassName())); } @Override public void setModelSQLParameters( PreparedStatement preparedStatement, long companyId, long groupId, long userId, long classNameId, long classPK, int type, String extraData) throws SQLException { preparedStatement.setLong(1, companyId); preparedStatement.setLong(2, groupId); preparedStatement.setLong(3, classPK); } }; private class KBArticleExtraDataFactory implements ExtraDataFactory { @Override public JSONObject createExtraDataJSONObject( ResultSet resultSet, String extraData) throws SQLException { JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject(); extraDataJSONObject.put("title", resultSet.getString("title")); return extraDataJSONObject; } @Override public String getActivityClassName() { return "com.liferay.knowledgebase.model.KBArticle"; } @Override public String getActivitySQLWhereClause() { return "classNameId = ? and (type_ = ? or type_ = ? or type_ = ?)"; } @Override public String getSQL() { return "select title from KBArticle where resourcePrimKey = ?"; } @Override public void setActivitySQLParameters( PreparedStatement preparedStatement) throws SQLException { preparedStatement.setLong( 1, PortalUtil.getClassNameId(getActivityClassName())); preparedStatement.setInt(2, _ADD_KB_ARTICLE); preparedStatement.setInt(3, _UPDATE_KB_ARTICLE); preparedStatement.setInt(4, _MOVE_KB_ARTICLE); } @Override public void setModelSQLParameters( PreparedStatement preparedStatement, long companyId, long groupId, long userId, long classNameId, long classPK, int type, String extraData) throws SQLException { preparedStatement.setLong(1, classPK); } private static final int _ADD_KB_ARTICLE = 1; private static final int _MOVE_KB_ARTICLE = 7; private static final int _UPDATE_KB_ARTICLE = 3; }; private class KBCommentExtraDataFactory implements ExtraDataFactory { @Override public JSONObject createExtraDataJSONObject( ResultSet resultSet, String extraData) throws SQLException { long classNameId = resultSet.getLong("classNameId"); long classPK = resultSet.getLong("classPK"); ExtraDataFactory extraDataFactory = null; if (classNameId == PortalUtil.getClassNameId( _kbArticleExtraDataFactory.getActivityClassName())) { extraDataFactory = _kbArticleExtraDataFactory; } else if (classNameId == PortalUtil.getClassNameId( _kbTemplateExtraDataFactory.getActivityClassName())) { extraDataFactory = _kbTemplateExtraDataFactory; } if (extraDataFactory == null) { return null; } try (PreparedStatement preparedStatement = connection.prepareStatement(extraDataFactory.getSQL())) { preparedStatement.setLong(1, classPK); try (ResultSet curResultSet = preparedStatement.executeQuery()) { while (curResultSet.next()) { return extraDataFactory.createExtraDataJSONObject( curResultSet, StringPool.BLANK); } } } return null; } @Override public String getActivityClassName() { return "com.liferay.knowledgebase.model.KBComment"; } @Override public String getActivitySQLWhereClause() { return "classNameId = ? and (type_ = ? or type_ = ?)"; } @Override public String getSQL() { return "select classNameId, classPK from KBComment where " + "kbCommentId = ?"; } @Override public void setActivitySQLParameters( PreparedStatement preparedStatement) throws SQLException { preparedStatement.setLong( 1, PortalUtil.getClassNameId(getActivityClassName())); preparedStatement.setInt(2, _ADD_KB_COMMENT); preparedStatement.setInt(3, _UPDATE_KB_COMMENT); } @Override public void setModelSQLParameters( PreparedStatement preparedStatement, long companyId, long groupId, long userId, long classNameId, long classPK, int type, String extraData) throws SQLException { preparedStatement.setLong(1, classPK); } private static final int _ADD_KB_COMMENT = 5; private static final int _UPDATE_KB_COMMENT = 6; private final KBArticleExtraDataFactory _kbArticleExtraDataFactory = new KBArticleExtraDataFactory(); private final KBTemplateExtraDataFactory _kbTemplateExtraDataFactory = new KBTemplateExtraDataFactory(); }; private class KBTemplateExtraDataFactory implements ExtraDataFactory { @Override public JSONObject createExtraDataJSONObject( ResultSet resultSet, String extraData) throws SQLException { JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject(); extraDataJSONObject.put("title", resultSet.getString("title")); return extraDataJSONObject; } @Override public String getActivityClassName() { return "com.liferay.knowledgebase.model.KBTemplate"; } @Override public String getActivitySQLWhereClause() { return "classNameId = ? and (type_ = ? or type_ = ?)"; } @Override public String getSQL() { return "select title from KBTemplate where kbTemplateId = ?"; } @Override public void setActivitySQLParameters( PreparedStatement preparedStatement) throws SQLException { preparedStatement.setLong( 1, PortalUtil.getClassNameId(getActivityClassName())); preparedStatement.setInt(2, _ADD_KB_TEMPLATE); preparedStatement.setInt(3, _UPDATE_KB_TEMPLATE); } @Override public void setModelSQLParameters( PreparedStatement preparedStatement, long companyId, long groupId, long userId, long classNameId, long classPK, int type, String extraData) throws SQLException { preparedStatement.setLong(1, classPK); } private static final int _ADD_KB_TEMPLATE = 2; private static final int _UPDATE_KB_TEMPLATE = 4; }; private class WikiPageExtraDataFactory implements ExtraDataFactory { @Override public JSONObject createExtraDataJSONObject( ResultSet resultSet, String extraData) throws SQLException { JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject(); extraDataJSONObject.put("title", resultSet.getString("title")); extraDataJSONObject.put("version", resultSet.getDouble("version")); return extraDataJSONObject; } @Override public String getActivityClassName() { return "com.liferay.portlet.wiki.model.WikiPage"; } @Override public String getActivitySQLWhereClause() { return "classNameId = ? and (type_ = ? or type_ = ?)"; } @Override public String getSQL() { return "select title, version from WikiPage where companyId = ? " + "and groupId = ? and resourcePrimKey = ? and head = ?"; } @Override public void setActivitySQLParameters( PreparedStatement preparedStatement) throws SQLException { preparedStatement.setLong( 1, PortalUtil.getClassNameId(getActivityClassName())); preparedStatement.setInt(2, _ADD_PAGE); preparedStatement.setInt(3, _UPDATE_PAGE); } @Override public void setModelSQLParameters( PreparedStatement preparedStatement, long companyId, long groupId, long userId, long classNameId, long classPK, int type, String extraData) throws SQLException { preparedStatement.setLong(1, companyId); preparedStatement.setLong(2, groupId); preparedStatement.setLong(3, classPK); preparedStatement.setBoolean(4, true); } private static final int _ADD_PAGE = 1; private static final int _UPDATE_PAGE = 2; }; }