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