001    /**
002     * Copyright (c) 2000-2012 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.service.impl;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.staging.LayoutStagingUtil;
020    import com.liferay.portal.kernel.staging.MergeLayoutPrototypesThreadLocal;
021    import com.liferay.portal.kernel.staging.StagingUtil;
022    import com.liferay.portal.kernel.util.GetterUtil;
023    import com.liferay.portal.kernel.util.LocaleUtil;
024    import com.liferay.portal.kernel.util.ParamUtil;
025    import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
026    import com.liferay.portal.kernel.util.ProxyUtil;
027    import com.liferay.portal.kernel.util.StringPool;
028    import com.liferay.portal.kernel.workflow.WorkflowConstants;
029    import com.liferay.portal.model.Layout;
030    import com.liferay.portal.model.LayoutRevision;
031    import com.liferay.portal.model.LayoutSet;
032    import com.liferay.portal.model.LayoutStagingHandler;
033    import com.liferay.portal.model.User;
034    import com.liferay.portal.security.auth.PrincipalThreadLocal;
035    import com.liferay.portal.service.ServiceContext;
036    import com.liferay.portal.service.ServiceContextThreadLocal;
037    import com.liferay.portal.service.UserLocalServiceUtil;
038    import com.liferay.portlet.expando.model.ExpandoBridge;
039    
040    import java.lang.reflect.InvocationTargetException;
041    import java.lang.reflect.Method;
042    
043    import java.util.ArrayList;
044    import java.util.HashSet;
045    import java.util.List;
046    import java.util.Locale;
047    import java.util.Map;
048    import java.util.Set;
049    
050    import org.aopalliance.intercept.MethodInterceptor;
051    import org.aopalliance.intercept.MethodInvocation;
052    
053    import org.springframework.core.annotation.Order;
054    
055    /**
056     * @author Raymond Augé
057     * @author Brian Wing Shun Chan
058     */
059    @Order(1)
060    public class LayoutLocalServiceStagingAdvice
061            extends LayoutLocalServiceImpl implements MethodInterceptor {
062    
063            @Override
064            public void deleteLayout(
065                            Layout layout, boolean updateLayoutSet,
066                            ServiceContext serviceContext)
067                    throws PortalException, SystemException {
068    
069                    long layoutSetBranchId = ParamUtil.getLong(
070                            serviceContext, "layoutSetBranchId");
071    
072                    if (layoutSetBranchId > 0) {
073                            layoutRevisionLocalService.deleteLayoutRevisions(
074                                    layoutSetBranchId, layout.getPlid());
075    
076                            List<LayoutRevision> notIncompleteLayoutRevisions =
077                                    layoutRevisionPersistence.findByP_NotS(
078                                            layout.getPlid(), WorkflowConstants.STATUS_INCOMPLETE);
079    
080                            if (notIncompleteLayoutRevisions.isEmpty()) {
081                                    layoutRevisionLocalService.deleteLayoutLayoutRevisions(
082                                            layout.getPlid());
083    
084                                    super.deleteLayout(layout, updateLayoutSet, serviceContext);
085                            }
086                    }
087                    else {
088                            super.deleteLayout(layout, updateLayoutSet, serviceContext);
089                    }
090            }
091    
092            public Object invoke(MethodInvocation methodInvocation) throws Throwable {
093                    Method method = methodInvocation.getMethod();
094    
095                    String methodName = method.getName();
096    
097                    Object[] arguments = methodInvocation.getArguments();
098    
099                    boolean showIncomplete = false;
100    
101                    if (!_layoutLocalServiceStagingAdviceMethodNames.contains(methodName)) {
102                            return wrapReturnValue(methodInvocation.proceed(), showIncomplete);
103                    }
104    
105                    Object returnValue = null;
106    
107                    if (methodName.equals("deleteLayout") && (arguments.length == 3)) {
108                            deleteLayout(
109                                    (Layout)arguments[0], (Boolean)arguments[1],
110                                    (ServiceContext)arguments[2]);
111                    }
112                    else if (methodName.equals("getLayouts")) {
113                            if (arguments.length == 6) {
114                                    showIncomplete = (Boolean)arguments[3];
115                            }
116    
117                            return wrapReturnValue(methodInvocation.proceed(), showIncomplete);
118                    }
119                    else if (methodName.equals("updateLayout") &&
120                                     (arguments.length == 15)) {
121    
122                            returnValue = updateLayout(
123                                    (Long)arguments[0], (Boolean)arguments[1], (Long)arguments[2],
124                                    (Long)arguments[3], (Map<Locale, String>)arguments[4],
125                                    (Map<Locale, String>)arguments[5],
126                                    (Map<Locale, String>)arguments[6],
127                                    (Map<Locale, String>)arguments[7],
128                                    (Map<Locale, String>)arguments[8], (String)arguments[9],
129                                    (Boolean)arguments[10], (String)arguments[11],
130                                    (Boolean)arguments[12], (byte[])arguments[13],
131                                    (ServiceContext)arguments[14]);
132                    }
133                    else {
134                            try {
135                                    Class<?> clazz = getClass();
136    
137                                    Method localMethod = clazz.getMethod(
138                                            methodName, method.getParameterTypes());
139    
140                                    returnValue = localMethod.invoke(this, arguments);
141                            }
142                            catch (InvocationTargetException ite) {
143                                    throw ite.getTargetException();
144                            }
145                            catch (NoSuchMethodException nsme) {
146                                    throw new SystemException(nsme);
147                            }
148                    }
149    
150                    returnValue = wrapReturnValue(returnValue, showIncomplete);
151    
152                    return returnValue;
153            }
154    
155            @Override
156            public Layout updateLayout(
157                            long groupId, boolean privateLayout, long layoutId,
158                            long parentLayoutId, Map<Locale, String> nameMap,
159                            Map<Locale, String> titleMap, Map<Locale, String> descriptionMap,
160                            Map<Locale, String> keywordsMap, Map<Locale, String> robotsMap,
161                            String type, boolean hidden, String friendlyURL, Boolean iconImage,
162                            byte[] iconBytes, ServiceContext serviceContext)
163                    throws PortalException, SystemException {
164    
165                    // Layout
166    
167                    parentLayoutId = getParentLayoutId(
168                            groupId, privateLayout, parentLayoutId);
169                    String name = nameMap.get(LocaleUtil.getDefault());
170                    friendlyURL = getFriendlyURL(
171                            groupId, privateLayout, layoutId, StringPool.BLANK, friendlyURL);
172    
173                    validate(
174                            groupId, privateLayout, layoutId, parentLayoutId, name, type,
175                            hidden, friendlyURL);
176    
177                    validateParentLayoutId(
178                            groupId, privateLayout, layoutId, parentLayoutId);
179    
180                    Layout layout = layoutPersistence.findByG_P_L(
181                            groupId, privateLayout, layoutId);
182    
183                    LayoutRevision layoutRevision = LayoutStagingUtil.getLayoutRevision(
184                            layout);
185    
186                    if (layoutRevision == null) {
187                            return super.updateLayout(
188                                    groupId, privateLayout, layoutId, parentLayoutId, nameMap,
189                                    titleMap, descriptionMap, keywordsMap, robotsMap, type, hidden,
190                                    friendlyURL, iconImage, iconBytes, serviceContext);
191                    }
192    
193                    if (parentLayoutId != layout.getParentLayoutId()) {
194                            layout.setPriority(
195                                    getNextPriority(groupId, privateLayout, parentLayoutId));
196                    }
197    
198                    layout.setParentLayoutId(parentLayoutId);
199                    layoutRevision.setNameMap(nameMap);
200                    layoutRevision.setTitleMap(titleMap);
201                    layoutRevision.setDescriptionMap(descriptionMap);
202                    layoutRevision.setKeywordsMap(keywordsMap);
203                    layoutRevision.setRobotsMap(robotsMap);
204                    layout.setType(type);
205                    layout.setHidden(hidden);
206                    layout.setFriendlyURL(friendlyURL);
207    
208                    if (iconImage != null) {
209                            layout.setIconImage(iconImage.booleanValue());
210    
211                            if (iconImage.booleanValue()) {
212                                    long iconImageId = layout.getIconImageId();
213    
214                                    if (iconImageId <= 0) {
215                                            iconImageId = counterLocalService.increment();
216    
217                                            layout.setIconImageId(iconImageId);
218                                    }
219                            }
220                    }
221    
222                    layoutPersistence.update(layout, false);
223    
224                    serviceContext.setWorkflowAction(WorkflowConstants.ACTION_SAVE_DRAFT);
225    
226                    layoutRevisionLocalService.updateLayoutRevision(
227                            serviceContext.getUserId(), layoutRevision.getLayoutRevisionId(),
228                            layoutRevision.getLayoutBranchId(), layoutRevision.getName(),
229                            layoutRevision.getTitle(), layoutRevision.getDescription(),
230                            layoutRevision.getKeywords(), layoutRevision.getRobots(),
231                            layoutRevision.getTypeSettings(), layoutRevision.getIconImage(),
232                            layoutRevision.getIconImageId(), layoutRevision.getThemeId(),
233                            layoutRevision.getColorSchemeId(), layoutRevision.getWapThemeId(),
234                            layoutRevision.getWapColorSchemeId(), layoutRevision.getCss(),
235                            serviceContext);
236    
237                    // Icon
238    
239                    if (iconImage != null) {
240                            if ((iconBytes != null) && (iconBytes.length > 0)) {
241                                    imageLocalService.updateImage(
242                                            layout.getIconImageId(), iconBytes);
243                            }
244                    }
245    
246                    // Expando
247    
248                    ExpandoBridge expandoBridge = layout.getExpandoBridge();
249    
250                    expandoBridge.setAttributes(serviceContext);
251    
252                    return wrapLayout(layout);
253            }
254    
255            @Override
256            public Layout updateLayout(
257                            long groupId, boolean privateLayout, long layoutId,
258                            String typeSettings)
259                    throws PortalException, SystemException {
260    
261                    Layout layout = layoutPersistence.findByG_P_L(
262                            groupId, privateLayout, layoutId);
263    
264                    layout = wrapLayout(layout);
265    
266                    LayoutRevision layoutRevision = LayoutStagingUtil.getLayoutRevision(
267                            layout);
268    
269                    if (layoutRevision == null) {
270                            return super.updateLayout(
271                                    groupId, privateLayout, layoutId, typeSettings);
272                    }
273    
274                    layout.setTypeSettings(typeSettings);
275    
276                    ServiceContext serviceContext =
277                            ServiceContextThreadLocal.getServiceContext();
278    
279                    if (!MergeLayoutPrototypesThreadLocal.isInProgress()) {
280                            serviceContext.setWorkflowAction(
281                                    WorkflowConstants.ACTION_SAVE_DRAFT);
282                    }
283    
284                    layoutRevisionLocalService.updateLayoutRevision(
285                            serviceContext.getUserId(), layoutRevision.getLayoutRevisionId(),
286                            layoutRevision.getLayoutBranchId(), layoutRevision.getName(),
287                            layoutRevision.getTitle(), layoutRevision.getDescription(),
288                            layoutRevision.getKeywords(), layoutRevision.getRobots(),
289                            layoutRevision.getTypeSettings(), layoutRevision.getIconImage(),
290                            layoutRevision.getIconImageId(), layoutRevision.getThemeId(),
291                            layoutRevision.getColorSchemeId(), layoutRevision.getWapThemeId(),
292                            layoutRevision.getWapColorSchemeId(), layoutRevision.getCss(),
293                            serviceContext);
294    
295                    return layout;
296            }
297    
298            @Override
299            public Layout updateLookAndFeel(
300                            long groupId, boolean privateLayout, long layoutId, String themeId,
301                            String colorSchemeId, String css, boolean wapTheme)
302                    throws PortalException, SystemException {
303    
304                    Layout layout = layoutPersistence.findByG_P_L(
305                            groupId, privateLayout, layoutId);
306    
307                    layout = wrapLayout(layout);
308    
309                    LayoutRevision layoutRevision = LayoutStagingUtil.getLayoutRevision(
310                            layout);
311    
312                    if (layoutRevision == null) {
313                            return super.updateLookAndFeel(
314                                    groupId, privateLayout, layoutId, themeId, colorSchemeId, css,
315                                    wapTheme);
316                    }
317    
318                    if (wapTheme) {
319                            layout.setWapThemeId(themeId);
320                            layout.setWapColorSchemeId(colorSchemeId);
321                    }
322                    else {
323                            layout.setThemeId(themeId);
324                            layout.setColorSchemeId(colorSchemeId);
325                            layout.setCss(css);
326                    }
327    
328                    ServiceContext serviceContext =
329                            ServiceContextThreadLocal.getServiceContext();
330    
331                    if (!MergeLayoutPrototypesThreadLocal.isInProgress()) {
332                            serviceContext.setWorkflowAction(
333                                    WorkflowConstants.ACTION_SAVE_DRAFT);
334                    }
335    
336                    layoutRevisionLocalService.updateLayoutRevision(
337                            serviceContext.getUserId(), layoutRevision.getLayoutRevisionId(),
338                            layoutRevision.getLayoutBranchId(), layoutRevision.getName(),
339                            layoutRevision.getTitle(), layoutRevision.getDescription(),
340                            layoutRevision.getKeywords(), layoutRevision.getRobots(),
341                            layoutRevision.getTypeSettings(), layoutRevision.getIconImage(),
342                            layoutRevision.getIconImageId(), layoutRevision.getThemeId(),
343                            layoutRevision.getColorSchemeId(), layoutRevision.getWapThemeId(),
344                            layoutRevision.getWapColorSchemeId(), layoutRevision.getCss(),
345                            serviceContext);
346    
347                    return layout;
348            }
349    
350            @Override
351            public Layout updateName(Layout layout, String name, String languageId)
352                    throws PortalException, SystemException {
353    
354                    layout = wrapLayout(layout);
355    
356                    LayoutRevision layoutRevision = LayoutStagingUtil.getLayoutRevision(
357                            layout);
358    
359                    if (layoutRevision == null) {
360                            return super.updateName(layout, name, languageId);
361                    }
362    
363                    validateName(name, languageId);
364    
365                    layout.setName(name, LocaleUtil.fromLanguageId(languageId));
366    
367                    ServiceContext serviceContext =
368                            ServiceContextThreadLocal.getServiceContext();
369    
370                    serviceContext.setWorkflowAction(WorkflowConstants.ACTION_SAVE_DRAFT);
371    
372                    layoutRevisionLocalService.updateLayoutRevision(
373                            serviceContext.getUserId(), layoutRevision.getLayoutRevisionId(),
374                            layoutRevision.getLayoutBranchId(), layoutRevision.getName(),
375                            layoutRevision.getTitle(), layoutRevision.getDescription(),
376                            layoutRevision.getKeywords(), layoutRevision.getRobots(),
377                            layoutRevision.getTypeSettings(), layoutRevision.getIconImage(),
378                            layoutRevision.getIconImageId(), layoutRevision.getThemeId(),
379                            layoutRevision.getColorSchemeId(), layoutRevision.getWapThemeId(),
380                            layoutRevision.getWapColorSchemeId(), layoutRevision.getCss(),
381                            serviceContext);
382    
383                    return layout;
384            }
385    
386            protected Layout unwrapLayout(Layout layout) {
387                    LayoutStagingHandler layoutStagingHandler =
388                            LayoutStagingUtil.getLayoutStagingHandler(layout);
389    
390                    if (layoutStagingHandler == null) {
391                            return layout;
392                    }
393    
394                    return layoutStagingHandler.getLayout();
395            }
396    
397            protected Layout wrapLayout(Layout layout) {
398                    LayoutStagingHandler layoutStagingHandler =
399                            LayoutStagingUtil.getLayoutStagingHandler(layout);
400    
401                    if (layoutStagingHandler != null) {
402                            return layout;
403                    }
404    
405                    if (!LayoutStagingUtil.isBranchingLayout(layout)) {
406                            return layout;
407                    }
408    
409                    return (Layout)ProxyUtil.newProxyInstance(
410                            PortalClassLoaderUtil.getClassLoader(), new Class[] {Layout.class},
411                            new LayoutStagingHandler(layout));
412            }
413    
414            protected List<Layout> wrapLayouts(
415                    List<Layout> layouts, boolean showIncomplete) {
416    
417                    if (layouts.isEmpty()) {
418                            return layouts;
419                    }
420    
421                    Layout firstLayout = layouts.get(0);
422    
423                    Layout wrappedFirstLayout = wrapLayout(firstLayout);
424    
425                    if (wrappedFirstLayout == firstLayout) {
426                            return layouts;
427                    }
428    
429                    long layoutSetBranchId = 0;
430    
431                    if (!showIncomplete) {
432                            try {
433                                    long userId = GetterUtil.getLong(
434                                            PrincipalThreadLocal.getName());
435    
436                                    if (userId > 0) {
437                                            User user = UserLocalServiceUtil.getUser(userId);
438    
439                                            LayoutSet layoutSet = firstLayout.getLayoutSet();
440    
441                                            layoutSetBranchId = StagingUtil.getRecentLayoutSetBranchId(
442                                                    user, layoutSet.getLayoutSetId());
443                                    }
444                            }
445                            catch (Exception e) {
446                            }
447                    }
448    
449                    List<Layout> wrappedLayouts = new ArrayList<Layout>(layouts.size());
450    
451                    for (int i = 0; i < layouts.size(); i++) {
452                            Layout wrappedLayout = wrapLayout(layouts.get(i));
453    
454                            if (showIncomplete ||
455                                    !StagingUtil.isIncomplete(wrappedLayout, layoutSetBranchId)) {
456    
457                                    wrappedLayouts.add(wrappedLayout);
458                            }
459                    }
460    
461                    return wrappedLayouts;
462            }
463    
464            protected Object wrapReturnValue(
465                    Object returnValue, boolean showIncomplete) {
466    
467                    if (returnValue instanceof Layout) {
468                            returnValue = wrapLayout((Layout)returnValue);
469                    }
470                    else if (returnValue instanceof List<?>) {
471                            returnValue = wrapLayouts(
472                                    (List<Layout>)returnValue, showIncomplete);
473                    }
474    
475                    return returnValue;
476            }
477    
478            private static Set<String> _layoutLocalServiceStagingAdviceMethodNames =
479                    new HashSet<String>();
480    
481            static {
482                    _layoutLocalServiceStagingAdviceMethodNames.add("deleteLayout");
483                    _layoutLocalServiceStagingAdviceMethodNames.add("getLayouts");
484                    _layoutLocalServiceStagingAdviceMethodNames.add("updateLayout");
485                    _layoutLocalServiceStagingAdviceMethodNames.add("updateLookAndFeel");
486                    _layoutLocalServiceStagingAdviceMethodNames.add("updateName");
487            }
488    
489    }