001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.model;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.staging.MergeLayoutPrototypesThreadLocal;
022    import com.liferay.portal.kernel.staging.StagingUtil;
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.ReflectionUtil;
027    import com.liferay.portal.kernel.workflow.WorkflowConstants;
028    import com.liferay.portal.service.LayoutBranchLocalServiceUtil;
029    import com.liferay.portal.service.LayoutRevisionLocalServiceUtil;
030    import com.liferay.portal.service.LayoutSetBranchLocalServiceUtil;
031    import com.liferay.portal.service.ServiceContext;
032    import com.liferay.portal.service.ServiceContextThreadLocal;
033    import com.liferay.portal.service.UserLocalServiceUtil;
034    import com.liferay.portal.util.LayoutTypePortletFactoryUtil;
035    
036    import java.io.Serializable;
037    
038    import java.lang.reflect.InvocationHandler;
039    import java.lang.reflect.InvocationTargetException;
040    import java.lang.reflect.Method;
041    
042    import java.util.HashSet;
043    import java.util.Set;
044    
045    import javax.servlet.http.HttpServletRequest;
046    
047    /**
048     * @author Raymond Aug??
049     * @author Brian Wing Shun Chan
050     */
051    public class LayoutStagingHandler implements InvocationHandler, Serializable {
052    
053            public LayoutStagingHandler(Layout layout) {
054                    this(layout, null);
055            }
056    
057            public Layout getLayout() {
058                    return _layout;
059            }
060    
061            public LayoutRevision getLayoutRevision() {
062                    return _layoutRevision;
063            }
064    
065            @Override
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("getRegularURL")) {
080                                    Class<?> layoutRevisionClass = _layoutRevision.getClass();
081    
082                                    method = layoutRevisionClass.getMethod(
083                                            methodName, HttpServletRequest.class);
084    
085                                    return method.invoke(_layoutRevision, arguments);
086                            }
087                            else if (methodName.equals("toEscapedModel")) {
088                                    if (_layout.isEscapedModel()) {
089                                            return this;
090                                    }
091    
092                                    return _toEscapedModel();
093                            }
094    
095                            if (methodName.equals("clone")) {
096                                    return _clone();
097                            }
098    
099                            Object bean = _layout;
100    
101                            if (_layoutRevisionMethodNames.contains(methodName)) {
102                                    try {
103                                            Class<?> layoutRevisionClass = _layoutRevision.getClass();
104    
105                                            method = layoutRevisionClass.getMethod(
106                                                    methodName,
107                                                    ReflectionUtil.getParameterTypes(arguments));
108    
109                                            bean = _layoutRevision;
110                                    }
111                                    catch (NoSuchMethodException nsme) {
112                                            _log.error(nsme, nsme);
113                                    }
114                            }
115    
116                            return method.invoke(bean, arguments);
117                    }
118                    catch (InvocationTargetException ite) {
119                            throw ite.getTargetException();
120                    }
121            }
122    
123            public void setLayoutRevision(LayoutRevision layoutRevision) {
124                    _layoutRevision = layoutRevision;
125            }
126    
127            private LayoutStagingHandler(Layout layout, LayoutRevision layoutRevision) {
128                    _layout = layout;
129    
130                    try {
131                            _layoutRevision = _getLayoutRevision(layout, layoutRevision);
132                    }
133                    catch (Exception e) {
134                            _log.error(e, e);
135    
136                            throw new IllegalStateException(e);
137                    }
138            }
139    
140            private Object _clone() {
141                    return ProxyUtil.newProxyInstance(
142                            PortalClassLoaderUtil.getClassLoader(), new Class[] {Layout.class},
143                            new LayoutStagingHandler(_layout, _layoutRevision));
144            }
145    
146            private LayoutRevision _getLayoutRevision(
147                            Layout layout, LayoutRevision layoutRevision)
148                    throws PortalException, SystemException {
149    
150                    if (layoutRevision != null) {
151                            return layoutRevision;
152                    }
153    
154                    ServiceContext serviceContext =
155                            ServiceContextThreadLocal.getServiceContext();
156    
157                    if ((serviceContext == null) || !serviceContext.isSignedIn()) {
158                            LayoutRevision lastLayoutRevision = null;
159    
160                            lastLayoutRevision =
161                                    LayoutRevisionLocalServiceUtil.fetchLastLayoutRevision(
162                                            layout.getPlid(), true);
163    
164                            if (lastLayoutRevision == null) {
165                                    lastLayoutRevision =
166                                            LayoutRevisionLocalServiceUtil.fetchLastLayoutRevision(
167                                                    layout.getPlid(), false);
168                            }
169    
170                            return lastLayoutRevision;
171                    }
172    
173                    User user = UserLocalServiceUtil.getUser(serviceContext.getUserId());
174    
175                    long layoutSetBranchId = ParamUtil.getLong(
176                            serviceContext, "layoutSetBranchId");
177    
178                    LayoutSet layoutSet = layout.getLayoutSet();
179    
180                    LayoutSetBranch layoutSetBranch =
181                            LayoutSetBranchLocalServiceUtil.getUserLayoutSetBranch(
182                                    serviceContext.getUserId(), layout.getGroupId(),
183                                    layout.isPrivateLayout(), layoutSet.getLayoutSetId(),
184                                    layoutSetBranchId);
185    
186                    layoutSetBranchId = layoutSetBranch.getLayoutSetBranchId();
187    
188                    long layoutRevisionId = ParamUtil.getLong(
189                            serviceContext, "layoutRevisionId");
190    
191                    if (layoutRevisionId > 0) {
192                            layoutRevision =
193                                    LayoutRevisionLocalServiceUtil.fetchLayoutRevision(
194                                            layoutRevisionId);
195                    }
196    
197                    if ((layoutRevisionId <= 0) ||
198                            !_isBelongsToLayout(layoutRevision, layout)) {
199    
200                            layoutRevisionId = StagingUtil.getRecentLayoutRevisionId(
201                                    user, layoutSetBranchId, layout.getPlid());
202    
203                            layoutRevision =
204                                    LayoutRevisionLocalServiceUtil.fetchLayoutRevision(
205                                            layoutRevisionId);
206                    }
207    
208                    if ((layoutRevision != null) && !layoutRevision.isInactive()) {
209                            return layoutRevision;
210                    }
211    
212                    layoutRevision =
213                            LayoutRevisionLocalServiceUtil.fetchLatestLayoutRevision(
214                                    layoutSetBranchId, layout.getPlid());
215    
216                    if (layoutRevision != null) {
217                            StagingUtil.setRecentLayoutRevisionId(
218                                    user, layoutSetBranchId, layout.getPlid(),
219                                    layoutRevision.getLayoutRevisionId());
220    
221                            return layoutRevision;
222                    }
223    
224                    LayoutBranch layoutBranch =
225                            LayoutBranchLocalServiceUtil.getMasterLayoutBranch(
226                                    layoutSetBranchId, layout.getPlid(), serviceContext);
227    
228                    if (!MergeLayoutPrototypesThreadLocal.isInProgress()) {
229                            serviceContext.setWorkflowAction(
230                                    WorkflowConstants.ACTION_SAVE_DRAFT);
231                    }
232    
233                    layoutRevision = LayoutRevisionLocalServiceUtil.addLayoutRevision(
234                            serviceContext.getUserId(), layoutSetBranchId,
235                            layoutBranch.getLayoutBranchId(),
236                            LayoutRevisionConstants.DEFAULT_PARENT_LAYOUT_REVISION_ID, false,
237                            layout.getPlid(), LayoutConstants.DEFAULT_PLID,
238                            layout.isPrivateLayout(), layout.getName(), layout.getTitle(),
239                            layout.getDescription(), layout.getKeywords(), layout.getRobots(),
240                            layout.getTypeSettings(), layout.getIconImage(),
241                            layout.getIconImageId(), layout.getThemeId(),
242                            layout.getColorSchemeId(), layout.getWapThemeId(),
243                            layout.getWapColorSchemeId(), layout.getCss(), serviceContext);
244    
245                    boolean explicitCreation = ParamUtil.getBoolean(
246                            serviceContext, "explicitCreation");
247    
248                    if (!explicitCreation) {
249                            LayoutRevisionLocalServiceUtil.updateStatus(
250                                    serviceContext.getUserId(),
251                                    layoutRevision.getLayoutRevisionId(),
252                                    WorkflowConstants.STATUS_INCOMPLETE, serviceContext);
253                    }
254    
255                    return layoutRevision;
256            }
257    
258            private LayoutType _getLayoutType() {
259                    return LayoutTypePortletFactoryUtil.create(
260                            (Layout)ProxyUtil.newProxyInstance(
261                                    PortalClassLoaderUtil.getClassLoader(),
262                                    new Class[] {Layout.class},
263                                    new LayoutStagingHandler(_layout, _layoutRevision)));
264            }
265    
266            private boolean _isBelongsToLayout(
267                    LayoutRevision layoutRevision, Layout layout) {
268    
269                    if (layoutRevision == null) {
270                            return false;
271                    }
272    
273                    if (layoutRevision.getPlid() == layout.getPlid()) {
274                            return true;
275                    }
276    
277                    return false;
278            }
279    
280            private Object _toEscapedModel() {
281                    return ProxyUtil.newProxyInstance(
282                            PortalClassLoaderUtil.getClassLoader(), new Class[] {Layout.class},
283                            new LayoutStagingHandler(
284                                    _layout.toEscapedModel(), _layoutRevision.toEscapedModel()));
285            }
286    
287            private static Log _log = LogFactoryUtil.getLog(LayoutStagingHandler.class);
288    
289            private static Set<String> _layoutRevisionMethodNames =
290                    new HashSet<String>();
291    
292            static {
293                    _layoutRevisionMethodNames.add("getColorScheme");
294                    _layoutRevisionMethodNames.add("getColorSchemeId");
295                    _layoutRevisionMethodNames.add("getCss");
296                    _layoutRevisionMethodNames.add("getCssText");
297                    _layoutRevisionMethodNames.add("getDescription");
298                    _layoutRevisionMethodNames.add("getGroupId");
299                    _layoutRevisionMethodNames.add("getHTMLTitle");
300                    _layoutRevisionMethodNames.add("getIconImage");
301                    _layoutRevisionMethodNames.add("getIconImageId");
302                    _layoutRevisionMethodNames.add("getKeywords");
303                    _layoutRevisionMethodNames.add("getLayoutSet");
304                    _layoutRevisionMethodNames.add("getName");
305                    _layoutRevisionMethodNames.add("getRobots");
306                    _layoutRevisionMethodNames.add("getTheme");
307                    _layoutRevisionMethodNames.add("getThemeId");
308                    _layoutRevisionMethodNames.add("getThemeSetting");
309                    _layoutRevisionMethodNames.add("getTitle");
310                    _layoutRevisionMethodNames.add("getTypeSettings");
311                    _layoutRevisionMethodNames.add("getTypeSettingsProperties");
312                    _layoutRevisionMethodNames.add("getTypeSettingsProperty");
313                    _layoutRevisionMethodNames.add("getWapColorScheme");
314                    _layoutRevisionMethodNames.add("getWapColorSchemeId");
315                    _layoutRevisionMethodNames.add("getWapTheme");
316                    _layoutRevisionMethodNames.add("getWapThemeId");
317                    _layoutRevisionMethodNames.add("isContentDisplayPage");
318                    _layoutRevisionMethodNames.add("isEscapedModel");
319                    _layoutRevisionMethodNames.add("isIconImage");
320                    _layoutRevisionMethodNames.add("isInheritLookAndFeel");
321                    _layoutRevisionMethodNames.add("isInheritWapLookAndFeel");
322                    _layoutRevisionMethodNames.add("setColorSchemeId");
323                    _layoutRevisionMethodNames.add("setCss");
324                    _layoutRevisionMethodNames.add("setDescription");
325                    _layoutRevisionMethodNames.add("setDescriptionMap");
326                    _layoutRevisionMethodNames.add("setEscapedModel");
327                    _layoutRevisionMethodNames.add("setGroupId");
328                    _layoutRevisionMethodNames.add("setIconImage");
329                    _layoutRevisionMethodNames.add("setIconImageId");
330                    _layoutRevisionMethodNames.add("setKeywords");
331                    _layoutRevisionMethodNames.add("setKeywordsMap");
332                    _layoutRevisionMethodNames.add("setName");
333                    _layoutRevisionMethodNames.add("setNameMap");
334                    _layoutRevisionMethodNames.add("setRobots");
335                    _layoutRevisionMethodNames.add("setRobotsMap");
336                    _layoutRevisionMethodNames.add("setThemeId");
337                    _layoutRevisionMethodNames.add("setTitle");
338                    _layoutRevisionMethodNames.add("setTitleMap");
339                    _layoutRevisionMethodNames.add("setTypeSettings");
340                    _layoutRevisionMethodNames.add("setTypeSettingsProperties");
341                    _layoutRevisionMethodNames.add("setWapColorSchemeId");
342                    _layoutRevisionMethodNames.add("setWapThemeId");
343            }
344    
345            private Layout _layout;
346            private LayoutRevision _layoutRevision;
347    
348    }