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