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