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.action;
016    
017    import com.liferay.portal.kernel.json.JSONFactoryUtil;
018    import com.liferay.portal.kernel.json.JSONObject;
019    import com.liferay.portal.kernel.servlet.BufferCacheServletResponse;
020    import com.liferay.portal.kernel.servlet.DynamicServletRequest;
021    import com.liferay.portal.kernel.servlet.ServletResponseUtil;
022    import com.liferay.portal.kernel.staging.StagingUtil;
023    import com.liferay.portal.kernel.util.Constants;
024    import com.liferay.portal.kernel.util.ContentTypes;
025    import com.liferay.portal.kernel.util.HttpUtil;
026    import com.liferay.portal.kernel.util.InstancePool;
027    import com.liferay.portal.kernel.util.ParamUtil;
028    import com.liferay.portal.kernel.util.PropertiesParamUtil;
029    import com.liferay.portal.kernel.util.StringBundler;
030    import com.liferay.portal.kernel.util.StringPool;
031    import com.liferay.portal.kernel.util.UnicodeProperties;
032    import com.liferay.portal.kernel.workflow.WorkflowConstants;
033    import com.liferay.portal.model.Layout;
034    import com.liferay.portal.model.LayoutRevision;
035    import com.liferay.portal.model.LayoutTypePortlet;
036    import com.liferay.portal.model.Portlet;
037    import com.liferay.portal.security.permission.ActionKeys;
038    import com.liferay.portal.security.permission.PermissionChecker;
039    import com.liferay.portal.service.LayoutRevisionLocalServiceUtil;
040    import com.liferay.portal.service.LayoutServiceUtil;
041    import com.liferay.portal.service.PortletLocalServiceUtil;
042    import com.liferay.portal.service.ServiceContext;
043    import com.liferay.portal.service.ServiceContextFactory;
044    import com.liferay.portal.service.permission.LayoutPermissionUtil;
045    import com.liferay.portal.servlet.NamespaceServletRequest;
046    import com.liferay.portal.struts.JSONAction;
047    import com.liferay.portal.theme.ThemeDisplay;
048    import com.liferay.portal.util.LayoutClone;
049    import com.liferay.portal.util.LayoutCloneFactory;
050    import com.liferay.portal.util.PortalUtil;
051    import com.liferay.portal.util.WebKeys;
052    import com.liferay.portlet.PortletPreferencesFactoryUtil;
053    
054    import java.util.LinkedHashSet;
055    import java.util.Set;
056    
057    import javax.portlet.PortletPreferences;
058    
059    import javax.servlet.http.HttpServletRequest;
060    import javax.servlet.http.HttpServletResponse;
061    
062    import org.apache.struts.action.Action;
063    import org.apache.struts.action.ActionForm;
064    import org.apache.struts.action.ActionMapping;
065    
066    /**
067     * @author Brian Wing Shun Chan
068     */
069    public class UpdateLayoutAction extends JSONAction {
070    
071            @Override
072            public String getJSON(
073                            ActionMapping mapping, ActionForm form, HttpServletRequest request,
074                            HttpServletResponse response)
075                    throws Exception {
076    
077                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
078                            WebKeys.THEME_DISPLAY);
079    
080                    long userId = themeDisplay.getUserId();
081    
082                    Layout layout = themeDisplay.getLayout();
083                    LayoutTypePortlet layoutTypePortlet =
084                            themeDisplay.getLayoutTypePortlet();
085    
086                    PermissionChecker permissionChecker =
087                            themeDisplay.getPermissionChecker();
088    
089                    String cmd = ParamUtil.getString(request, Constants.CMD);
090    
091                    String portletId = ParamUtil.getString(request, "p_p_id");
092    
093                    boolean updateLayout = true;
094    
095                    if (cmd.equals(Constants.ADD)) {
096                            String columnId = ParamUtil.getString(request, "p_p_col_id", null);
097                            int columnPos = ParamUtil.getInteger(request, "p_p_col_pos", -1);
098    
099                            portletId = layoutTypePortlet.addPortletId(
100                                    userId, portletId, columnId, columnPos);
101    
102                            if (layoutTypePortlet.isCustomizable() &&
103                                    layoutTypePortlet.isCustomizedView() &&
104                                    !layoutTypePortlet.isColumnDisabled(columnId)) {
105    
106                                    updateLayout = false;
107                            }
108                    }
109                    else if (cmd.equals(Constants.DELETE)) {
110                            if (layoutTypePortlet.hasPortletId(portletId)) {
111                                    layoutTypePortlet.removePortletId(userId, portletId);
112    
113                                    if (layoutTypePortlet.isCustomizable() &&
114                                            layoutTypePortlet.isCustomizedView()) {
115    
116                                            updateLayout = false;
117                                    }
118                            }
119                    }
120                    else if (cmd.equals("drag")) {
121                            if (LayoutPermissionUtil.contains(
122                                            permissionChecker, layout, ActionKeys.UPDATE)) {
123    
124                                    String height = ParamUtil.getString(request, "height");
125                                    String width = ParamUtil.getString(request, "width");
126                                    String top = ParamUtil.getString(request, "top");
127                                    String left = ParamUtil.getString(request, "left");
128    
129                                    PortletPreferences preferences =
130                                            PortletPreferencesFactoryUtil.getLayoutPortletSetup(
131                                                    layout, portletId);
132    
133                                    StringBundler sb = new StringBundler(12);
134    
135                                    sb.append("height=");
136                                    sb.append(height);
137                                    sb.append("\n");
138                                    sb.append("width=");
139                                    sb.append(width);
140                                    sb.append("\n");
141                                    sb.append("top=");
142                                    sb.append(top);
143                                    sb.append("\n");
144                                    sb.append("left=");
145                                    sb.append(left);
146                                    sb.append("\n");
147    
148                                    preferences.setValue("portlet-freeform-styles", sb.toString());
149    
150                                    preferences.store();
151                            }
152                    }
153                    else if (cmd.equals("minimize")) {
154                            boolean restore = ParamUtil.getBoolean(request, "p_p_restore");
155    
156                            if (restore) {
157                                    layoutTypePortlet.removeStateMinPortletId(portletId);
158                            }
159                            else {
160                                    layoutTypePortlet.addStateMinPortletId(portletId);
161                            }
162    
163                            updateLayout = false;
164                    }
165                    else if (cmd.equals("move")) {
166                            String columnId = ParamUtil.getString(request, "p_p_col_id");
167                            int columnPos = ParamUtil.getInteger(request, "p_p_col_pos");
168    
169                            layoutTypePortlet.movePortletId(
170                                    userId, portletId, columnId, columnPos);
171    
172                            if (layoutTypePortlet.isCustomizable() &&
173                                    layoutTypePortlet.isCustomizedView() &&
174                                    !layoutTypePortlet.isColumnDisabled(columnId)) {
175    
176                                    updateLayout = false;
177                            }
178                    }
179                    else if (cmd.equals("redo_layout_revision")) {
180                            long layoutRevisionId = ParamUtil.getLong(
181                                    request, "layoutRevisionId");
182                            long layoutSetBranchId = ParamUtil.getLong(
183                                    request, "layoutSetBranchId");
184    
185                            ServiceContext serviceContext = ServiceContextFactory.getInstance(
186                                    request);
187    
188                            LayoutRevisionLocalServiceUtil.updateStatus(
189                                    userId, layoutRevisionId, WorkflowConstants.STATUS_DRAFT,
190                                    serviceContext);
191    
192                            StagingUtil.setRecentLayoutRevisionId(
193                                    request, layoutSetBranchId, layout.getPlid(), layoutRevisionId);
194    
195                            updateLayout = false;
196                    }
197                    else if (cmd.equals("select_layout_revision")) {
198                            long layoutRevisionId = ParamUtil.getLong(
199                                    request, "layoutRevisionId");
200                            long layoutSetBranchId = ParamUtil.getLong(
201                                    request, "layoutSetBranchId");
202    
203                            StagingUtil.setRecentLayoutRevisionId(
204                                    request, layoutSetBranchId, layout.getPlid(), layoutRevisionId);
205    
206                            updateLayout = false;
207                    }
208                    else if (cmd.equals("toggle_customized_view")) {
209                            updateLayout = false;
210                    }
211                    else if (cmd.equals("update_type_settings")) {
212                            UnicodeProperties layoutTypeSettingsProperties =
213                                    layout.getTypeSettingsProperties();
214    
215                            UnicodeProperties formTypeSettingsProperties =
216                                    PropertiesParamUtil.getProperties(
217                                            request, "TypeSettingsProperties--");
218    
219                            layoutTypeSettingsProperties.putAll(formTypeSettingsProperties);
220                    }
221                    else if (cmd.equals("undo_layout_revision")) {
222                            long layoutRevisionId = ParamUtil.getLong(
223                                    request, "layoutRevisionId");
224                            long layoutSetBranchId = ParamUtil.getLong(
225                                    request, "layoutSetBranchId");
226    
227                            ServiceContext serviceContext = ServiceContextFactory.getInstance(
228                                    request);
229    
230                            LayoutRevision layoutRevision =
231                                    LayoutRevisionLocalServiceUtil.updateStatus(
232                                            userId, layoutRevisionId, WorkflowConstants.STATUS_INACTIVE,
233                                            serviceContext);
234    
235                            StagingUtil.setRecentLayoutRevisionId(
236                                    request, layoutSetBranchId, layout.getPlid(),
237                                    layoutRevision.getParentLayoutRevisionId());
238    
239                            updateLayout = false;
240                    }
241    
242                    if (updateLayout) {
243    
244                            // LEP-3648
245    
246                            layoutTypePortlet.resetModes();
247                            layoutTypePortlet.resetStates();
248    
249                            layout = LayoutServiceUtil.updateLayout(
250                                    layout.getGroupId(), layout.isPrivateLayout(),
251                                    layout.getLayoutId(), layout.getTypeSettings());
252                    }
253                    else {
254                            LayoutClone layoutClone = LayoutCloneFactory.getInstance();
255    
256                            if (layoutClone != null) {
257                                    layoutClone.update(
258                                            request, layout.getPlid(), layout.getTypeSettings());
259                            }
260                    }
261    
262                    if (cmd.equals(Constants.ADD) && (portletId != null)) {
263                            addPortlet(mapping, form, request, response, portletId);
264                    }
265    
266                    return StringPool.BLANK;
267            }
268    
269            protected void addPortlet(
270                            ActionMapping mapping, ActionForm form, HttpServletRequest request,
271                            HttpServletResponse response, String portletId)
272                    throws Exception {
273    
274                    // Run the render portlet action to add a portlet without refreshing.
275    
276                    Action renderPortletAction = (Action)InstancePool.get(
277                            RenderPortletAction.class.getName());
278    
279                    // Pass in the portlet id because the portlet id may be the instance id.
280                    // Namespace the request if necessary. See LEP-4644.
281    
282                    long companyId = PortalUtil.getCompanyId(request);
283    
284                    Portlet portlet = PortletLocalServiceUtil.getPortletById(
285                            companyId, portletId);
286    
287                    DynamicServletRequest dynamicRequest = null;
288    
289                    if (portlet.isPrivateRequestAttributes()) {
290                            String portletNamespace = PortalUtil.getPortletNamespace(
291                                    portlet.getPortletId());
292    
293                            dynamicRequest = new NamespaceServletRequest(
294                                    request, portletNamespace, portletNamespace);
295                    }
296                    else {
297                            dynamicRequest = new DynamicServletRequest(request);
298                    }
299    
300                    dynamicRequest.setParameter("p_p_id", portletId);
301    
302                    String dataType = ParamUtil.getString(request, "dataType");
303    
304                    if (dataType.equals("json")) {
305                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
306    
307                            BufferCacheServletResponse bufferCacheServletResponse =
308                                    new BufferCacheServletResponse(response);
309    
310                            renderPortletAction.execute(
311                                    mapping, form, dynamicRequest, bufferCacheServletResponse);
312    
313                            String portletHTML = bufferCacheServletResponse.getString();
314    
315                            portletHTML = portletHTML.trim();
316    
317                            populatePortletJSONObject(
318                                    request, portletHTML, portlet, jsonObject);
319    
320                            response.setContentType(ContentTypes.TEXT_JAVASCRIPT);
321    
322                            ServletResponseUtil.write(response, jsonObject.toString());
323                    }
324                    else {
325                            renderPortletAction.execute(
326                                    mapping, form, dynamicRequest, response);
327                    }
328            }
329    
330            protected String getRootPortletId(Portlet portlet) {
331    
332                    // Workaround for portlet.getRootPortletId() because that does not
333                    // return the proper root portlet ID for OpenSocial and WSRP portlets
334    
335                    Portlet rootPortlet = portlet.getRootPortlet();
336    
337                    return rootPortlet.getPortletId();
338            }
339    
340            protected void populatePortletJSONObject(
341                            HttpServletRequest request, String portletHTML, Portlet portlet,
342                            JSONObject jsonObject)
343                    throws Exception {
344    
345                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
346                            WebKeys.THEME_DISPLAY);
347    
348                    LayoutTypePortlet layoutTypePortlet =
349                            themeDisplay.getLayoutTypePortlet();
350    
351                    jsonObject.put("portletHTML", portletHTML);
352                    jsonObject.put("refresh", !portlet.isAjaxable());
353    
354                    Set<String> footerCssSet = new LinkedHashSet<String>();
355                    Set<String> footerJavaScriptSet = new LinkedHashSet<String>();
356                    Set<String> headerCssSet = new LinkedHashSet<String>();
357                    Set<String> headerJavaScriptSet = new LinkedHashSet<String>();
358    
359                    boolean portletOnLayout = false;
360    
361                    String rootPortletId = getRootPortletId(portlet);
362                    String portletId = portlet.getPortletId();
363    
364                    for (Portlet layoutPortlet : layoutTypePortlet.getAllPortlets()) {
365    
366                            // Check to see if an instance of this portlet is already in the
367                            // layout, but ignore the portlet that was just added
368    
369                            String layoutPortletRootPortletId = getRootPortletId(layoutPortlet);
370    
371                            if (rootPortletId.equals(layoutPortletRootPortletId) &&
372                                    !portletId.equals(layoutPortlet.getPortletId())) {
373    
374                                    portletOnLayout = true;
375    
376                                    break;
377                            }
378                    }
379    
380                    if (!portletOnLayout && portlet.isAjaxable()) {
381                            Portlet rootPortlet = portlet.getRootPortlet();
382    
383                            for (String footerPortalCss : portlet.getFooterPortalCss()) {
384                                    if (!HttpUtil.hasProtocol(footerPortalCss)) {
385                                            footerPortalCss =
386                                                    PortalUtil.getPathContext() + footerPortalCss;
387    
388                                            footerPortalCss = PortalUtil.getStaticResourceURL(
389                                                    request, footerPortalCss, rootPortlet.getTimestamp());
390                                    }
391    
392                                    footerCssSet.add(footerPortalCss);
393                            }
394    
395                            for (String footerPortalJavaScript :
396                                            portlet.getFooterPortalJavaScript()) {
397    
398                                    if (!HttpUtil.hasProtocol(footerPortalJavaScript)) {
399                                            footerPortalJavaScript =
400                                                    PortalUtil.getPathContext() + footerPortalJavaScript;
401    
402                                            footerPortalJavaScript = PortalUtil.getStaticResourceURL(
403                                                    request, footerPortalJavaScript,
404                                                    rootPortlet.getTimestamp());
405                                    }
406    
407                                    footerJavaScriptSet.add(footerPortalJavaScript);
408                            }
409    
410                            for (String footerPortletCss : portlet.getFooterPortletCss()) {
411                                    if (!HttpUtil.hasProtocol(footerPortletCss)) {
412                                            footerPortletCss =
413                                                    portlet.getStaticResourcePath() + footerPortletCss;
414    
415                                            footerPortletCss = PortalUtil.getStaticResourceURL(
416                                                    request, footerPortletCss, rootPortlet.getTimestamp());
417                                    }
418    
419                                    footerCssSet.add(footerPortletCss);
420                            }
421    
422                            for (String footerPortletJavaScript :
423                                            portlet.getFooterPortletJavaScript()) {
424    
425                                    if (!HttpUtil.hasProtocol(footerPortletJavaScript)) {
426                                            footerPortletJavaScript =
427                                                    portlet.getStaticResourcePath() +
428                                                            footerPortletJavaScript;
429    
430                                            footerPortletJavaScript = PortalUtil.getStaticResourceURL(
431                                                    request, footerPortletJavaScript,
432                                                    rootPortlet.getTimestamp());
433                                    }
434    
435                                    footerJavaScriptSet.add(footerPortletJavaScript);
436                            }
437    
438                            for (String headerPortalCss : portlet.getHeaderPortalCss()) {
439                                    if (!HttpUtil.hasProtocol(headerPortalCss)) {
440                                            headerPortalCss =
441                                                    PortalUtil.getPathContext() + headerPortalCss;
442    
443                                            headerPortalCss = PortalUtil.getStaticResourceURL(
444                                                    request, headerPortalCss, rootPortlet.getTimestamp());
445                                    }
446    
447                                    headerCssSet.add(headerPortalCss);
448                            }
449    
450                            for (String headerPortalJavaScript :
451                                            portlet.getHeaderPortalJavaScript()) {
452    
453                                    if (!HttpUtil.hasProtocol(headerPortalJavaScript)) {
454                                            headerPortalJavaScript =
455                                                    PortalUtil.getPathContext() + headerPortalJavaScript;
456    
457                                            headerPortalJavaScript = PortalUtil.getStaticResourceURL(
458                                                    request, headerPortalJavaScript,
459                                                    rootPortlet.getTimestamp());
460                                    }
461    
462                                    headerJavaScriptSet.add(headerPortalJavaScript);
463                            }
464    
465                            for (String headerPortletCss : portlet.getHeaderPortletCss()) {
466                                    if (!HttpUtil.hasProtocol(headerPortletCss)) {
467                                            headerPortletCss =
468                                                    portlet.getStaticResourcePath() + headerPortletCss;
469    
470                                            headerPortletCss = PortalUtil.getStaticResourceURL(
471                                                    request, headerPortletCss, rootPortlet.getTimestamp());
472                                    }
473    
474                                    headerCssSet.add(headerPortletCss);
475                            }
476    
477                            for (String headerPortletJavaScript :
478                                            portlet.getHeaderPortletJavaScript()) {
479    
480                                    if (!HttpUtil.hasProtocol(headerPortletJavaScript)) {
481                                            headerPortletJavaScript =
482                                                    portlet.getStaticResourcePath() +
483                                                            headerPortletJavaScript;
484    
485                                            headerPortletJavaScript = PortalUtil.getStaticResourceURL(
486                                                    request, headerPortletJavaScript,
487                                                    rootPortlet.getTimestamp());
488                                    }
489    
490                                    headerJavaScriptSet.add(headerPortletJavaScript);
491                            }
492                    }
493    
494                    String footerCssPaths = JSONFactoryUtil.serialize(
495                            footerCssSet.toArray(new String[footerCssSet.size()]));
496    
497                    jsonObject.put(
498                            "footerCssPaths", JSONFactoryUtil.createJSONArray(footerCssPaths));
499    
500                    String footerJavaScriptPaths = JSONFactoryUtil.serialize(
501                            footerJavaScriptSet.toArray(
502                                    new String[footerJavaScriptSet.size()]));
503    
504                    jsonObject.put(
505                            "footerJavaScriptPaths",
506                            JSONFactoryUtil.createJSONArray(footerJavaScriptPaths));
507    
508                    String headerCssPaths = JSONFactoryUtil.serialize(
509                            headerCssSet.toArray(new String[headerCssSet.size()]));
510    
511                    jsonObject.put(
512                            "headerCssPaths", JSONFactoryUtil.createJSONArray(headerCssPaths));
513    
514                    String headerJavaScriptPaths = JSONFactoryUtil.serialize(
515                            headerJavaScriptSet.toArray(
516                                    new String[headerJavaScriptSet.size()]));
517    
518                    jsonObject.put(
519                            "headerJavaScriptPaths",
520                            JSONFactoryUtil.createJSONArray(headerJavaScriptPaths));
521            }
522    
523    }