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