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