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