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.kernel.upgrade;
016    
017    import com.liferay.portal.kernel.dao.jdbc.AutoBatchPreparedStatementUtil;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.model.LayoutTypePortletConstants;
021    import com.liferay.portal.kernel.model.PortletConstants;
022    import com.liferay.portal.kernel.model.PortletInstance;
023    import com.liferay.portal.kernel.model.ResourceConstants;
024    import com.liferay.portal.kernel.service.permission.PortletPermissionUtil;
025    import com.liferay.portal.kernel.util.GetterUtil;
026    import com.liferay.portal.kernel.util.LoggingTimer;
027    import com.liferay.portal.kernel.util.StringBundler;
028    import com.liferay.portal.kernel.util.StringPool;
029    import com.liferay.portal.kernel.util.StringUtil;
030    import com.liferay.portal.kernel.util.UnicodeProperties;
031    
032    import java.sql.PreparedStatement;
033    import java.sql.ResultSet;
034    import java.sql.SQLException;
035    
036    /**
037     * @author Brian Wing Shun Chan
038     */
039    public abstract class BaseUpgradePortletId extends UpgradeProcess {
040    
041            @Override
042            protected void doUpgrade() throws Exception {
043                    upgradeInstanceablePortletIds();
044                    upgradeUninstanceablePortletIds();
045            }
046    
047            protected String getNewTypeSettings(
048                    String typeSettings, String oldRootPortletId, String newRootPortletId,
049                    boolean exactMatch) {
050    
051                    UnicodeProperties typeSettingsProperties = new UnicodeProperties(true);
052    
053                    typeSettingsProperties.fastLoad(typeSettings);
054    
055                    for (int i = 1; i <= 10; i++) {
056                            String column = LayoutTypePortletConstants.COLUMN_PREFIX + i;
057    
058                            if (!typeSettingsProperties.containsKey(column)) {
059                                    continue;
060                            }
061    
062                            String[] portletIds = StringUtil.split(
063                                    typeSettingsProperties.getProperty(column));
064    
065                            for (int j = 0; j < portletIds.length; j++) {
066                                    String portletId = portletIds[j];
067    
068                                    if (exactMatch) {
069                                            if (portletId.equals(oldRootPortletId)) {
070                                                    portletIds[j] = newRootPortletId;
071                                            }
072    
073                                            continue;
074                                    }
075    
076                                    String rootPortletId = PortletConstants.getRootPortletId(
077                                            portletId);
078    
079                                    if (!rootPortletId.equals(oldRootPortletId)) {
080                                            continue;
081                                    }
082    
083                                    long userId = PortletConstants.getUserId(portletId);
084                                    String instanceId = PortletConstants.getInstanceId(portletId);
085    
086                                    portletIds[j] = PortletConstants.assemblePortletId(
087                                            newRootPortletId, userId, instanceId);
088                            }
089    
090                            typeSettingsProperties.setProperty(
091                                    column, StringUtil.merge(portletIds).concat(StringPool.COMMA));
092                    }
093    
094                    return typeSettingsProperties.toString();
095            }
096    
097            protected String[][] getRenamePortletIdsArray() {
098                    return new String[0][0];
099            }
100    
101            protected String getTypeSettingsCriteria(String portletId) {
102                    StringBundler sb = new StringBundler(21);
103    
104                    sb.append("typeSettings like '%=");
105                    sb.append(portletId);
106                    sb.append(",%' OR typeSettings like '%=");
107                    sb.append(portletId);
108                    sb.append("\n%' OR typeSettings like '%=");
109                    sb.append(portletId);
110                    sb.append("%' OR typeSettings like '%,");
111                    sb.append(portletId);
112                    sb.append(",%' OR typeSettings like '%,");
113                    sb.append(portletId);
114                    sb.append("\n%' OR typeSettings like '%,");
115                    sb.append(portletId);
116                    sb.append("%' OR typeSettings like '%=");
117                    sb.append(portletId);
118                    sb.append("_INSTANCE_%' OR typeSettings like '%,");
119                    sb.append(portletId);
120                    sb.append("_INSTANCE_%' OR typeSettings like '%=");
121                    sb.append(portletId);
122                    sb.append("_USER_%' OR typeSettings like '%,");
123                    sb.append(portletId);
124                    sb.append("_USER_%'");
125    
126                    return sb.toString();
127            }
128    
129            protected String[] getUninstanceablePortletIds() {
130                    return new String[0];
131            }
132    
133            protected void updateInstanceablePortletPreferences(
134                            String oldRootPortletId, String newRootPortletId)
135                    throws Exception {
136    
137                    StringBundler sb = new StringBundler(8);
138    
139                    sb.append("select portletPreferencesId, portletId from ");
140                    sb.append("PortletPreferences where portletId = '");
141                    sb.append(oldRootPortletId);
142                    sb.append("' OR portletId like '");
143                    sb.append(oldRootPortletId);
144                    sb.append("_INSTANCE_%' OR portletId like '");
145                    sb.append(oldRootPortletId);
146                    sb.append("_USER_%_INSTANCE_%'");
147    
148                    try (PreparedStatement ps1 = connection.prepareStatement(sb.toString());
149                            PreparedStatement ps2 =
150                                    AutoBatchPreparedStatementUtil.concurrentAutoBatch(
151                                            connection,
152                                            "update PortletPreferences set portletId = ? where " +
153                                                    "portletPreferencesId = ?");
154                            ResultSet rs = ps1.executeQuery()) {
155    
156                            while (rs.next()) {
157                                    long portletPreferencesId = rs.getLong("portletPreferencesId");
158                                    String portletId = rs.getString("portletId");
159    
160                                    String newPortletId = StringUtil.replace(
161                                            portletId, oldRootPortletId, newRootPortletId);
162    
163                                    ps2.setString(1, newPortletId);
164                                    ps2.setLong(2, portletPreferencesId);
165    
166                                    ps2.addBatch();
167                            }
168    
169                            ps2.executeBatch();
170                    }
171            }
172    
173            protected void updateLayout(long plid, String typeSettings)
174                    throws Exception {
175    
176                    try (PreparedStatement ps = connection.prepareStatement(
177                                    "update Layout set typeSettings = ? where plid = " + plid)) {
178    
179                            ps.setString(1, typeSettings);
180    
181                            ps.executeUpdate();
182                    }
183                    catch (SQLException sqle) {
184                            if (_log.isWarnEnabled()) {
185                                    _log.warn(sqle, sqle);
186                            }
187                    }
188            }
189    
190            protected void updateLayout(
191                            long plid, String oldPortletId, String newPortletId)
192                    throws Exception {
193    
194                    try (PreparedStatement ps = connection.prepareStatement(
195                                    "select typeSettings from Layout where plid = " + plid);
196                            ResultSet rs = ps.executeQuery()) {
197    
198                            while (rs.next()) {
199                                    String typeSettings = rs.getString("typeSettings");
200    
201                                    String newTypeSettings = StringUtil.replace(
202                                            typeSettings, oldPortletId, newPortletId);
203    
204                                    updateLayout(plid, newTypeSettings);
205                            }
206                    }
207                    catch (Exception e) {
208                            if (_log.isWarnEnabled()) {
209                                    _log.warn(e, e);
210                            }
211                    }
212            }
213    
214            protected void updateLayoutRevision(
215                            long layoutRevisionId, String typeSettings)
216                    throws Exception {
217    
218                    String sql =
219                            "update LayoutRevision set typeSettings = ? " +
220                                    "where layoutRevisionId = " + layoutRevisionId;
221    
222                    try (PreparedStatement ps = connection.prepareStatement(sql)) {
223                            ps.setString(1, typeSettings);
224    
225                            ps.executeUpdate();
226                    }
227                    catch (SQLException sqle) {
228                            if (_log.isWarnEnabled()) {
229                                    _log.warn(sqle, sqle);
230                            }
231                    }
232            }
233    
234            protected void updateLayoutRevisions(
235                            String oldRootPortletId, String newRootPortletId,
236                            boolean exactMatch)
237                    throws Exception {
238    
239                    String sql =
240                            "select layoutRevisionId, typeSettings from LayoutRevision where " +
241                                    getTypeSettingsCriteria(oldRootPortletId);
242    
243                    try (PreparedStatement ps = connection.prepareStatement(sql);
244                            ResultSet rs = ps.executeQuery()) {
245    
246                            while (rs.next()) {
247                                    long layoutRevisionId = rs.getLong("layoutRevisionId");
248                                    String typeSettings = rs.getString("typeSettings");
249    
250                                    String newTypeSettings = getNewTypeSettings(
251                                            typeSettings, oldRootPortletId, newRootPortletId,
252                                            exactMatch);
253    
254                                    updateLayoutRevision(layoutRevisionId, newTypeSettings);
255                            }
256                    }
257            }
258    
259            protected void updateLayouts(
260                            String oldRootPortletId, String newRootPortletId,
261                            boolean exactMatch)
262                    throws Exception {
263    
264                    String sql =
265                            "select plid, typeSettings from Layout where " +
266                                    getTypeSettingsCriteria(oldRootPortletId);
267    
268                    try (PreparedStatement ps = connection.prepareStatement(sql);
269                            ResultSet rs = ps.executeQuery()) {
270    
271                            while (rs.next()) {
272                                    long plid = rs.getLong("plid");
273                                    String typeSettings = rs.getString("typeSettings");
274    
275                                    String newTypeSettings = getNewTypeSettings(
276                                            typeSettings, oldRootPortletId, newRootPortletId,
277                                            exactMatch);
278    
279                                    updateLayout(plid, newTypeSettings);
280                            }
281                    }
282            }
283    
284            protected void updatePortlet(
285                            String oldRootPortletId, String newRootPortletId)
286                    throws Exception {
287    
288                    try {
289                            updatePortletId(oldRootPortletId, newRootPortletId);
290    
291                            updateResourceAction(oldRootPortletId, newRootPortletId);
292    
293                            updateResourcePermission(oldRootPortletId, newRootPortletId, true);
294    
295                            updateUserNotificationDelivery(oldRootPortletId, newRootPortletId);
296    
297                            updateUserNotificationEvent(oldRootPortletId, newRootPortletId);
298    
299                            updateInstanceablePortletPreferences(
300                                    oldRootPortletId, newRootPortletId);
301                    }
302                    catch (Exception e) {
303                            if (_log.isWarnEnabled()) {
304                                    _log.warn(e, e);
305                            }
306                    }
307            }
308    
309            protected void updatePortletId(
310                            String oldRootPortletId, String newRootPortletId)
311                    throws Exception {
312    
313                    runSQL(
314                            "update Portlet set portletId = '" + newRootPortletId +
315                                    "' where portletId = '" + oldRootPortletId + "'");
316            }
317    
318            protected void updateResourceAction(String oldName, String newName)
319                    throws Exception {
320    
321                    runSQL(
322                            "update ResourceAction set name = '" + newName +
323                                    "' where name = '" + oldName + "'");
324            }
325    
326            protected void updateResourcePermission(
327                            String oldRootPortletId, String newRootPortletId,
328                            boolean updateName)
329                    throws Exception {
330    
331                    try (PreparedStatement ps1 = connection.prepareStatement(
332                                    "select resourcePermissionId, name, scope, primKey from " +
333                                            "ResourcePermission where name = '" + oldRootPortletId +
334                                                    "'");
335                            PreparedStatement ps2 =
336                                    AutoBatchPreparedStatementUtil.concurrentAutoBatch(
337                                            connection,
338                                            "update ResourcePermission set name = ?, primKey = ? " +
339                                                    "where resourcePermissionId = ?");
340                            ResultSet rs = ps1.executeQuery()) {
341    
342                            while (rs.next()) {
343                                    long resourcePermissionId = rs.getLong("resourcePermissionId");
344                                    String name = rs.getString("name");
345                                    int scope = rs.getInt("scope");
346                                    String primKey = rs.getString("primKey");
347    
348                                    String newName = name;
349    
350                                    if (updateName) {
351                                            newName = newRootPortletId;
352                                    }
353    
354                                    if (scope == ResourceConstants.SCOPE_INDIVIDUAL) {
355                                            int pos = primKey.indexOf(
356                                                    PortletConstants.LAYOUT_SEPARATOR);
357    
358                                            if (pos != -1) {
359                                                    long plid = GetterUtil.getLong(
360                                                            primKey.substring(0, pos));
361    
362                                                    String portletId = primKey.substring(
363                                                            pos + PortletConstants.LAYOUT_SEPARATOR.length());
364    
365                                                    String instanceId = PortletConstants.getInstanceId(
366                                                            portletId);
367                                                    long userId = PortletConstants.getUserId(portletId);
368    
369                                                    String newPortletId =
370                                                            PortletConstants.assemblePortletId(
371                                                                    newRootPortletId, userId, instanceId);
372    
373                                                    primKey = PortletPermissionUtil.getPrimaryKey(
374                                                            plid, newPortletId);
375                                            }
376    
377                                            if (name.equals(primKey)) {
378                                                    primKey = newName;
379                                            }
380                                    }
381    
382                                    ps2.setString(1, newName);
383                                    ps2.setString(2, primKey);
384                                    ps2.setLong(3, resourcePermissionId);
385    
386                                    ps2.addBatch();
387                            }
388    
389                            ps2.executeBatch();
390                    }
391                    catch (SQLException sqle) {
392                            if (_log.isWarnEnabled()) {
393                                    _log.warn(sqle, sqle);
394                            }
395                    }
396            }
397    
398            protected void updateUserNotificationDelivery(
399                            String oldPortletId, String newPortletId)
400                    throws Exception {
401    
402                    runSQL(
403                            "update UserNotificationDelivery set portletId = '" + newPortletId +
404                                    "' where portletId = '" + oldPortletId +"'");
405            }
406    
407            protected void updateUserNotificationEvent(
408                            String oldPortletId, String newPortletId)
409                    throws Exception {
410    
411                    runSQL(
412                            "update UserNotificationEvent set type_ = '" + newPortletId +
413                                    "' where type_ = '" + oldPortletId + "'");
414            }
415    
416            protected void upgradeInstanceablePortletIds() throws Exception {
417    
418                    // Rename instanceable portlet IDs. We expect the root form of the
419                    // portlet ID because we will rename all instances of the portlet ID.
420    
421                    try (LoggingTimer loggingTimer = new LoggingTimer()) {
422                            String[][] renamePortletIdsArray = getRenamePortletIdsArray();
423    
424                            for (String[] renamePortletIds : renamePortletIdsArray) {
425                                    String oldRootPortletId = renamePortletIds[0];
426                                    String newRootPortletId = renamePortletIds[1];
427    
428                                    updatePortlet(oldRootPortletId, newRootPortletId);
429                                    updateLayoutRevisions(
430                                            oldRootPortletId, newRootPortletId, false);
431                                    updateLayouts(oldRootPortletId, newRootPortletId, false);
432                            }
433                    }
434            }
435    
436            protected void upgradeUninstanceablePortletIds() throws Exception {
437    
438                    // Rename uninstanceable portlet IDs to instanceable portlet IDs
439    
440                    try (LoggingTimer loggingTimer = new LoggingTimer()) {
441                            String[] uninstanceablePortletIds = getUninstanceablePortletIds();
442    
443                            for (String portletId : uninstanceablePortletIds) {
444                                    PortletInstance portletInstance =
445                                            PortletInstance.fromPortletInstanceKey(portletId);
446    
447                                    if (portletInstance.hasInstanceId()) {
448                                            if (_log.isWarnEnabled()) {
449                                                    _log.warn(
450                                                            "Portlet " + portletId +
451                                                                    " is already instanceable");
452                                            }
453    
454                                            continue;
455                                    }
456    
457                                    PortletInstance newPortletInstance = new PortletInstance(
458                                            portletId);
459    
460                                    String newPortletInstanceKey =
461                                            newPortletInstance.getPortletInstanceKey();
462    
463                                    updateInstanceablePortletPreferences(
464                                            portletId, newPortletInstanceKey);
465                                    updateResourcePermission(
466                                            portletId, newPortletInstanceKey, false);
467                                    updateLayoutRevisions(portletId, newPortletInstanceKey, true);
468                                    updateLayouts(portletId, newPortletInstanceKey, true);
469                            }
470                    }
471            }
472    
473            private static final Log _log = LogFactoryUtil.getLog(
474                    BaseUpgradePortletId.class);
475    
476    }