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