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.dao.orm.ActionableDynamicQuery;
018    import com.liferay.portal.kernel.dao.orm.DynamicQuery;
019    import com.liferay.portal.kernel.dao.orm.Projection;
020    import com.liferay.portal.kernel.dao.orm.ProjectionFactoryUtil;
021    import com.liferay.portal.kernel.dao.orm.Property;
022    import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil;
023    import com.liferay.portal.kernel.exception.LayoutFriendlyURLException;
024    import com.liferay.portal.kernel.language.LanguageUtil;
025    import com.liferay.portal.kernel.log.Log;
026    import com.liferay.portal.kernel.log.LogFactoryUtil;
027    import com.liferay.portal.kernel.model.Layout;
028    import com.liferay.portal.kernel.model.LayoutFriendlyURL;
029    import com.liferay.portal.kernel.service.LayoutFriendlyURLLocalServiceUtil;
030    import com.liferay.portal.kernel.service.LayoutLocalServiceUtil;
031    import com.liferay.portal.kernel.util.LocaleUtil;
032    import com.liferay.portal.kernel.util.LoggingTimer;
033    import com.liferay.portal.kernel.util.StringBundler;
034    import com.liferay.portal.kernel.util.StringPool;
035    import com.liferay.portal.kernel.util.Validator;
036    
037    import java.util.ArrayList;
038    import java.util.List;
039    
040    /**
041     * @author Brian Wing Shun Chan
042     * @author Gergely Mathe
043     * @author Kenneth Chang
044     */
045    public class VerifyLayout extends VerifyProcess {
046    
047            protected void deleteLinkedOrphanedLayouts() throws Exception {
048                    try (LoggingTimer loggingTimer = new LoggingTimer()) {
049                            StringBundler sb = new StringBundler(3);
050    
051                            sb.append("delete from Layout where layoutPrototypeUuid != '' ");
052                            sb.append("and layoutPrototypeUuid not in (select uuid_ from ");
053                            sb.append("LayoutPrototype) and layoutPrototypeLinkEnabled = TRUE");
054    
055                            runSQL(sb.toString());
056                    }
057            }
058    
059            @Override
060            protected void doVerify() throws Exception {
061                    deleteLinkedOrphanedLayouts();
062                    updateUnlinkedOrphanedLayouts();
063                    verifyFriendlyURL();
064                    verifyLayoutIdFriendlyURL();
065                    verifyLayoutPrototypeLinkEnabled();
066                    verifyUuid();
067            }
068    
069            protected List<Layout> getInvalidLayoutIdFriendlyURLLayouts()
070                    throws Exception {
071    
072                    final List<Layout> layouts = new ArrayList<>();
073    
074                    ActionableDynamicQuery actionableDynamicQuery =
075                            LayoutLocalServiceUtil.getActionableDynamicQuery();
076    
077                    actionableDynamicQuery.setPerformActionMethod(
078                            new ActionableDynamicQuery.PerformActionMethod<Layout>() {
079    
080                                    @Override
081                                    public void performAction(Layout layout) {
082                                            String friendlyURL = layout.getFriendlyURL();
083    
084                                            friendlyURL = friendlyURL.substring(1);
085    
086                                            if (Validator.isNumber(friendlyURL) &&
087                                                    !friendlyURL.equals(
088                                                            String.valueOf(layout.getLayoutId()))) {
089    
090                                                    layouts.add(layout);
091                                            }
092                                    }
093    
094                            });
095    
096                    actionableDynamicQuery.performActions();
097    
098                    return layouts;
099            }
100    
101            protected void updateUnlinkedOrphanedLayouts() throws Exception {
102                    try (LoggingTimer loggingTimer = new LoggingTimer()) {
103                            StringBundler sb = new StringBundler(4);
104    
105                            sb.append("update Layout set layoutPrototypeUuid = null where ");
106                            sb.append("layoutPrototypeUuid != '' and layoutPrototypeUuid not ");
107                            sb.append("in (select uuid_ from LayoutPrototype) and ");
108                            sb.append("layoutPrototypeLinkEnabled = FALSE");
109    
110                            runSQL(sb.toString());
111                    }
112            }
113    
114            protected void verifyFriendlyURL() throws Exception {
115                    try (LoggingTimer loggingTimer = new LoggingTimer()) {
116                            List<Layout> layouts =
117                                    LayoutLocalServiceUtil.getNullFriendlyURLLayouts();
118    
119                            for (Layout layout : layouts) {
120                                    List<LayoutFriendlyURL> layoutFriendlyURLs =
121                                            LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs(
122                                                    layout.getPlid());
123    
124                                    for (LayoutFriendlyURL layoutFriendlyURL : layoutFriendlyURLs) {
125                                            String friendlyURL =
126                                                    StringPool.SLASH + layout.getLayoutId();
127    
128                                            LayoutLocalServiceUtil.updateFriendlyURL(
129                                                    layout.getUserId(), layout.getPlid(), friendlyURL,
130                                                    layoutFriendlyURL.getLanguageId());
131                                    }
132                            }
133    
134                            ActionableDynamicQuery actionableDynamicQuery =
135                                    LayoutFriendlyURLLocalServiceUtil.getActionableDynamicQuery();
136    
137                            actionableDynamicQuery.setAddCriteriaMethod(
138                                    new ActionableDynamicQuery.AddCriteriaMethod() {
139    
140                                            @Override
141                                            public void addCriteria(DynamicQuery dynamicQuery) {
142                                                    DynamicQuery layoutDynamicQuery =
143                                                            LayoutLocalServiceUtil.dynamicQuery();
144    
145                                                    Projection projection = ProjectionFactoryUtil.property(
146                                                            "plid");
147    
148                                                    layoutDynamicQuery.setProjection(projection);
149    
150                                                    Property plidProperty = PropertyFactoryUtil.forName(
151                                                            "plid");
152    
153                                                    dynamicQuery.add(
154                                                            plidProperty.notIn(layoutDynamicQuery));
155                                            }
156    
157                                    });
158                            actionableDynamicQuery.setPerformActionMethod(
159                                    new ActionableDynamicQuery.
160                                            PerformActionMethod<LayoutFriendlyURL>() {
161    
162                                            @Override
163                                            public void performAction(
164                                                    LayoutFriendlyURL layoutFriendlyURL) {
165    
166                                                    LayoutFriendlyURLLocalServiceUtil.
167                                                            deleteLayoutFriendlyURL(layoutFriendlyURL);
168                                            }
169    
170                                    });
171    
172                            actionableDynamicQuery.performActions();
173                    }
174            }
175    
176            protected void verifyLayoutIdFriendlyURL() throws Exception {
177                    try (LoggingTimer loggingTimer = new LoggingTimer()) {
178                            while (true) {
179                                    List<Layout> layouts = getInvalidLayoutIdFriendlyURLLayouts();
180    
181                                    if (layouts.isEmpty()) {
182                                            break;
183                                    }
184    
185                                    for (Layout layout : layouts) {
186                                            if (verifyLayoutIdFriendlyURL(layout)) {
187                                                    continue;
188                                            }
189                                    }
190                            }
191                    }
192            }
193    
194            protected boolean verifyLayoutIdFriendlyURL(Layout layout)
195                    throws Exception {
196    
197                    String oldFriendlyURL = layout.getFriendlyURL();
198                    String newFriendlyURL = StringPool.SLASH + layout.getLayoutId();
199    
200                    if (_log.isDebugEnabled()) {
201                            _log.debug(
202                                    "Updating layout " + layout.getPlid() + " from friendly URL " +
203                                            oldFriendlyURL + " to friendly URL " + newFriendlyURL);
204                    }
205    
206                    List<LayoutFriendlyURL> layoutFriendlyURLs =
207                            LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs(
208                                    layout.getPlid());
209    
210                    for (LayoutFriendlyURL layoutFriendlyURL : layoutFriendlyURLs) {
211                            if (!oldFriendlyURL.equals(layoutFriendlyURL.getFriendlyURL())) {
212                                    continue;
213                            }
214    
215                            try {
216                                    layout = LayoutLocalServiceUtil.updateFriendlyURL(
217                                            layout.getUserId(), layout.getPlid(), newFriendlyURL,
218                                            layoutFriendlyURL.getLanguageId());
219                            }
220                            catch (LayoutFriendlyURLException lfurle) {
221                                    int type = lfurle.getType();
222    
223                                    if (type == LayoutFriendlyURLException.DUPLICATE) {
224                                            continue;
225                                    }
226                                    else {
227                                            throw lfurle;
228                                    }
229                            }
230                    }
231    
232                    try {
233                            Layout duplicateLayout =
234                                    LayoutLocalServiceUtil.fetchLayoutByFriendlyURL(
235                                            layout.getGroupId(), layout.isPrivateLayout(),
236                                            newFriendlyURL);
237    
238                            if (duplicateLayout != null) {
239                                    throw new LayoutFriendlyURLException(
240                                            LayoutFriendlyURLException.DUPLICATE);
241                            }
242    
243                            LayoutLocalServiceUtil.updateFriendlyURL(
244                                    layout.getUserId(), layout.getPlid(), newFriendlyURL,
245                                    LanguageUtil.getLanguageId(LocaleUtil.getSiteDefault()));
246                    }
247                    catch (LayoutFriendlyURLException lfurle) {
248                            int type = lfurle.getType();
249    
250                            if (type == LayoutFriendlyURLException.DUPLICATE) {
251                                    return true;
252                            }
253                            else {
254                                    throw lfurle;
255                            }
256                    }
257    
258                    return false;
259            }
260    
261            protected void verifyLayoutPrototypeLinkEnabled() throws Exception {
262                    try (LoggingTimer loggingTimer = new LoggingTimer()) {
263                            runSQL(
264                                    "update Layout set layoutPrototypeLinkEnabled = [$FALSE$] " +
265                                            "where type_ = 'link_to_layout' and " +
266                                                    "layoutPrototypeLinkEnabled = [$TRUE$]");
267                    }
268            }
269    
270            protected void verifyUuid() throws Exception {
271                    try (LoggingTimer loggingTimer = new LoggingTimer()) {
272                            verifyUuid("AssetEntry");
273    
274                            runSQL(
275                                    "update Layout set uuid_ = sourcePrototypeLayoutUuid where " +
276                                            "sourcePrototypeLayoutUuid != '' and uuid_ != " +
277                                                    "sourcePrototypeLayoutUuid");
278                    }
279            }
280    
281            protected void verifyUuid(String tableName) throws Exception {
282                    StringBundler sb = new StringBundler(12);
283    
284                    sb.append("update ");
285                    sb.append(tableName);
286                    sb.append(" set layoutUuid = (select distinct ");
287                    sb.append("sourcePrototypeLayoutUuid from Layout where Layout.uuid_ ");
288                    sb.append("= ");
289                    sb.append(tableName);
290                    sb.append(".layoutUuid) where exists (select 1 from Layout where ");
291                    sb.append("Layout.uuid_ = ");
292                    sb.append(tableName);
293                    sb.append(".layoutUuid and Layout.uuid_ != ");
294                    sb.append("Layout.sourcePrototypeLayoutUuid and ");
295                    sb.append("Layout.sourcePrototypeLayoutUuid != '')");
296    
297                    runSQL(sb.toString());
298            }
299    
300            private static final Log _log = LogFactoryUtil.getLog(VerifyLayout.class);
301    
302    }