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.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.DynamicServletRequest;
020    import com.liferay.portal.kernel.servlet.ServletResponseUtil;
021    import com.liferay.portal.kernel.servlet.StringServletResponse;
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.StringUtil;
032    import com.liferay.portal.kernel.util.UnicodeProperties;
033    import com.liferay.portal.kernel.workflow.WorkflowConstants;
034    import com.liferay.portal.model.Layout;
035    import com.liferay.portal.model.LayoutRevision;
036    import com.liferay.portal.model.LayoutTypePortlet;
037    import com.liferay.portal.model.Portlet;
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.List;
057    import java.util.Set;
058    
059    import javax.portlet.MimeResponse;
060    import javax.portlet.PortletPreferences;
061    
062    import javax.servlet.http.HttpServletRequest;
063    import javax.servlet.http.HttpServletResponse;
064    
065    import org.apache.struts.action.Action;
066    import org.apache.struts.action.ActionForm;
067    import org.apache.struts.action.ActionMapping;
068    
069    /**
070     * @author Brian Wing Shun Chan
071     */
072    public class UpdateLayoutAction extends JSONAction {
073    
074            @Override
075            public String getJSON(
076                            ActionMapping actionMapping, ActionForm actionForm,
077                            HttpServletRequest request, HttpServletResponse response)
078                    throws Exception {
079    
080                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
081                            WebKeys.THEME_DISPLAY);
082    
083                    long userId = themeDisplay.getUserId();
084    
085                    Layout layout = themeDisplay.getLayout();
086                    LayoutTypePortlet layoutTypePortlet =
087                            themeDisplay.getLayoutTypePortlet();
088    
089                    PermissionChecker permissionChecker =
090                            themeDisplay.getPermissionChecker();
091    
092                    String cmd = ParamUtil.getString(request, Constants.CMD);
093    
094                    String portletId = ParamUtil.getString(request, "p_p_id");
095    
096                    boolean updateLayout = true;
097    
098                    if (cmd.equals(Constants.ADD)) {
099                            String columnId = ParamUtil.getString(request, "p_p_col_id", null);
100                            int columnPos = ParamUtil.getInteger(request, "p_p_col_pos", -1);
101    
102                            portletId = layoutTypePortlet.addPortletId(
103                                    userId, portletId, columnId, columnPos);
104    
105                            if (layoutTypePortlet.isCustomizable() &&
106                                    layoutTypePortlet.isCustomizedView() &&
107                                    !layoutTypePortlet.isColumnDisabled(columnId)) {
108    
109                                    updateLayout = false;
110                            }
111                    }
112                    else if (cmd.equals(Constants.DELETE)) {
113                            if (layoutTypePortlet.hasPortletId(portletId)) {
114                                    layoutTypePortlet.removePortletId(userId, portletId);
115    
116                                    if (layoutTypePortlet.isCustomizable() &&
117                                            layoutTypePortlet.isCustomizedView()) {
118    
119                                            updateLayout = false;
120                                    }
121                            }
122                    }
123                    else if (cmd.equals("drag")) {
124                            if (LayoutPermissionUtil.contains(
125                                            permissionChecker, layout, ActionKeys.UPDATE)) {
126    
127                                    String height = ParamUtil.getString(request, "height");
128                                    String width = ParamUtil.getString(request, "width");
129                                    String top = ParamUtil.getString(request, "top");
130                                    String left = ParamUtil.getString(request, "left");
131    
132                                    PortletPreferences preferences =
133                                            PortletPreferencesFactoryUtil.getLayoutPortletSetup(
134                                                    layout, portletId);
135    
136                                    StringBundler sb = new StringBundler(12);
137    
138                                    sb.append("height=");
139                                    sb.append(height);
140                                    sb.append("\n");
141                                    sb.append("width=");
142                                    sb.append(width);
143                                    sb.append("\n");
144                                    sb.append("top=");
145                                    sb.append(top);
146                                    sb.append("\n");
147                                    sb.append("left=");
148                                    sb.append(left);
149                                    sb.append("\n");
150    
151                                    preferences.setValue("portlet-freeform-styles", sb.toString());
152    
153                                    preferences.store();
154                            }
155                    }
156                    else if (cmd.equals("minimize")) {
157                            boolean restore = ParamUtil.getBoolean(request, "p_p_restore");
158    
159                            if (restore) {
160                                    layoutTypePortlet.removeStateMinPortletId(portletId);
161                            }
162                            else {
163                                    layoutTypePortlet.addStateMinPortletId(portletId);
164                            }
165    
166                            updateLayout = false;
167                    }
168                    else if (cmd.equals("move")) {
169                            String columnId = ParamUtil.getString(request, "p_p_col_id");
170                            int columnPos = ParamUtil.getInteger(request, "p_p_col_pos");
171    
172                            layoutTypePortlet.movePortletId(
173                                    userId, portletId, columnId, columnPos);
174    
175                            if (layoutTypePortlet.isCustomizable() &&
176                                    layoutTypePortlet.isCustomizedView() &&
177                                    !layoutTypePortlet.isColumnDisabled(columnId)) {
178    
179                                    updateLayout = false;
180                            }
181                    }
182                    else if (cmd.equals("redo_layout_revision")) {
183                            long layoutRevisionId = ParamUtil.getLong(
184                                    request, "layoutRevisionId");
185                            long layoutSetBranchId = ParamUtil.getLong(
186                                    request, "layoutSetBranchId");
187    
188                            ServiceContext serviceContext = ServiceContextFactory.getInstance(
189                                    request);
190    
191                            LayoutRevisionLocalServiceUtil.updateStatus(
192                                    userId, layoutRevisionId, WorkflowConstants.STATUS_DRAFT,
193                                    serviceContext);
194    
195                            StagingUtil.setRecentLayoutRevisionId(
196                                    request, layoutSetBranchId, layout.getPlid(), layoutRevisionId);
197    
198                            updateLayout = false;
199                    }
200                    else if (cmd.equals("select_layout_revision")) {
201                            long layoutRevisionId = ParamUtil.getLong(
202                                    request, "layoutRevisionId");
203                            long layoutSetBranchId = ParamUtil.getLong(
204                                    request, "layoutSetBranchId");
205    
206                            StagingUtil.setRecentLayoutRevisionId(
207                                    request, layoutSetBranchId, layout.getPlid(), layoutRevisionId);
208    
209                            updateLayout = false;
210                    }
211                    else if (cmd.equals("toggle_customized_view")) {
212                            updateLayout = false;
213                    }
214                    else if (cmd.equals("update_type_settings")) {
215                            UnicodeProperties layoutTypeSettingsProperties =
216                                    layout.getTypeSettingsProperties();
217    
218                            UnicodeProperties formTypeSettingsProperties =
219                                    PropertiesParamUtil.getProperties(
220                                            request, "TypeSettingsProperties--");
221    
222                            layoutTypeSettingsProperties.putAll(formTypeSettingsProperties);
223                    }
224                    else if (cmd.equals("undo_layout_revision")) {
225                            long layoutRevisionId = ParamUtil.getLong(
226                                    request, "layoutRevisionId");
227                            long layoutSetBranchId = ParamUtil.getLong(
228                                    request, "layoutSetBranchId");
229    
230                            ServiceContext serviceContext = ServiceContextFactory.getInstance(
231                                    request);
232    
233                            LayoutRevision layoutRevision =
234                                    LayoutRevisionLocalServiceUtil.updateStatus(
235                                            userId, layoutRevisionId, WorkflowConstants.STATUS_INACTIVE,
236                                            serviceContext);
237    
238                            StagingUtil.setRecentLayoutRevisionId(
239                                    request, layoutSetBranchId, layout.getPlid(),
240                                    layoutRevision.getParentLayoutRevisionId());
241    
242                            updateLayout = false;
243                    }
244    
245                    if (updateLayout) {
246    
247                            // LEP-3648
248    
249                            layoutTypePortlet.resetModes();
250                            layoutTypePortlet.resetStates();
251    
252                            layout = LayoutServiceUtil.updateLayout(
253                                    layout.getGroupId(), layout.isPrivateLayout(),
254                                    layout.getLayoutId(), layout.getTypeSettings());
255                    }
256                    else {
257                            LayoutClone layoutClone = LayoutCloneFactory.getInstance();
258    
259                            if (layoutClone != null) {
260                                    layoutClone.update(
261                                            request, layout.getPlid(), layout.getTypeSettings());
262                            }
263                    }
264    
265                    if (cmd.equals(Constants.ADD) && (portletId != null)) {
266                            addPortlet(actionMapping, actionForm, request, response, portletId);
267                    }
268    
269                    return StringPool.BLANK;
270            }
271    
272            protected void addPortlet(
273                            ActionMapping actionMapping, ActionForm actionForm,
274                            HttpServletRequest request, HttpServletResponse response,
275                            String portletId)
276                    throws Exception {
277    
278                    // Run the render portlet action to add a portlet without refreshing.
279    
280                    Action renderPortletAction = (Action)InstancePool.get(
281                            RenderPortletAction.class.getName());
282    
283                    // Pass in the portlet id because the portlet id may be the instance id.
284                    // Namespace the request if necessary. See LEP-4644.
285    
286                    long companyId = PortalUtil.getCompanyId(request);
287    
288                    Portlet portlet = PortletLocalServiceUtil.getPortletById(
289                            companyId, portletId);
290    
291                    DynamicServletRequest dynamicRequest = null;
292    
293                    if (portlet.isPrivateRequestAttributes()) {
294                            String portletNamespace = PortalUtil.getPortletNamespace(
295                                    portlet.getPortletId());
296    
297                            dynamicRequest = new NamespaceServletRequest(
298                                    request, portletNamespace, portletNamespace);
299                    }
300                    else {
301                            dynamicRequest = new DynamicServletRequest(request);
302                    }
303    
304                    dynamicRequest.setParameter("p_p_id", portletId);
305    
306                    String dataType = ParamUtil.getString(request, "dataType");
307    
308                    if (dataType.equals("json")) {
309                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
310    
311                            StringServletResponse stringResponse = new StringServletResponse(
312                                    response);
313    
314                            renderPortletAction.execute(
315                                    actionMapping, actionForm, dynamicRequest, stringResponse);
316    
317                            populatePortletJSONObject(
318                                    request, stringResponse, portlet, jsonObject);
319    
320                            response.setContentType(ContentTypes.APPLICATION_JSON);
321    
322                            ServletResponseUtil.write(response, jsonObject.toString());
323                    }
324                    else {
325                            renderPortletAction.execute(
326                                    actionMapping, actionForm, 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, StringServletResponse stringResponse,
342                            Portlet portlet, 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("refresh", !portlet.isAjaxable());
352                    jsonObject.put("portletHTML", stringResponse.getString().trim());
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                    List<String> markupHeadElements = (List<String>)request.getAttribute(
523                            MimeResponse.MARKUP_HEAD_ELEMENT);
524    
525                    if (markupHeadElements != null) {
526                            jsonObject.put(
527                                    "markupHeadElements",
528                                    StringUtil.merge(markupHeadElements, StringPool.BLANK));
529                    }
530            }
531    
532    }