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.dao.orm.QueryUtil;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.staging.MergeLayoutPrototypesThreadLocal;
023    import com.liferay.portal.kernel.staging.StagingUtil;
024    import com.liferay.portal.kernel.util.ParamUtil;
025    import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
026    import com.liferay.portal.kernel.util.ProxyUtil;
027    import com.liferay.portal.kernel.util.ReflectionUtil;
028    import com.liferay.portal.kernel.workflow.WorkflowConstants;
029    import com.liferay.portal.service.LayoutBranchLocalServiceUtil;
030    import com.liferay.portal.service.LayoutRevisionLocalServiceUtil;
031    import com.liferay.portal.service.LayoutSetBranchLocalServiceUtil;
032    import com.liferay.portal.service.ServiceContext;
033    import com.liferay.portal.service.ServiceContextThreadLocal;
034    import com.liferay.portal.service.UserLocalServiceUtil;
035    import com.liferay.portal.util.LayoutTypePortletFactoryUtil;
036    import com.liferay.portal.util.comparator.LayoutRevisionCreateDateComparator;
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            @Override
067            public Object invoke(Object proxy, Method method, Object[] arguments)
068                    throws Throwable {
069    
070                    try {
071                            if (_layoutRevision == null) {
072                                    return method.invoke(_layout, arguments);
073                            }
074    
075                            String methodName = method.getName();
076    
077                            if (methodName.equals("getLayoutType")) {
078                                    return _getLayoutType();
079                            }
080                            else if (methodName.equals("toEscapedModel")) {
081                                    if (_layout.isEscapedModel()) {
082                                            return this;
083                                    }
084    
085                                    return _toEscapedModel();
086                            }
087    
088                            if (methodName.equals("clone")) {
089                                    return _clone();
090                            }
091    
092                            Object bean = _layout;
093    
094                            if (_layoutRevisionMethodNames.contains(methodName)) {
095                                    try {
096                                            Class<?> layoutRevisionClass = _layoutRevision.getClass();
097    
098                                            method = layoutRevisionClass.getMethod(
099                                                    methodName,
100                                                    ReflectionUtil.getParameterTypes(arguments));
101    
102                                            bean = _layoutRevision;
103                                    }
104                                    catch (NoSuchMethodException nsme) {
105                                            _log.error(nsme, nsme);
106                                    }
107                            }
108    
109                            return method.invoke(bean, arguments);
110                    }
111                    catch (InvocationTargetException ite) {
112                            throw ite.getTargetException();
113                    }
114            }
115    
116            public void setLayoutRevision(LayoutRevision layoutRevision) {
117                    _layoutRevision = layoutRevision;
118            }
119    
120            private LayoutStagingHandler(Layout layout, LayoutRevision layoutRevision) {
121                    _layout = layout;
122    
123                    try {
124                            _layoutRevision = _getLayoutRevision(layout, layoutRevision);
125                    }
126                    catch (Exception e) {
127                            _log.error(e, e);
128    
129                            throw new IllegalStateException(e);
130                    }
131            }
132    
133            private Object _clone() {
134                    return ProxyUtil.newProxyInstance(
135                            PortalClassLoaderUtil.getClassLoader(), new Class[] {Layout.class},
136                            new LayoutStagingHandler(_layout, _layoutRevision));
137            }
138    
139            private LayoutRevision _getLayoutRevision(
140                            Layout layout, LayoutRevision layoutRevision)
141                    throws PortalException, SystemException {
142    
143                    if (layoutRevision != null) {
144                            return layoutRevision;
145                    }
146    
147                    ServiceContext serviceContext =
148                            ServiceContextThreadLocal.getServiceContext();
149    
150                    if (!serviceContext.isSignedIn()) {
151                            LayoutRevision lastLayoutRevision = null;
152    
153                            lastLayoutRevision =
154                                    LayoutRevisionLocalServiceUtil.fetchLastLayoutRevision(
155                                            layout.getPlid(), true);
156    
157                            if (lastLayoutRevision == null) {
158                                    lastLayoutRevision =
159                                            LayoutRevisionLocalServiceUtil.fetchLastLayoutRevision(
160                                                    layout.getPlid(), false);
161                            }
162    
163                            return lastLayoutRevision;
164                    }
165    
166                    User user = UserLocalServiceUtil.getUser(serviceContext.getUserId());
167    
168                    long layoutSetBranchId = ParamUtil.getLong(
169                            serviceContext, "layoutSetBranchId");
170    
171                    LayoutSet layoutSet = layout.getLayoutSet();
172    
173                    LayoutSetBranch layoutSetBranch =
174                            LayoutSetBranchLocalServiceUtil.getUserLayoutSetBranch(
175                                    serviceContext.getUserId(), layout.getGroupId(),
176                                    layout.isPrivateLayout(), layoutSet.getLayoutSetId(),
177                                    layoutSetBranchId);
178    
179                    layoutSetBranchId = layoutSetBranch.getLayoutSetBranchId();
180    
181                    long layoutRevisionId = ParamUtil.getLong(
182                            serviceContext, "layoutRevisionId");
183    
184                    if (layoutRevisionId <= 0) {
185                            layoutRevisionId = StagingUtil.getRecentLayoutRevisionId(
186                                    user, layoutSetBranchId, layout.getPlid());
187                    }
188    
189                    if (layoutRevisionId > 0) {
190                            layoutRevision =
191                                    LayoutRevisionLocalServiceUtil.fetchLayoutRevision(
192                                            layoutRevisionId);
193    
194                            if (layoutRevision.getStatus() !=
195                                            WorkflowConstants.STATUS_INACTIVE) {
196    
197                                    return layoutRevision;
198                            }
199    
200                            layoutRevision = null;
201                    }
202    
203                    List<LayoutRevision> layoutRevisions =
204                            LayoutRevisionLocalServiceUtil.getLayoutRevisions(
205                                    layoutSetBranchId, layout.getPlid(), QueryUtil.ALL_POS,
206                                    QueryUtil.ALL_POS,
207                                    new LayoutRevisionCreateDateComparator(true));
208    
209                    if (!layoutRevisions.isEmpty()) {
210                            layoutRevision = layoutRevisions.get(0);
211    
212                            for (LayoutRevision curLayoutRevision : layoutRevisions) {
213                                    if (curLayoutRevision.isHead()) {
214                                            layoutRevision = curLayoutRevision;
215    
216                                            break;
217                                    }
218                            }
219                    }
220    
221                    if (layoutRevision != null) {
222                            StagingUtil.setRecentLayoutRevisionId(
223                                    user, layoutSetBranchId, layout.getPlid(),
224                                    layoutRevision.getLayoutRevisionId());
225    
226                            return layoutRevision;
227                    }
228    
229                    LayoutBranch layoutBranch =
230                            LayoutBranchLocalServiceUtil.getMasterLayoutBranch(
231                                    layoutSetBranchId, layout.getPlid(), serviceContext);
232    
233                    if (!MergeLayoutPrototypesThreadLocal.isInProgress()) {
234                            serviceContext.setWorkflowAction(
235                                    WorkflowConstants.ACTION_SAVE_DRAFT);
236                    }
237    
238                    return LayoutRevisionLocalServiceUtil.addLayoutRevision(
239                            serviceContext.getUserId(), layoutSetBranchId,
240                            layoutBranch.getLayoutBranchId(),
241                            LayoutRevisionConstants.DEFAULT_PARENT_LAYOUT_REVISION_ID, false,
242                            layout.getPlid(), LayoutConstants.DEFAULT_PLID,
243                            layout.isPrivateLayout(), layout.getName(), layout.getTitle(),
244                            layout.getDescription(), layout.getKeywords(), layout.getRobots(),
245                            layout.getTypeSettings(), layout.getIconImage(),
246                            layout.getIconImageId(), layout.getThemeId(),
247                            layout.getColorSchemeId(), layout.getWapThemeId(),
248                            layout.getWapColorSchemeId(), layout.getCss(), serviceContext);
249            }
250    
251            private LayoutType _getLayoutType() {
252                    return LayoutTypePortletFactoryUtil.create(
253                            (Layout)ProxyUtil.newProxyInstance(
254                                    PortalClassLoaderUtil.getClassLoader(),
255                                    new Class[] {Layout.class},
256                                    new LayoutStagingHandler(_layout, _layoutRevision)));
257            }
258    
259            private Object _toEscapedModel() {
260                    return ProxyUtil.newProxyInstance(
261                            PortalClassLoaderUtil.getClassLoader(), new Class[] {Layout.class},
262                            new LayoutStagingHandler(
263                                    _layout.toEscapedModel(), _layoutRevision.toEscapedModel()));
264            }
265    
266            private static Log _log = LogFactoryUtil.getLog(LayoutStagingHandler.class);
267    
268            private static Set<String> _layoutRevisionMethodNames =
269                    new HashSet<String>();
270    
271            static {
272                    _layoutRevisionMethodNames.add("getColorScheme");
273                    _layoutRevisionMethodNames.add("getColorSchemeId");
274                    _layoutRevisionMethodNames.add("getCss");
275                    _layoutRevisionMethodNames.add("getCssText");
276                    _layoutRevisionMethodNames.add("getDescription");
277                    _layoutRevisionMethodNames.add("getHTMLTitle");
278                    _layoutRevisionMethodNames.add("getIconImage");
279                    _layoutRevisionMethodNames.add("getIconImageId");
280                    _layoutRevisionMethodNames.add("getKeywords");
281                    _layoutRevisionMethodNames.add("getName");
282                    _layoutRevisionMethodNames.add("getRobots");
283                    _layoutRevisionMethodNames.add("getTheme");
284                    _layoutRevisionMethodNames.add("getThemeId");
285                    _layoutRevisionMethodNames.add("getTitle");
286                    _layoutRevisionMethodNames.add("getTypeSettings");
287                    _layoutRevisionMethodNames.add("getTypeSettingsProperties");
288                    _layoutRevisionMethodNames.add("getWapColorScheme");
289                    _layoutRevisionMethodNames.add("getWapColorSchemeId");
290                    _layoutRevisionMethodNames.add("getWapTheme");
291                    _layoutRevisionMethodNames.add("getWapThemeId");
292                    _layoutRevisionMethodNames.add("isEscapedModel");
293                    _layoutRevisionMethodNames.add("isIconImage");
294                    _layoutRevisionMethodNames.add("isInheritLookAndFeel");
295                    _layoutRevisionMethodNames.add("isInheritWapLookAndFeel");
296                    _layoutRevisionMethodNames.add("setColorSchemeId");
297                    _layoutRevisionMethodNames.add("setCss");
298                    _layoutRevisionMethodNames.add("setDescription");
299                    _layoutRevisionMethodNames.add("setDescriptionMap");
300                    _layoutRevisionMethodNames.add("setEscapedModel");
301                    _layoutRevisionMethodNames.add("setIconImage");
302                    _layoutRevisionMethodNames.add("setIconImageId");
303                    _layoutRevisionMethodNames.add("setKeywords");
304                    _layoutRevisionMethodNames.add("setKeywordsMap");
305                    _layoutRevisionMethodNames.add("setName");
306                    _layoutRevisionMethodNames.add("setNameMap");
307                    _layoutRevisionMethodNames.add("setRobots");
308                    _layoutRevisionMethodNames.add("setRobotsMap");
309                    _layoutRevisionMethodNames.add("setThemeId");
310                    _layoutRevisionMethodNames.add("setTitle");
311                    _layoutRevisionMethodNames.add("setTitleMap");
312                    _layoutRevisionMethodNames.add("setTypeSettings");
313                    _layoutRevisionMethodNames.add("setTypeSettingsProperties");
314                    _layoutRevisionMethodNames.add("setWapColorSchemeId");
315                    _layoutRevisionMethodNames.add("setWapThemeId");
316            }
317    
318            private Layout _layout;
319            private LayoutRevision _layoutRevision;
320    
321    }