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