/** * 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.dao.orm.ActionableDynamicQuery; import com.liferay.portal.kernel.dao.orm.DynamicQuery; import com.liferay.portal.kernel.dao.orm.Projection; import com.liferay.portal.kernel.dao.orm.ProjectionFactoryUtil; import com.liferay.portal.kernel.dao.orm.Property; import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil; import com.liferay.portal.kernel.exception.LayoutFriendlyURLException; import com.liferay.portal.kernel.language.LanguageUtil; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.model.Layout; import com.liferay.portal.kernel.model.LayoutFriendlyURL; import com.liferay.portal.kernel.service.LayoutFriendlyURLLocalServiceUtil; import com.liferay.portal.kernel.service.LayoutLocalServiceUtil; import com.liferay.portal.kernel.util.LocaleUtil; import com.liferay.portal.kernel.util.LoggingTimer; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.Validator; import java.util.ArrayList; import java.util.List; /** * @author Brian Wing Shun Chan * @author Gergely Mathe * @author Kenneth Chang */ public class VerifyLayout extends VerifyProcess { protected void deleteLinkedOrphanedLayouts() throws Exception { try (LoggingTimer loggingTimer = new LoggingTimer()) { StringBundler sb = new StringBundler(3); sb.append("delete from Layout where layoutPrototypeUuid != '' "); sb.append("and layoutPrototypeUuid not in (select uuid_ from "); sb.append("LayoutPrototype) and layoutPrototypeLinkEnabled = TRUE"); runSQL(sb.toString()); } } @Override protected void doVerify() throws Exception { deleteLinkedOrphanedLayouts(); updateUnlinkedOrphanedLayouts(); verifyFriendlyURL(); verifyLayoutIdFriendlyURL(); verifyLayoutPrototypeLinkEnabled(); verifyUuid(); } protected List<Layout> getInvalidLayoutIdFriendlyURLLayouts() throws Exception { final List<Layout> layouts = new ArrayList<>(); ActionableDynamicQuery actionableDynamicQuery = LayoutLocalServiceUtil.getActionableDynamicQuery(); actionableDynamicQuery.setPerformActionMethod( new ActionableDynamicQuery.PerformActionMethod<Layout>() { @Override public void performAction(Layout layout) { String friendlyURL = layout.getFriendlyURL(); friendlyURL = friendlyURL.substring(1); if (Validator.isNumber(friendlyURL) && !friendlyURL.equals( String.valueOf(layout.getLayoutId()))) { layouts.add(layout); } } }); actionableDynamicQuery.performActions(); return layouts; } protected void updateUnlinkedOrphanedLayouts() throws Exception { try (LoggingTimer loggingTimer = new LoggingTimer()) { StringBundler sb = new StringBundler(4); sb.append("update Layout set layoutPrototypeUuid = null where "); sb.append("layoutPrototypeUuid != '' and layoutPrototypeUuid not "); sb.append("in (select uuid_ from LayoutPrototype) and "); sb.append("layoutPrototypeLinkEnabled = FALSE"); runSQL(sb.toString()); } } protected void verifyFriendlyURL() throws Exception { try (LoggingTimer loggingTimer = new LoggingTimer()) { List<Layout> layouts = LayoutLocalServiceUtil.getNullFriendlyURLLayouts(); for (Layout layout : layouts) { List<LayoutFriendlyURL> layoutFriendlyURLs = LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs( layout.getPlid()); for (LayoutFriendlyURL layoutFriendlyURL : layoutFriendlyURLs) { String friendlyURL = StringPool.SLASH + layout.getLayoutId(); LayoutLocalServiceUtil.updateFriendlyURL( layout.getUserId(), layout.getPlid(), friendlyURL, layoutFriendlyURL.getLanguageId()); } } ActionableDynamicQuery actionableDynamicQuery = LayoutFriendlyURLLocalServiceUtil.getActionableDynamicQuery(); actionableDynamicQuery.setAddCriteriaMethod( new ActionableDynamicQuery.AddCriteriaMethod() { @Override public void addCriteria(DynamicQuery dynamicQuery) { DynamicQuery layoutDynamicQuery = LayoutLocalServiceUtil.dynamicQuery(); Projection projection = ProjectionFactoryUtil.property( "plid"); layoutDynamicQuery.setProjection(projection); Property plidProperty = PropertyFactoryUtil.forName( "plid"); dynamicQuery.add( plidProperty.notIn(layoutDynamicQuery)); } }); actionableDynamicQuery.setPerformActionMethod( new ActionableDynamicQuery. PerformActionMethod<LayoutFriendlyURL>() { @Override public void performAction( LayoutFriendlyURL layoutFriendlyURL) { LayoutFriendlyURLLocalServiceUtil. deleteLayoutFriendlyURL(layoutFriendlyURL); } }); actionableDynamicQuery.performActions(); } } protected void verifyLayoutIdFriendlyURL() throws Exception { try (LoggingTimer loggingTimer = new LoggingTimer()) { while (true) { List<Layout> layouts = getInvalidLayoutIdFriendlyURLLayouts(); if (layouts.isEmpty()) { break; } for (Layout layout : layouts) { if (verifyLayoutIdFriendlyURL(layout)) { continue; } } } } } protected boolean verifyLayoutIdFriendlyURL(Layout layout) throws Exception { String oldFriendlyURL = layout.getFriendlyURL(); String newFriendlyURL = StringPool.SLASH + layout.getLayoutId(); if (_log.isDebugEnabled()) { _log.debug( "Updating layout " + layout.getPlid() + " from friendly URL " + oldFriendlyURL + " to friendly URL " + newFriendlyURL); } List<LayoutFriendlyURL> layoutFriendlyURLs = LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs( layout.getPlid()); for (LayoutFriendlyURL layoutFriendlyURL : layoutFriendlyURLs) { if (!oldFriendlyURL.equals(layoutFriendlyURL.getFriendlyURL())) { continue; } try { layout = LayoutLocalServiceUtil.updateFriendlyURL( layout.getUserId(), layout.getPlid(), newFriendlyURL, layoutFriendlyURL.getLanguageId()); } catch (LayoutFriendlyURLException lfurle) { int type = lfurle.getType(); if (type == LayoutFriendlyURLException.DUPLICATE) { continue; } else { throw lfurle; } } } try { Layout duplicateLayout = LayoutLocalServiceUtil.fetchLayoutByFriendlyURL( layout.getGroupId(), layout.isPrivateLayout(), newFriendlyURL); if (duplicateLayout != null) { throw new LayoutFriendlyURLException( LayoutFriendlyURLException.DUPLICATE); } LayoutLocalServiceUtil.updateFriendlyURL( layout.getUserId(), layout.getPlid(), newFriendlyURL, LanguageUtil.getLanguageId(LocaleUtil.getSiteDefault())); } catch (LayoutFriendlyURLException lfurle) { int type = lfurle.getType(); if (type == LayoutFriendlyURLException.DUPLICATE) { return true; } else { throw lfurle; } } return false; } protected void verifyLayoutPrototypeLinkEnabled() throws Exception { try (LoggingTimer loggingTimer = new LoggingTimer()) { runSQL( "update Layout set layoutPrototypeLinkEnabled = [$FALSE$] " + "where type_ = 'link_to_layout' and " + "layoutPrototypeLinkEnabled = [$TRUE$]"); } } protected void verifyUuid() throws Exception { try (LoggingTimer loggingTimer = new LoggingTimer()) { verifyUuid("AssetEntry"); runSQL( "update Layout set uuid_ = sourcePrototypeLayoutUuid where " + "sourcePrototypeLayoutUuid != '' and uuid_ != " + "sourcePrototypeLayoutUuid"); } } protected void verifyUuid(String tableName) throws Exception { StringBundler sb = new StringBundler(12); sb.append("update "); sb.append(tableName); sb.append(" set layoutUuid = (select distinct "); sb.append("sourcePrototypeLayoutUuid from Layout where Layout.uuid_ "); sb.append("= "); sb.append(tableName); sb.append(".layoutUuid) where exists (select 1 from Layout where "); sb.append("Layout.uuid_ = "); sb.append(tableName); sb.append(".layoutUuid and Layout.uuid_ != "); sb.append("Layout.sourcePrototypeLayoutUuid and "); sb.append("Layout.sourcePrototypeLayoutUuid != '')"); runSQL(sb.toString()); } private static final Log _log = LogFactoryUtil.getLog(VerifyLayout.class); }