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.model;
016    
017    import com.liferay.portal.NoSuchLayoutBranchException;
018    import com.liferay.portal.NoSuchLayoutRevisionException;
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.MergeLayoutPrototypesThreadLocal;
024    import com.liferay.portal.kernel.staging.StagingUtil;
025    import com.liferay.portal.kernel.util.ParamUtil;
026    import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
027    import com.liferay.portal.kernel.util.ProxyUtil;
028    import com.liferay.portal.kernel.util.ReflectionUtil;
029    import com.liferay.portal.kernel.workflow.WorkflowConstants;
030    import com.liferay.portal.service.LayoutBranchLocalServiceUtil;
031    import com.liferay.portal.service.LayoutRevisionLocalServiceUtil;
032    import com.liferay.portal.service.LayoutSetBranchLocalServiceUtil;
033    import com.liferay.portal.service.ServiceContext;
034    import com.liferay.portal.service.ServiceContextThreadLocal;
035    import com.liferay.portal.service.UserLocalServiceUtil;
036    import com.liferay.portal.util.LayoutTypePortletFactoryUtil;
037    
038    import java.io.Serializable;
039    
040    import java.lang.reflect.InvocationHandler;
041    import java.lang.reflect.InvocationTargetException;
042    import java.lang.reflect.Method;
043    
044    import java.util.HashSet;
045    import java.util.List;
046    import java.util.Set;
047    
048    /**
049     * @author Raymond Augé
050     * @author Brian Wing Shun Chan
051     */
052    public class LayoutStagingHandler implements InvocationHandler, Serializable {
053    
054            public LayoutStagingHandler(Layout layout) {
055                    this(layout, null);
056            }
057    
058            public Layout getLayout() {
059                    return _layout;
060            }
061    
062            public LayoutRevision getLayoutRevision() {
063                    return _layoutRevision;
064            }
065    
066            public Object invoke(Object proxy, Method method, Object[] arguments)
067                    throws Throwable {
068    
069                    try {
070                            if (_layoutRevision == null) {
071                                    return method.invoke(_layout, arguments);
072                            }
073    
074                            String methodName = method.getName();
075    
076                            if (methodName.equals("getLayoutType")) {
077                                    return _getLayoutType();
078                            }
079                            else if (methodName.equals("toEscapedModel")) {
080                                    if (_layout.isEscapedModel()) {
081                                            return this;
082                                    }
083    
084                                    return _toEscapedModel();
085                            }
086    
087                            if (methodName.equals("clone")) {
088                                    return _clone();
089                            }
090    
091                            Object bean = _layout;
092    
093                            if (_layoutRevisionMethodNames.contains(methodName)) {
094                                    try {
095                                            Class<?> layoutRevisionClass = _layoutRevision.getClass();
096    
097                                            method = layoutRevisionClass.getMethod(
098                                                    methodName,
099                                                    ReflectionUtil.getParameterTypes(arguments));
100    
101                                            bean = _layoutRevision;
102                                    }
103                                    catch (NoSuchMethodException nsme) {
104                                            _log.error(nsme, nsme);
105                                    }
106                            }
107    
108                            return method.invoke(bean, arguments);
109                    }
110                    catch (InvocationTargetException ite) {
111                            throw ite.getTargetException();
112                    }
113            }
114    
115            public void setLayoutRevision(LayoutRevision layoutRevision) {
116                    _layoutRevision = layoutRevision;
117            }
118    
119            private LayoutStagingHandler(Layout layout, LayoutRevision layoutRevision) {
120                    _layout = layout;
121    
122                    try {
123                            _layoutRevision = _getLayoutRevision(layout, layoutRevision);
124                    }
125                    catch (Exception e) {
126                            _log.error(e, e);
127    
128                            throw new IllegalStateException(e);
129                    }
130            }
131    
132            private Object _clone() {
133                    return ProxyUtil.newProxyInstance(
134                            PortalClassLoaderUtil.getClassLoader(), new Class[] {Layout.class},
135                            new LayoutStagingHandler(_layout, _layoutRevision));
136            }
137    
138            private LayoutRevision _getLayoutRevision(
139                            Layout layout, LayoutRevision layoutRevision)
140                    throws PortalException, SystemException {
141    
142                    if (layoutRevision != null) {
143                            return layoutRevision;
144                    }
145    
146                    ServiceContext serviceContext =
147                            ServiceContextThreadLocal.getServiceContext();
148    
149                    if (!serviceContext.isSignedIn()) {
150                            LayoutRevision lastLayoutRevision = null;
151    
152                            lastLayoutRevision =
153                                    LayoutRevisionLocalServiceUtil.fetchLastLayoutRevision(
154                                            layout.getPlid(), true);
155    
156                            if (lastLayoutRevision == null) {
157                                    lastLayoutRevision =
158                                            LayoutRevisionLocalServiceUtil.fetchLastLayoutRevision(
159                                                    layout.getPlid(), false);
160                            }
161    
162                            return lastLayoutRevision;
163                    }
164    
165                    long layoutSetBranchId = ParamUtil.getLong(
166                            serviceContext, "layoutSetBranchId");
167    
168                    LayoutSet layoutSet = layout.getLayoutSet();
169    
170                    LayoutSetBranch layoutSetBranch =
171                            LayoutSetBranchLocalServiceUtil.getUserLayoutSetBranch(
172                                    serviceContext.getUserId(), layout.getGroupId(),
173                                    layout.isPrivateLayout(), layoutSet.getLayoutSetId(),
174                                    layoutSetBranchId);
175    
176                    layoutSetBranchId = layoutSetBranch.getLayoutSetBranchId();
177    
178                    long layoutRevisionId = ParamUtil.getLong(
179                            serviceContext, "layoutRevisionId");
180    
181                    if (layoutSetBranchId > 0) {
182                            if (layoutRevisionId <= 0) {
183                                    User user = UserLocalServiceUtil.getUser(
184                                            serviceContext.getUserId());
185    
186                                    layoutRevisionId = StagingUtil.getRecentLayoutRevisionId(
187                                            user, layoutSetBranchId, layout.getPlid());
188    
189                                    if (layoutRevisionId > 0) {
190                                            try {
191                                                    layoutRevision =
192                                                            LayoutRevisionLocalServiceUtil.getLayoutRevision(
193                                                                    layoutRevisionId);
194    
195                                                    if (layoutRevision.getStatus() !=
196                                                                    WorkflowConstants.STATUS_INACTIVE) {
197    
198                                                            return layoutRevision;
199                                                    }
200    
201                                                    StagingUtil.setRecentLayoutRevisionId(
202                                                            user, layoutSetBranchId, layout.getPlid(),
203                                                            LayoutRevisionConstants.
204                                                                    DEFAULT_PARENT_LAYOUT_REVISION_ID);
205    
206                                                    layoutRevisionId =
207                                                            StagingUtil.getRecentLayoutRevisionId(
208                                                                    user, layoutSetBranchId, layout.getPlid());
209                                            }
210                                            catch (NoSuchLayoutRevisionException nslre) {
211                                            }
212                                    }
213                            }
214    
215                            if (layoutRevisionId > 0) {
216                                    try {
217                                            return LayoutRevisionLocalServiceUtil.getLayoutRevision(
218                                                    layoutRevisionId);
219                                    }
220                                    catch (NoSuchLayoutRevisionException nslre) {
221                                    }
222                            }
223    
224                            try {
225                                    return LayoutRevisionLocalServiceUtil.getLayoutRevision(
226                                            layoutSetBranchId, layout.getPlid(), true);
227                            }
228                            catch (NoSuchLayoutRevisionException nslre) {
229                                    List<LayoutRevision> layoutRevisions =
230                                            LayoutRevisionLocalServiceUtil.getChildLayoutRevisions(
231                                                    layoutSetBranchId,
232                                                    LayoutRevisionConstants.
233                                                            DEFAULT_PARENT_LAYOUT_REVISION_ID,
234                                                    layout.getPlid());
235    
236                                    if (!layoutRevisions.isEmpty()) {
237                                            return layoutRevisions.get(0);
238                                    }
239                            }
240                    }
241    
242                    LayoutBranch layoutBranch = null;
243    
244                    try {
245                            layoutBranch = LayoutBranchLocalServiceUtil.getMasterLayoutBranch(
246                                    layoutSetBranchId, layout.getPlid());
247                    }
248                    catch (NoSuchLayoutBranchException nslbe) {
249                            layoutBranch = LayoutBranchLocalServiceUtil.addLayoutBranch(
250                                    layoutSetBranchId, layout.getPlid(),
251                                    LayoutBranchConstants.MASTER_BRANCH_NAME,
252                                    LayoutBranchConstants.MASTER_BRANCH_DESCRIPTION, true,
253                                    serviceContext);
254                    }
255    
256                    if (!MergeLayoutPrototypesThreadLocal.isInProgress()) {
257                            serviceContext.setWorkflowAction(
258                                    WorkflowConstants.ACTION_SAVE_DRAFT);
259                    }
260    
261                    layoutRevision = LayoutRevisionLocalServiceUtil.addLayoutRevision(
262                            serviceContext.getUserId(), layoutSetBranchId,
263                            layoutBranch.getLayoutBranchId(),
264                            LayoutRevisionConstants.DEFAULT_PARENT_LAYOUT_REVISION_ID, false,
265                            layout.getPlid(), LayoutConstants.DEFAULT_PLID,
266                            layout.isPrivateLayout(), layout.getName(), layout.getTitle(),
267                            layout.getDescription(), layout.getKeywords(), layout.getRobots(),
268                            layout.getTypeSettings(), layout.getIconImage(),
269                            layout.getIconImageId(), layout.getThemeId(),
270                            layout.getColorSchemeId(), layout.getWapThemeId(),
271                            layout.getWapColorSchemeId(), layout.getCss(), serviceContext);
272    
273                    boolean explicitCreation = ParamUtil.getBoolean(
274                            serviceContext, "explicitCreation");
275    
276                    if (!explicitCreation) {
277                            LayoutRevisionLocalServiceUtil.updateStatus(
278                                    serviceContext.getUserId(),
279                                    layoutRevision.getLayoutRevisionId(),
280                                    WorkflowConstants.STATUS_INCOMPLETE, serviceContext);
281                    }
282    
283                    return layoutRevision;
284            }
285    
286            private LayoutType _getLayoutType() {
287                    return LayoutTypePortletFactoryUtil.create(
288                            (Layout)ProxyUtil.newProxyInstance(
289                                    PortalClassLoaderUtil.getClassLoader(),
290                                    new Class[] {Layout.class},
291                                    new LayoutStagingHandler(_layout, _layoutRevision)));
292            }
293    
294            private Object _toEscapedModel() {
295                    return ProxyUtil.newProxyInstance(
296                            PortalClassLoaderUtil.getClassLoader(), new Class[] {Layout.class},
297                            new LayoutStagingHandler(
298                                    _layout.toEscapedModel(), _layoutRevision.toEscapedModel()));
299            }
300    
301            private static Log _log = LogFactoryUtil.getLog(LayoutStagingHandler.class);
302    
303            private static Set<String> _layoutRevisionMethodNames =
304                    new HashSet<String>();
305    
306            static {
307                    _layoutRevisionMethodNames.add("getColorScheme");
308                    _layoutRevisionMethodNames.add("getColorSchemeId");
309                    _layoutRevisionMethodNames.add("getCss");
310                    _layoutRevisionMethodNames.add("getCssText");
311                    _layoutRevisionMethodNames.add("getDescription");
312                    _layoutRevisionMethodNames.add("getHTMLTitle");
313                    _layoutRevisionMethodNames.add("getIconImage");
314                    _layoutRevisionMethodNames.add("getIconImageId");
315                    _layoutRevisionMethodNames.add("getKeywords");
316                    _layoutRevisionMethodNames.add("getName");
317                    _layoutRevisionMethodNames.add("getRobots");
318                    _layoutRevisionMethodNames.add("getTheme");
319                    _layoutRevisionMethodNames.add("getThemeId");
320                    _layoutRevisionMethodNames.add("getTitle");
321                    _layoutRevisionMethodNames.add("getTypeSettings");
322                    _layoutRevisionMethodNames.add("getTypeSettingsProperties");
323                    _layoutRevisionMethodNames.add("getWapColorScheme");
324                    _layoutRevisionMethodNames.add("getWapColorSchemeId");
325                    _layoutRevisionMethodNames.add("getWapTheme");
326                    _layoutRevisionMethodNames.add("getWapThemeId");
327                    _layoutRevisionMethodNames.add("isEscapedModel");
328                    _layoutRevisionMethodNames.add("isIconImage");
329                    _layoutRevisionMethodNames.add("isInheritLookAndFeel");
330                    _layoutRevisionMethodNames.add("isInheritWapLookAndFeel");
331                    _layoutRevisionMethodNames.add("setColorSchemeId");
332                    _layoutRevisionMethodNames.add("setCss");
333                    _layoutRevisionMethodNames.add("setDescription");
334                    _layoutRevisionMethodNames.add("setDescriptionMap");
335                    _layoutRevisionMethodNames.add("setEscapedModel");
336                    _layoutRevisionMethodNames.add("setIconImage");
337                    _layoutRevisionMethodNames.add("setIconImageId");
338                    _layoutRevisionMethodNames.add("setKeywords");
339                    _layoutRevisionMethodNames.add("setKeywordsMap");
340                    _layoutRevisionMethodNames.add("setName");
341                    _layoutRevisionMethodNames.add("setNameMap");
342                    _layoutRevisionMethodNames.add("setRobots");
343                    _layoutRevisionMethodNames.add("setRobotsMap");
344                    _layoutRevisionMethodNames.add("setThemeId");
345                    _layoutRevisionMethodNames.add("setTitle");
346                    _layoutRevisionMethodNames.add("setTitleMap");
347                    _layoutRevisionMethodNames.add("setTypeSettings");
348                    _layoutRevisionMethodNames.add("setTypeSettingsProperties");
349                    _layoutRevisionMethodNames.add("setWapColorSchemeId");
350                    _layoutRevisionMethodNames.add("setWapThemeId");
351            }
352    
353            private Layout _layout;
354            private LayoutRevision _layoutRevision;
355    
356    }