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