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