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.portlet.layoutsadmin.action;
016    
017    import com.liferay.portal.ImageTypeException;
018    import com.liferay.portal.LayoutFriendlyURLException;
019    import com.liferay.portal.LayoutNameException;
020    import com.liferay.portal.LayoutParentLayoutIdException;
021    import com.liferay.portal.LayoutSetVirtualHostException;
022    import com.liferay.portal.LayoutTypeException;
023    import com.liferay.portal.NoSuchGroupException;
024    import com.liferay.portal.NoSuchLayoutException;
025    import com.liferay.portal.RequiredLayoutException;
026    import com.liferay.portal.SitemapChangeFrequencyException;
027    import com.liferay.portal.SitemapIncludeException;
028    import com.liferay.portal.SitemapPagePriorityException;
029    import com.liferay.portal.events.EventsProcessorUtil;
030    import com.liferay.portal.kernel.exception.PortalException;
031    import com.liferay.portal.kernel.exception.SystemException;
032    import com.liferay.portal.kernel.log.Log;
033    import com.liferay.portal.kernel.log.LogFactoryUtil;
034    import com.liferay.portal.kernel.servlet.SessionErrors;
035    import com.liferay.portal.kernel.servlet.SessionMessages;
036    import com.liferay.portal.kernel.staging.StagingUtil;
037    import com.liferay.portal.kernel.upload.UploadException;
038    import com.liferay.portal.kernel.upload.UploadPortletRequest;
039    import com.liferay.portal.kernel.util.Constants;
040    import com.liferay.portal.kernel.util.FileUtil;
041    import com.liferay.portal.kernel.util.HttpUtil;
042    import com.liferay.portal.kernel.util.LocalizationUtil;
043    import com.liferay.portal.kernel.util.ParamUtil;
044    import com.liferay.portal.kernel.util.PropertiesParamUtil;
045    import com.liferay.portal.kernel.util.PropsKeys;
046    import com.liferay.portal.kernel.util.StringPool;
047    import com.liferay.portal.kernel.util.StringUtil;
048    import com.liferay.portal.kernel.util.ThemeFactoryUtil;
049    import com.liferay.portal.kernel.util.UnicodeProperties;
050    import com.liferay.portal.kernel.util.Validator;
051    import com.liferay.portal.kernel.workflow.WorkflowConstants;
052    import com.liferay.portal.model.ColorScheme;
053    import com.liferay.portal.model.Group;
054    import com.liferay.portal.model.Layout;
055    import com.liferay.portal.model.LayoutConstants;
056    import com.liferay.portal.model.LayoutPrototype;
057    import com.liferay.portal.model.LayoutRevision;
058    import com.liferay.portal.model.LayoutSet;
059    import com.liferay.portal.model.LayoutSetBranch;
060    import com.liferay.portal.model.LayoutTypePortlet;
061    import com.liferay.portal.model.Theme;
062    import com.liferay.portal.model.ThemeSetting;
063    import com.liferay.portal.model.User;
064    import com.liferay.portal.model.impl.ThemeSettingImpl;
065    import com.liferay.portal.security.auth.PrincipalException;
066    import com.liferay.portal.security.permission.ActionKeys;
067    import com.liferay.portal.security.permission.PermissionChecker;
068    import com.liferay.portal.service.LayoutLocalServiceUtil;
069    import com.liferay.portal.service.LayoutPrototypeLocalServiceUtil;
070    import com.liferay.portal.service.LayoutPrototypeServiceUtil;
071    import com.liferay.portal.service.LayoutRevisionLocalServiceUtil;
072    import com.liferay.portal.service.LayoutServiceUtil;
073    import com.liferay.portal.service.LayoutSetBranchLocalServiceUtil;
074    import com.liferay.portal.service.LayoutSetLocalServiceUtil;
075    import com.liferay.portal.service.PortletLocalServiceUtil;
076    import com.liferay.portal.service.ServiceContext;
077    import com.liferay.portal.service.ServiceContextFactory;
078    import com.liferay.portal.service.ThemeLocalServiceUtil;
079    import com.liferay.portal.service.UserLocalServiceUtil;
080    import com.liferay.portal.service.permission.GroupPermissionUtil;
081    import com.liferay.portal.service.permission.LayoutPermissionUtil;
082    import com.liferay.portal.service.permission.LayoutPrototypePermissionUtil;
083    import com.liferay.portal.service.permission.LayoutSetPrototypePermissionUtil;
084    import com.liferay.portal.service.permission.UserPermissionUtil;
085    import com.liferay.portal.struts.PortletAction;
086    import com.liferay.portal.theme.ThemeDisplay;
087    import com.liferay.portal.util.LayoutSettings;
088    import com.liferay.portal.util.PortalUtil;
089    import com.liferay.portal.util.PropsValues;
090    import com.liferay.portal.util.WebKeys;
091    import com.liferay.portlet.mobiledevicerules.model.MDRAction;
092    import com.liferay.portlet.mobiledevicerules.model.MDRRuleGroupInstance;
093    import com.liferay.portlet.mobiledevicerules.service.MDRActionLocalServiceUtil;
094    import com.liferay.portlet.mobiledevicerules.service.MDRActionServiceUtil;
095    import com.liferay.portlet.mobiledevicerules.service.MDRRuleGroupInstanceLocalServiceUtil;
096    import com.liferay.portlet.mobiledevicerules.service.MDRRuleGroupInstanceServiceUtil;
097    import com.liferay.portlet.sites.action.ActionUtil;
098    import com.liferay.portlet.sites.util.SitesUtil;
099    
100    import java.io.IOException;
101    import java.io.InputStream;
102    
103    import java.util.Iterator;
104    import java.util.List;
105    import java.util.Locale;
106    import java.util.Map;
107    import java.util.Set;
108    
109    import javax.portlet.ActionRequest;
110    import javax.portlet.ActionResponse;
111    import javax.portlet.PortletConfig;
112    import javax.portlet.PortletContext;
113    import javax.portlet.PortletRequest;
114    import javax.portlet.PortletRequestDispatcher;
115    import javax.portlet.RenderRequest;
116    import javax.portlet.RenderResponse;
117    import javax.portlet.ResourceRequest;
118    import javax.portlet.ResourceResponse;
119    
120    import javax.servlet.http.HttpServletRequest;
121    import javax.servlet.http.HttpServletResponse;
122    
123    import org.apache.struts.action.ActionForm;
124    import org.apache.struts.action.ActionForward;
125    import org.apache.struts.action.ActionMapping;
126    
127    /**
128     * @author Brian Wing Shun Chan
129     * @author Julio Camarero
130     */
131    public class EditLayoutsAction extends PortletAction {
132    
133            @Override
134            public void processAction(
135                            ActionMapping actionMapping, ActionForm actionForm,
136                            PortletConfig portletConfig, ActionRequest actionRequest,
137                            ActionResponse actionResponse)
138                    throws Exception {
139    
140                    try {
141                            checkPermissions(actionRequest);
142                    }
143                    catch (PrincipalException pe) {
144                            return;
145                    }
146    
147                    ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
148                            WebKeys.THEME_DISPLAY);
149    
150                    String cmd = ParamUtil.getString(actionRequest, Constants.CMD);
151    
152                    String redirect = ParamUtil.getString(actionRequest, "redirect");
153                    String closeRedirect = ParamUtil.getString(
154                            actionRequest, "closeRedirect");
155    
156                    try {
157                            Layout layout = null;
158                            String oldFriendlyURL = StringPool.BLANK;
159    
160                            if (cmd.equals(Constants.ADD) || cmd.equals(Constants.UPDATE)) {
161                                    Object[] returnValue = updateLayout(
162                                            actionRequest, actionResponse);
163    
164                                    layout = (Layout)returnValue[0];
165                                    oldFriendlyURL = (String)returnValue[1];
166    
167                                    redirect = updateCloseRedirect(
168                                            themeDisplay, redirect, null, layout, oldFriendlyURL);
169                                    closeRedirect = updateCloseRedirect(
170                                            themeDisplay, closeRedirect, null, layout, oldFriendlyURL);
171    
172                                    SessionMessages.add(
173                                            actionRequest,
174                                            PortalUtil.getPortletId(actionRequest) + "pageAdded",
175                                            layout);
176                            }
177                            else if (cmd.equals(Constants.DELETE)) {
178                                    long plid = ParamUtil.getLong(actionRequest, "plid");
179    
180                                    if (plid <= 0) {
181                                            long groupId = ParamUtil.getLong(actionRequest, "groupId");
182                                            boolean privateLayout = ParamUtil.getBoolean(
183                                                    actionRequest, "privateLayout");
184                                            long layoutId = ParamUtil.getLong(
185                                                    actionRequest, "layoutId");
186    
187                                            layout = LayoutLocalServiceUtil.getLayout(
188                                                    groupId, privateLayout, layoutId);
189    
190                                            plid = layout.getPlid();
191                                    }
192    
193                                    Object[] returnValue = SitesUtil.deleteLayout(
194                                            actionRequest, actionResponse);
195    
196                                    Group group = (Group)returnValue[0];
197                                    oldFriendlyURL = (String)returnValue[1];
198                                    long newRefererPlid = (Long)returnValue[2];
199    
200                                    redirect = updateCloseRedirect(
201                                            themeDisplay, redirect, group, null, oldFriendlyURL);
202    
203                                    long refererPlid = themeDisplay.getRefererPlid();
204    
205                                    if (plid == refererPlid) {
206                                            redirect = HttpUtil.setParameter(
207                                                    redirect, "refererPlid", newRefererPlid);
208                                            redirect = HttpUtil.setParameter(
209                                                    redirect, actionResponse.getNamespace() + "selPlid", 0);
210                                    }
211    
212                                    closeRedirect = updateCloseRedirect(
213                                            themeDisplay, closeRedirect, group, null, oldFriendlyURL);
214    
215                                    redirect = HttpUtil.addParameter(
216                                            redirect, actionResponse.getNamespace() + "closeRedirect",
217                                            closeRedirect);
218                            }
219                            else if (cmd.equals("display_order")) {
220                                    updateDisplayOrder(actionRequest);
221                            }
222                            else if (cmd.equals("delete_layout_revision")) {
223                                    deleteLayoutRevision(actionRequest);
224                            }
225                            else if (cmd.equals("enable")) {
226                                    enableLayout(actionRequest);
227                            }
228                            else if (cmd.equals("reset_customized_view")) {
229                                    LayoutTypePortlet layoutTypePortlet =
230                                            themeDisplay.getLayoutTypePortlet();
231    
232                                    if ((layoutTypePortlet != null) &&
233                                            layoutTypePortlet.isCustomizable() &&
234                                            layoutTypePortlet.isCustomizedView()) {
235    
236                                            layoutTypePortlet.resetUserPreferences();
237                                    }
238                            }
239                            else if (cmd.equals("reset_merge_fail_count_and_merge")) {
240                                    resetMergeFailCountAndMerge(actionRequest);
241                            }
242                            else if (cmd.equals("reset_prototype")) {
243                                    SitesUtil.resetPrototype(themeDisplay.getLayout());
244                            }
245                            else if (cmd.equals("select_layout_set_branch")) {
246                                    selectLayoutSetBranch(actionRequest);
247                            }
248                            else if (cmd.equals("select_layout_branch")) {
249                                    selectLayoutBranch(actionRequest);
250                            }
251                            else if (cmd.equals("update_layout_revision")) {
252                                    updateLayoutRevision(actionRequest, themeDisplay);
253                            }
254    
255                            sendRedirect(
256                                    portletConfig, actionRequest, actionResponse, redirect,
257                                    closeRedirect);
258                    }
259                    catch (Exception e) {
260                            if (e instanceof NoSuchLayoutException ||
261                                    e instanceof PrincipalException) {
262    
263                                    SessionErrors.add(actionRequest, e.getClass());
264    
265                                    setForward(actionRequest, "portlet.layouts_admin.error");
266                            }
267                            else if (e instanceof ImageTypeException ||
268                                             e instanceof LayoutFriendlyURLException ||
269                                             e instanceof LayoutNameException ||
270                                             e instanceof LayoutParentLayoutIdException ||
271                                             e instanceof LayoutSetVirtualHostException ||
272                                             e instanceof LayoutTypeException ||
273                                             e instanceof RequiredLayoutException ||
274                                             e instanceof SitemapChangeFrequencyException ||
275                                             e instanceof SitemapIncludeException ||
276                                             e instanceof SitemapPagePriorityException ||
277                                             e instanceof UploadException) {
278    
279                                    if (e instanceof LayoutFriendlyURLException) {
280                                            SessionErrors.add(
281                                                    actionRequest,
282                                                    LayoutFriendlyURLException.class.getName(), e);
283                                    }
284                                    else {
285                                            SessionErrors.add(actionRequest, e.getClass(), e);
286                                    }
287                            }
288                            else if (e instanceof SystemException) {
289                                    SessionErrors.add(actionRequest, e.getClass(), e);
290    
291                                    redirect = ParamUtil.getString(actionRequest, "pagesRedirect");
292    
293                                    sendRedirect(
294                                            portletConfig, actionRequest, actionResponse, redirect,
295                                            closeRedirect);
296                            }
297                            else {
298                                    throw e;
299                            }
300                    }
301            }
302    
303            @Override
304            public ActionForward render(
305                            ActionMapping actionMapping, ActionForm actionForm,
306                            PortletConfig portletConfig, RenderRequest renderRequest,
307                            RenderResponse renderResponse)
308                    throws Exception {
309    
310                    try {
311                            checkPermissions(renderRequest);
312                    }
313                    catch (PrincipalException pe) {
314                            SessionErrors.add(
315                                    renderRequest, PrincipalException.class.getName());
316    
317                            return actionMapping.findForward("portlet.layouts_admin.error");
318                    }
319    
320                    try {
321                            getGroup(renderRequest);
322                    }
323                    catch (Exception e) {
324                            if (e instanceof NoSuchGroupException ||
325                                    e instanceof PrincipalException) {
326    
327                                    SessionErrors.add(renderRequest, e.getClass());
328    
329                                    return actionMapping.findForward("portlet.layouts_admin.error");
330                            }
331                            else {
332                                    throw e;
333                            }
334                    }
335    
336                    return actionMapping.findForward(
337                            getForward(renderRequest, "portlet.layouts_admin.edit_layouts"));
338            }
339    
340            @Override
341            public void serveResource(
342                            ActionMapping actionMapping, ActionForm actionForm,
343                            PortletConfig portletConfig, ResourceRequest resourceRequest,
344                            ResourceResponse resourceResponse)
345                    throws Exception {
346    
347                    String cmd = ParamUtil.getString(resourceRequest, Constants.CMD);
348    
349                    PortletContext portletContext = portletConfig.getPortletContext();
350    
351                    PortletRequestDispatcher portletRequestDispatcher = null;
352    
353                    if (cmd.equals(ActionKeys.VIEW_TREE)) {
354                            getGroup(resourceRequest);
355    
356                            portletRequestDispatcher = portletContext.getRequestDispatcher(
357                                    "/html/portlet/layouts_admin/tree_js.jsp");
358                    }
359                    else {
360                            getGroup(resourceRequest);
361    
362                            portletRequestDispatcher = portletContext.getRequestDispatcher(
363                                    "/html/portlet/layouts_admin/view_resources.jsp");
364                    }
365    
366                    portletRequestDispatcher.include(resourceRequest, resourceResponse);
367            }
368    
369            protected void checkPermission(
370                            PermissionChecker permissionChecker, Group group, Layout layout,
371                            long selPlid)
372                    throws PortalException, SystemException {
373    
374                    if (selPlid > 0) {
375                            LayoutPermissionUtil.check(
376                                    permissionChecker, layout, ActionKeys.VIEW);
377                    }
378                    else {
379                            GroupPermissionUtil.check(
380                                    permissionChecker, group, ActionKeys.VIEW);
381                    }
382            }
383    
384            protected void checkPermissions(PortletRequest portletRequest)
385                    throws Exception {
386    
387                    Group group = getGroup(portletRequest);
388    
389                    if (group == null) {
390                            throw new PrincipalException();
391                    }
392    
393                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
394                            WebKeys.THEME_DISPLAY);
395    
396                    PermissionChecker permissionChecker =
397                            themeDisplay.getPermissionChecker();
398    
399                    Layout layout = themeDisplay.getLayout();
400    
401                    String cmd = ParamUtil.getString(portletRequest, Constants.CMD);
402    
403                    long selPlid = ParamUtil.getLong(portletRequest, "selPlid");
404    
405                    if (selPlid > 0) {
406                            layout = LayoutLocalServiceUtil.getLayout(selPlid);
407                    }
408    
409                    if (cmd.equals(Constants.ADD)) {
410                            long parentPlid = ParamUtil.getLong(portletRequest, "parentPlid");
411    
412                            if (parentPlid == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
413                                    if (!GroupPermissionUtil.contains(
414                                                    permissionChecker, group.getGroupId(),
415                                                    ActionKeys.ADD_LAYOUT)) {
416    
417                                            throw new PrincipalException();
418                                    }
419                            }
420                            else {
421                                    layout = LayoutLocalServiceUtil.getLayout(parentPlid);
422    
423                                    if (!LayoutPermissionUtil.contains(
424                                                    permissionChecker, layout, ActionKeys.ADD_LAYOUT)) {
425    
426                                            throw new PrincipalException();
427                                    }
428                            }
429                    }
430                    else if (cmd.equals(Constants.DELETE)) {
431                            if (!LayoutPermissionUtil.contains(
432                                            permissionChecker, layout, ActionKeys.DELETE)) {
433    
434                                    throw new PrincipalException();
435                            }
436                    }
437                    else if (cmd.equals(Constants.UPDATE)) {
438                            if (group.isCompany()) {
439                                    if (!permissionChecker.isCompanyAdmin()) {
440                                            throw new PrincipalException();
441                                    }
442                            }
443                            else if (group.isLayoutPrototype()) {
444                                    LayoutPrototypePermissionUtil.check(
445                                            permissionChecker, group.getClassPK(), ActionKeys.UPDATE);
446                            }
447                            else if (group.isLayoutSetPrototype()) {
448                                    LayoutSetPrototypePermissionUtil.check(
449                                            permissionChecker, group.getClassPK(), ActionKeys.UPDATE);
450                            }
451                            else if (group.isUser()) {
452                                    long groupUserId = group.getClassPK();
453    
454                                    User groupUser = UserLocalServiceUtil.getUserById(groupUserId);
455    
456                                    long[] organizationIds = groupUser.getOrganizationIds();
457    
458                                    UserPermissionUtil.check(
459                                            permissionChecker, groupUserId, organizationIds,
460                                            ActionKeys.UPDATE);
461                            }
462                            else {
463                                    checkPermission(permissionChecker, group, layout, selPlid);
464                            }
465                    }
466                    else if (cmd.equals("publish_to_live") ||
467                                     cmd.equals("publish_to_remote")) {
468    
469                            boolean hasUpdateLayoutPermission = false;
470    
471                            if (layout != null) {
472                                    hasUpdateLayoutPermission = LayoutPermissionUtil.contains(
473                                            permissionChecker, layout, ActionKeys.UPDATE);
474                            }
475    
476                            if (group.isCompany() || group.isSite()) {
477                                    boolean publishToLive = GroupPermissionUtil.contains(
478                                            permissionChecker, group.getGroupId(),
479                                            ActionKeys.PUBLISH_STAGING);
480    
481                                    if (!hasUpdateLayoutPermission && !publishToLive) {
482                                            throw new PrincipalException();
483                                    }
484                            }
485                            else {
486                                    checkPermission(permissionChecker, group, layout, selPlid);
487                            }
488                    }
489                    else if (cmd.equals("reset_customized_view")) {
490                            if (!LayoutPermissionUtil.contains(
491                                            permissionChecker, layout, ActionKeys.CUSTOMIZE)) {
492    
493                                    throw new PrincipalException();
494                            }
495                    }
496                    else {
497                            checkPermission(permissionChecker, group, layout, selPlid);
498                    }
499            }
500    
501            protected void deleteLayoutRevision(ActionRequest actionRequest)
502                    throws Exception {
503    
504                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
505                            actionRequest);
506    
507                    long layoutRevisionId = ParamUtil.getLong(
508                            actionRequest, "layoutRevisionId");
509    
510                    LayoutRevision layoutRevision =
511                            LayoutRevisionLocalServiceUtil.getLayoutRevision(layoutRevisionId);
512    
513                    LayoutRevisionLocalServiceUtil.deleteLayoutRevision(layoutRevision);
514    
515                    boolean updateRecentLayoutRevisionId = ParamUtil.getBoolean(
516                            actionRequest, "updateRecentLayoutRevisionId");
517    
518                    if (updateRecentLayoutRevisionId) {
519                            StagingUtil.setRecentLayoutRevisionId(
520                                    request, layoutRevision.getLayoutSetBranchId(),
521                                    layoutRevision.getPlid(),
522                                    layoutRevision.getParentLayoutRevisionId());
523                    }
524            }
525    
526            protected void deleteThemeSettingsProperties(
527                    UnicodeProperties typeSettingsProperties, String device) {
528    
529                    String keyPrefix = ThemeSettingImpl.namespaceProperty(device);
530    
531                    Set<String> keys = typeSettingsProperties.keySet();
532    
533                    Iterator<String> itr = keys.iterator();
534    
535                    while (itr.hasNext()) {
536                            String key = itr.next();
537    
538                            if (key.startsWith(keyPrefix)) {
539                                    itr.remove();
540                            }
541                    }
542            }
543    
544            protected void enableLayout(ActionRequest actionRequest) throws Exception {
545                    long incompleteLayoutRevisionId = ParamUtil.getLong(
546                            actionRequest, "incompleteLayoutRevisionId");
547    
548                    LayoutRevision incompleteLayoutRevision =
549                            LayoutRevisionLocalServiceUtil.getLayoutRevision(
550                                    incompleteLayoutRevisionId);
551    
552                    long layoutBranchId = ParamUtil.getLong(
553                            actionRequest, "layoutBranchId",
554                            incompleteLayoutRevision.getLayoutBranchId());
555    
556                    ServiceContext serviceContext = ServiceContextFactory.getInstance(
557                            actionRequest);
558    
559                    serviceContext.setWorkflowAction(WorkflowConstants.ACTION_SAVE_DRAFT);
560    
561                    LayoutRevisionLocalServiceUtil.updateLayoutRevision(
562                            serviceContext.getUserId(),
563                            incompleteLayoutRevision.getLayoutRevisionId(), layoutBranchId,
564                            incompleteLayoutRevision.getName(),
565                            incompleteLayoutRevision.getTitle(),
566                            incompleteLayoutRevision.getDescription(),
567                            incompleteLayoutRevision.getKeywords(),
568                            incompleteLayoutRevision.getRobots(),
569                            incompleteLayoutRevision.getTypeSettings(),
570                            incompleteLayoutRevision.getIconImage(),
571                            incompleteLayoutRevision.getIconImageId(),
572                            incompleteLayoutRevision.getThemeId(),
573                            incompleteLayoutRevision.getColorSchemeId(),
574                            incompleteLayoutRevision.getWapThemeId(),
575                            incompleteLayoutRevision.getWapColorSchemeId(),
576                            incompleteLayoutRevision.getCss(), serviceContext);
577            }
578    
579            protected String getColorSchemeId(
580                            long companyId, String themeId, String colorSchemeId,
581                            boolean wapTheme)
582                    throws Exception {
583    
584                    Theme theme = ThemeLocalServiceUtil.getTheme(
585                            companyId, themeId, wapTheme);
586    
587                    if (!theme.hasColorSchemes()) {
588                            colorSchemeId = StringPool.BLANK;
589                    }
590    
591                    if (Validator.isNull(colorSchemeId)) {
592                            ColorScheme colorScheme = ThemeLocalServiceUtil.getColorScheme(
593                                    companyId, themeId, colorSchemeId, wapTheme);
594    
595                            colorSchemeId = colorScheme.getColorSchemeId();
596                    }
597    
598                    return colorSchemeId;
599            }
600    
601            protected Group getGroup(PortletRequest portletRequest) throws Exception {
602                    return ActionUtil.getGroup(portletRequest);
603            }
604    
605            protected byte[] getIconBytes(
606                    UploadPortletRequest uploadPortletRequest, String iconFileName) {
607    
608                    InputStream inputStream = null;
609    
610                    try {
611                            inputStream = uploadPortletRequest.getFileAsStream(iconFileName);
612    
613                            if (inputStream != null) {
614                                    return FileUtil.getBytes(inputStream);
615                            }
616                    }
617                    catch (IOException ioe) {
618                            if (_log.isWarnEnabled()) {
619                                    _log.warn("Unable to retrieve icon", ioe);
620                            }
621                    }
622    
623                    return new byte[0];
624            }
625    
626            protected void inheritMobileRuleGroups(
627                            Layout layout, ServiceContext serviceContext)
628                    throws PortalException, SystemException {
629    
630                    List<MDRRuleGroupInstance> parentMDRRuleGroupInstances =
631                            MDRRuleGroupInstanceLocalServiceUtil.getRuleGroupInstances(
632                                    Layout.class.getName(), layout.getParentPlid());
633    
634                    for (MDRRuleGroupInstance parentMDRRuleGroupInstance :
635                                    parentMDRRuleGroupInstances) {
636    
637                            MDRRuleGroupInstance mdrRuleGroupInstance =
638                                    MDRRuleGroupInstanceServiceUtil.addRuleGroupInstance(
639                                            layout.getGroupId(), Layout.class.getName(),
640                                            layout.getPlid(),
641                                            parentMDRRuleGroupInstance.getRuleGroupId(),
642                                            parentMDRRuleGroupInstance.getPriority(), serviceContext);
643    
644                            List<MDRAction> parentMDRActions =
645                                    MDRActionLocalServiceUtil.getActions(
646                                            parentMDRRuleGroupInstance.getRuleGroupInstanceId());
647    
648                            for (MDRAction mdrAction : parentMDRActions) {
649                                    MDRActionServiceUtil.addAction(
650                                            mdrRuleGroupInstance.getRuleGroupInstanceId(),
651                                            mdrAction.getNameMap(), mdrAction.getDescriptionMap(),
652                                            mdrAction.getType(), mdrAction.getTypeSettings(),
653                                            serviceContext);
654                            }
655                    }
656            }
657    
658            @Override
659            protected boolean isCheckMethodOnProcessAction() {
660                    return _CHECK_METHOD_ON_PROCESS_ACTION;
661            }
662    
663            /**
664             * Resets the number of failed merge attempts for the page template, which
665             * is accessed from the action request's <code>layoutPrototypeId</code>
666             * param. Once the counter is reset, the modified page template is merged
667             * back into its linked page, which is accessed from the action request's
668             * <code>selPlid</code> param.
669             *
670             * <p>
671             * If the number of failed merge attempts is not equal to zero after the
672             * merge, an error key is submitted into the {@link SessionErrors}.
673             * </p>
674             *
675             * @param  actionRequest the action request
676             * @throws Exception if an exception occurred
677             */
678            protected void resetMergeFailCountAndMerge(ActionRequest actionRequest)
679                    throws Exception {
680    
681                    long layoutPrototypeId = ParamUtil.getLong(
682                            actionRequest, "layoutPrototypeId");
683    
684                    LayoutPrototype layoutPrototype =
685                            LayoutPrototypeLocalServiceUtil.getLayoutPrototype(
686                                    layoutPrototypeId);
687    
688                    SitesUtil.setMergeFailCount(layoutPrototype, 0);
689    
690                    long selPlid = ParamUtil.getLong(actionRequest, "selPlid");
691    
692                    Layout selLayout = LayoutLocalServiceUtil.getLayout(selPlid);
693    
694                    SitesUtil.resetPrototype(selLayout);
695    
696                    SitesUtil.mergeLayoutPrototypeLayout(selLayout.getGroup(), selLayout);
697    
698                    layoutPrototype = LayoutPrototypeServiceUtil.getLayoutPrototype(
699                            layoutPrototypeId);
700    
701                    int mergeFailCountAfterMerge = SitesUtil.getMergeFailCount(
702                            layoutPrototype);
703    
704                    if (mergeFailCountAfterMerge > 0) {
705                            SessionErrors.add(actionRequest, "resetMergeFailCountAndMerge");
706                    }
707            }
708    
709            protected void selectLayoutBranch(ActionRequest actionRequest)
710                    throws Exception {
711    
712                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
713                            actionRequest);
714    
715                    ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
716                            WebKeys.THEME_DISPLAY);
717    
718                    long layoutSetBranchId = ParamUtil.getLong(
719                            actionRequest, "layoutSetBranchId");
720    
721                    long layoutBranchId = ParamUtil.getLong(
722                            actionRequest, "layoutBranchId");
723    
724                    StagingUtil.setRecentLayoutBranchId(
725                            request, layoutSetBranchId, themeDisplay.getPlid(), layoutBranchId);
726            }
727    
728            protected void selectLayoutSetBranch(ActionRequest actionRequest)
729                    throws Exception {
730    
731                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
732                            actionRequest);
733    
734                    long groupId = ParamUtil.getLong(actionRequest, "groupId");
735                    boolean privateLayout = ParamUtil.getBoolean(
736                            actionRequest, "privateLayout");
737    
738                    LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
739                            groupId, privateLayout);
740    
741                    long layoutSetBranchId = ParamUtil.getLong(
742                            actionRequest, "layoutSetBranchId");
743    
744                    // Ensure layout set branch exists
745    
746                    LayoutSetBranch layoutSetBranch =
747                            LayoutSetBranchLocalServiceUtil.getLayoutSetBranch(
748                                    layoutSetBranchId);
749    
750                    StagingUtil.setRecentLayoutSetBranchId(
751                            request, layoutSet.getLayoutSetId(),
752                            layoutSetBranch.getLayoutSetBranchId());
753            }
754    
755            protected void setThemeSettingProperties(
756                            ActionRequest actionRequest,
757                            UnicodeProperties typeSettingsProperties, String themeId,
758                            Map<String, ThemeSetting> themeSettings, String device,
759                            String deviceThemeId)
760                    throws PortalException, SystemException {
761    
762                    long groupId = ParamUtil.getLong(actionRequest, "groupId");
763                    boolean privateLayout = ParamUtil.getBoolean(
764                            actionRequest, "privateLayout");
765                    long layoutId = ParamUtil.getLong(actionRequest, "layoutId");
766    
767                    Layout layout = LayoutLocalServiceUtil.getLayout(
768                            groupId, privateLayout, layoutId);
769    
770                    LayoutSet layoutSet = layout.getLayoutSet();
771    
772                    for (String key : themeSettings.keySet()) {
773                            ThemeSetting themeSetting = themeSettings.get(key);
774    
775                            String value = null;
776    
777                            if (!themeId.equals(deviceThemeId)) {
778                                    value = themeSetting.getValue();
779                            }
780                            else {
781                                    String property =
782                                            device + "ThemeSettingsProperties--" + key +
783                                                    StringPool.DOUBLE_DASH;
784    
785                                    value = ParamUtil.getString(actionRequest, property);
786                            }
787    
788                            if (!Validator.equals(
789                                            value, layoutSet.getThemeSetting(key, device))) {
790    
791                                    typeSettingsProperties.setProperty(
792                                            ThemeSettingImpl.namespaceProperty(device, key), value);
793                            }
794                    }
795            }
796    
797            protected String updateCloseRedirect(
798                    ThemeDisplay themeDisplay, String closeRedirect, Group group,
799                    Layout layout, String oldLayoutFriendlyURL) {
800    
801                    if (Validator.isNull(closeRedirect) ||
802                            Validator.isNull(oldLayoutFriendlyURL)) {
803    
804                            return closeRedirect;
805                    }
806    
807                    if (layout != null) {
808                            String oldPath = oldLayoutFriendlyURL;
809                            String newPath = layout.getFriendlyURL(themeDisplay.getLocale());
810    
811                            return PortalUtil.updateRedirect(closeRedirect, oldPath, newPath);
812                    }
813                    else if (group != null) {
814                            String oldPath = group.getFriendlyURL() + oldLayoutFriendlyURL;
815                            String newPath = group.getFriendlyURL();
816    
817                            return PortalUtil.updateRedirect(closeRedirect, oldPath, newPath);
818                    }
819    
820                    return closeRedirect;
821            }
822    
823            protected void updateDisplayOrder(ActionRequest actionRequest)
824                    throws Exception {
825    
826                    long groupId = ParamUtil.getLong(actionRequest, "groupId");
827                    boolean privateLayout = ParamUtil.getBoolean(
828                            actionRequest, "privateLayout");
829                    long parentLayoutId = ParamUtil.getLong(
830                            actionRequest, "parentLayoutId");
831                    long[] layoutIds = StringUtil.split(
832                            ParamUtil.getString(actionRequest, "layoutIds"), 0L);
833    
834                    ServiceContext serviceContext = ServiceContextFactory.getInstance(
835                            actionRequest);
836    
837                    LayoutServiceUtil.setLayouts(
838                            groupId, privateLayout, parentLayoutId, layoutIds, serviceContext);
839            }
840    
841            protected Object[] updateLayout(
842                            ActionRequest actionRequest, ActionResponse actionResponse)
843                    throws Exception {
844    
845                    UploadPortletRequest uploadPortletRequest =
846                            PortalUtil.getUploadPortletRequest(actionRequest);
847    
848                    ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
849                            WebKeys.THEME_DISPLAY);
850    
851                    String cmd = ParamUtil.getString(uploadPortletRequest, Constants.CMD);
852    
853                    long groupId = ParamUtil.getLong(actionRequest, "groupId");
854                    long liveGroupId = ParamUtil.getLong(actionRequest, "liveGroupId");
855                    long stagingGroupId = ParamUtil.getLong(
856                            actionRequest, "stagingGroupId");
857                    boolean privateLayout = ParamUtil.getBoolean(
858                            actionRequest, "privateLayout");
859                    long layoutId = ParamUtil.getLong(actionRequest, "layoutId");
860                    long parentLayoutId = ParamUtil.getLong(
861                            uploadPortletRequest, "parentLayoutId");
862                    Map<Locale, String> nameMap = LocalizationUtil.getLocalizationMap(
863                            actionRequest, "name");
864                    Map<Locale, String> titleMap = LocalizationUtil.getLocalizationMap(
865                            actionRequest, "title");
866                    Map<Locale, String> descriptionMap =
867                            LocalizationUtil.getLocalizationMap(actionRequest, "description");
868                    Map<Locale, String> keywordsMap = LocalizationUtil.getLocalizationMap(
869                            actionRequest, "keywords");
870                    Map<Locale, String> robotsMap = LocalizationUtil.getLocalizationMap(
871                            actionRequest, "robots");
872                    String type = ParamUtil.getString(uploadPortletRequest, "type");
873                    boolean hidden = ParamUtil.getBoolean(uploadPortletRequest, "hidden");
874                    Map<Locale, String> friendlyURLMap =
875                            LocalizationUtil.getLocalizationMap(actionRequest, "friendlyURL");
876                    boolean iconImage = ParamUtil.getBoolean(
877                            uploadPortletRequest, "iconImage");
878                    byte[] iconBytes = getIconBytes(uploadPortletRequest, "iconFileName");
879                    long layoutPrototypeId = ParamUtil.getLong(
880                            uploadPortletRequest, "layoutPrototypeId");
881    
882                    ServiceContext serviceContext = ServiceContextFactory.getInstance(
883                            Layout.class.getName(), actionRequest);
884    
885                    Layout layout = null;
886                    UnicodeProperties layoutTypeSettingsProperties = null;
887                    String oldFriendlyURL = StringPool.BLANK;
888    
889                    if (cmd.equals(Constants.ADD)) {
890    
891                            // Add layout
892    
893                            boolean inheritFromParentLayoutId = ParamUtil.getBoolean(
894                                    uploadPortletRequest, "inheritFromParentLayoutId");
895    
896                            UnicodeProperties typeSettingsProperties =
897                                    PropertiesParamUtil.getProperties(
898                                            actionRequest, "TypeSettingsProperties--");
899    
900                            if (inheritFromParentLayoutId && (parentLayoutId > 0)) {
901                                    Layout parentLayout = LayoutLocalServiceUtil.getLayout(
902                                            groupId, privateLayout, parentLayoutId);
903    
904                                    layout = LayoutServiceUtil.addLayout(
905                                            groupId, privateLayout, parentLayoutId, nameMap, titleMap,
906                                            parentLayout.getDescriptionMap(),
907                                            parentLayout.getKeywordsMap(), parentLayout.getRobotsMap(),
908                                            parentLayout.getType(), parentLayout.getTypeSettings(),
909                                            hidden, friendlyURLMap, serviceContext);
910    
911                                    inheritMobileRuleGroups(layout, serviceContext);
912    
913                                    if (parentLayout.isTypePortlet()) {
914                                            ActionUtil.copyPreferences(
915                                                    actionRequest, layout, parentLayout);
916    
917                                            SitesUtil.copyLookAndFeel(layout, parentLayout);
918                                    }
919                            }
920                            else if (layoutPrototypeId > 0) {
921                                    LayoutPrototype layoutPrototype =
922                                            LayoutPrototypeServiceUtil.getLayoutPrototype(
923                                                    layoutPrototypeId);
924    
925                                    String layoutPrototypeLinkEnabled = ParamUtil.getString(
926                                            uploadPortletRequest, "layoutPrototypeLinkEnabled");
927    
928                                    if (Validator.isNotNull(layoutPrototypeLinkEnabled)) {
929                                            serviceContext.setAttribute(
930                                                    "layoutPrototypeLinkEnabled",
931                                                    layoutPrototypeLinkEnabled);
932                                    }
933    
934                                    serviceContext.setAttribute(
935                                            "layoutPrototypeUuid", layoutPrototype.getUuid());
936    
937                                    layout = LayoutServiceUtil.addLayout(
938                                            groupId, privateLayout, parentLayoutId, nameMap, titleMap,
939                                            descriptionMap, keywordsMap, robotsMap,
940                                            LayoutConstants.TYPE_PORTLET,
941                                            typeSettingsProperties.toString(), hidden, friendlyURLMap,
942                                            serviceContext);
943                            }
944                            else {
945                                    long copyLayoutId = ParamUtil.getLong(
946                                            uploadPortletRequest, "copyLayoutId");
947    
948                                    Layout copyLayout = null;
949    
950                                    if (copyLayoutId > 0) {
951                                            try {
952                                                    copyLayout = LayoutLocalServiceUtil.getLayout(
953                                                            groupId, privateLayout, copyLayoutId);
954    
955                                                    if (copyLayout.isTypePortlet()) {
956                                                            typeSettingsProperties =
957                                                                    copyLayout.getTypeSettingsProperties();
958                                                    }
959                                            }
960                                            catch (NoSuchLayoutException nsle) {
961                                            }
962                                    }
963    
964                                    layout = LayoutServiceUtil.addLayout(
965                                            groupId, privateLayout, parentLayoutId, nameMap, titleMap,
966                                            descriptionMap, keywordsMap, robotsMap, type,
967                                            typeSettingsProperties.toString(), hidden, friendlyURLMap,
968                                            serviceContext);
969    
970                                    LayoutTypePortlet layoutTypePortlet =
971                                            (LayoutTypePortlet)layout.getLayoutType();
972    
973                                    String layoutTemplateId = ParamUtil.getString(
974                                            uploadPortletRequest, "layoutTemplateId",
975                                            PropsValues.DEFAULT_LAYOUT_TEMPLATE_ID);
976    
977                                    layoutTypePortlet.setLayoutTemplateId(
978                                            themeDisplay.getUserId(), layoutTemplateId);
979    
980                                    LayoutServiceUtil.updateLayout(
981                                            groupId, privateLayout, layout.getLayoutId(),
982                                            layout.getTypeSettings());
983    
984                                    if (copyLayout != null) {
985                                            if (copyLayout.isTypePortlet()) {
986                                                    ActionUtil.copyPreferences(
987                                                            actionRequest, layout, copyLayout);
988    
989                                                    SitesUtil.copyLookAndFeel(layout, copyLayout);
990                                            }
991                                    }
992                            }
993    
994                            layoutTypeSettingsProperties = layout.getTypeSettingsProperties();
995                    }
996                    else {
997    
998                            // Update layout
999    
1000                            layout = LayoutLocalServiceUtil.getLayout(
1001                                    groupId, privateLayout, layoutId);
1002    
1003                            oldFriendlyURL = layout.getFriendlyURL(themeDisplay.getLocale());
1004    
1005                            layout = LayoutServiceUtil.updateLayout(
1006                                    groupId, privateLayout, layoutId, layout.getParentLayoutId(),
1007                                    nameMap, titleMap, descriptionMap, keywordsMap, robotsMap, type,
1008                                    hidden, friendlyURLMap, Boolean.valueOf(iconImage), iconBytes,
1009                                    serviceContext);
1010    
1011                            layoutTypeSettingsProperties = layout.getTypeSettingsProperties();
1012    
1013                            if (oldFriendlyURL.equals(
1014                                            layout.getFriendlyURL(themeDisplay.getLocale()))) {
1015    
1016                                    oldFriendlyURL = StringPool.BLANK;
1017                            }
1018    
1019                            UnicodeProperties formTypeSettingsProperties =
1020                                    PropertiesParamUtil.getProperties(
1021                                            actionRequest, "TypeSettingsProperties--");
1022    
1023                            if (type.equals(LayoutConstants.TYPE_PORTLET)) {
1024                                    LayoutTypePortlet layoutTypePortlet =
1025                                            (LayoutTypePortlet)layout.getLayoutType();
1026    
1027                                    String layoutTemplateId = ParamUtil.getString(
1028                                            uploadPortletRequest, "layoutTemplateId",
1029                                            PropsValues.DEFAULT_LAYOUT_TEMPLATE_ID);
1030    
1031                                    layoutTypePortlet.setLayoutTemplateId(
1032                                            themeDisplay.getUserId(), layoutTemplateId);
1033    
1034                                    long copyLayoutId = ParamUtil.getLong(
1035                                            uploadPortletRequest, "copyLayoutId");
1036    
1037                                    if ((copyLayoutId > 0) &&
1038                                            (copyLayoutId != layout.getLayoutId())) {
1039    
1040                                            try {
1041                                                    Layout copyLayout = LayoutLocalServiceUtil.getLayout(
1042                                                            groupId, privateLayout, copyLayoutId);
1043    
1044                                                    if (copyLayout.isTypePortlet()) {
1045                                                            layoutTypeSettingsProperties =
1046                                                                    copyLayout.getTypeSettingsProperties();
1047    
1048                                                            ActionUtil.copyPreferences(
1049                                                                    actionRequest, layout, copyLayout);
1050    
1051                                                            SitesUtil.copyLookAndFeel(layout, copyLayout);
1052                                                    }
1053                                            }
1054                                            catch (NoSuchLayoutException nsle) {
1055                                            }
1056                                    }
1057                                    else {
1058                                            layoutTypeSettingsProperties.putAll(
1059                                                    formTypeSettingsProperties);
1060    
1061                                            LayoutServiceUtil.updateLayout(
1062                                                    groupId, privateLayout, layoutId,
1063                                                    layout.getTypeSettings());
1064                                    }
1065                            }
1066                            else {
1067                                    layout.setTypeSettingsProperties(formTypeSettingsProperties);
1068    
1069                                    layoutTypeSettingsProperties.putAll(
1070                                            layout.getTypeSettingsProperties());
1071    
1072                                    LayoutServiceUtil.updateLayout(
1073                                            groupId, privateLayout, layoutId, layout.getTypeSettings());
1074                            }
1075    
1076                            String[] removeEmbeddedPortletIds = ParamUtil.getParameterValues(
1077                                    actionRequest, "removeEmbeddedPortletIds");
1078    
1079                            if (removeEmbeddedPortletIds.length > 0) {
1080                                    PortletLocalServiceUtil.deletePortlets(
1081                                            themeDisplay.getCompanyId(), removeEmbeddedPortletIds,
1082                                            layout.getPlid());
1083                            }
1084    
1085                            LayoutSettings layoutSettings = LayoutSettings.getInstance(layout);
1086    
1087                            HttpServletResponse response = PortalUtil.getHttpServletResponse(
1088                                    actionResponse);
1089    
1090                            EventsProcessorUtil.process(
1091                                    PropsKeys.LAYOUT_CONFIGURATION_ACTION_UPDATE,
1092                                    layoutSettings.getConfigurationActionUpdate(),
1093                                    uploadPortletRequest, response);
1094                    }
1095    
1096                    updateLookAndFeel(
1097                            actionRequest, themeDisplay.getCompanyId(), liveGroupId,
1098                            stagingGroupId, privateLayout, layout.getLayoutId(),
1099                            layoutTypeSettingsProperties, layout.getThemeId());
1100    
1101                    return new Object[] {layout, oldFriendlyURL};
1102            }
1103    
1104            protected void updateLayoutRevision(
1105                            ActionRequest actionRequest, ThemeDisplay themeDisplay)
1106                    throws Exception {
1107    
1108                    long layoutRevisionId = ParamUtil.getLong(
1109                            actionRequest, "layoutRevisionId");
1110    
1111                    LayoutRevision layoutRevision =
1112                            LayoutRevisionLocalServiceUtil.getLayoutRevision(layoutRevisionId);
1113    
1114                    ServiceContext serviceContext = ServiceContextFactory.getInstance(
1115                            actionRequest);
1116    
1117                    LayoutRevision enableLayoutRevision =
1118                            LayoutRevisionLocalServiceUtil.updateLayoutRevision(
1119                                    serviceContext.getUserId(), layoutRevisionId,
1120                                    layoutRevision.getLayoutBranchId(), layoutRevision.getName(),
1121                                    layoutRevision.getTitle(), layoutRevision.getDescription(),
1122                                    layoutRevision.getKeywords(), layoutRevision.getRobots(),
1123                                    layoutRevision.getTypeSettings(), layoutRevision.getIconImage(),
1124                                    layoutRevision.getIconImageId(), layoutRevision.getThemeId(),
1125                                    layoutRevision.getColorSchemeId(),
1126                                    layoutRevision.getWapThemeId(),
1127                                    layoutRevision.getWapColorSchemeId(), layoutRevision.getCss(),
1128                                    serviceContext);
1129    
1130                    if (layoutRevision.getStatus() != WorkflowConstants.STATUS_INCOMPLETE) {
1131                            return;
1132                    }
1133    
1134                    LayoutRevision lastLayoutRevision =
1135                            LayoutRevisionLocalServiceUtil.fetchLastLayoutRevision(
1136                                    enableLayoutRevision.getPlid(), true);
1137    
1138                    if (lastLayoutRevision != null) {
1139                            LayoutRevision newLayoutRevision =
1140                                    LayoutRevisionLocalServiceUtil.addLayoutRevision(
1141                                            serviceContext.getUserId(),
1142                                            layoutRevision.getLayoutSetBranchId(),
1143                                            layoutRevision.getLayoutBranchId(),
1144                                            enableLayoutRevision.getLayoutRevisionId(), false,
1145                                            layoutRevision.getPlid(),
1146                                            lastLayoutRevision.getLayoutRevisionId(),
1147                                            lastLayoutRevision.isPrivateLayout(),
1148                                            lastLayoutRevision.getName(), lastLayoutRevision.getTitle(),
1149                                            lastLayoutRevision.getDescription(),
1150                                            lastLayoutRevision.getKeywords(),
1151                                            lastLayoutRevision.getRobots(),
1152                                            lastLayoutRevision.getTypeSettings(),
1153                                            lastLayoutRevision.isIconImage(),
1154                                            lastLayoutRevision.getIconImageId(),
1155                                            lastLayoutRevision.getThemeId(),
1156                                            lastLayoutRevision.getColorSchemeId(),
1157                                            lastLayoutRevision.getWapThemeId(),
1158                                            lastLayoutRevision.getWapColorSchemeId(),
1159                                            lastLayoutRevision.getCss(), serviceContext);
1160    
1161                            StagingUtil.setRecentLayoutRevisionId(
1162                                    themeDisplay.getUser(),
1163                                    newLayoutRevision.getLayoutSetBranchId(),
1164                                    newLayoutRevision.getPlid(),
1165                                    newLayoutRevision.getLayoutRevisionId());
1166                    }
1167            }
1168    
1169            protected void updateLookAndFeel(
1170                            ActionRequest actionRequest, long companyId, long liveGroupId,
1171                            long stagingGroupId, boolean privateLayout, long layoutId,
1172                            UnicodeProperties typeSettingsProperties, String themeId)
1173                    throws Exception {
1174    
1175                    String[] devices = StringUtil.split(
1176                            ParamUtil.getString(actionRequest, "devices"));
1177    
1178                    for (String device : devices) {
1179                            String deviceThemeId = ParamUtil.getString(
1180                                    actionRequest, device + "ThemeId");
1181                            String deviceColorSchemeId = ParamUtil.getString(
1182                                    actionRequest, device + "ColorSchemeId");
1183                            String deviceCss = ParamUtil.getString(
1184                                    actionRequest, device + "Css");
1185                            boolean deviceWapTheme = device.equals("wap");
1186    
1187                            boolean deviceInheritLookAndFeel = ParamUtil.getBoolean(
1188                                    actionRequest, device + "InheritLookAndFeel");
1189    
1190                            if (deviceInheritLookAndFeel) {
1191                                    deviceThemeId = ThemeFactoryUtil.getDefaultRegularThemeId(
1192                                            companyId);
1193                                    deviceColorSchemeId = StringPool.BLANK;
1194    
1195                                    deleteThemeSettingsProperties(typeSettingsProperties, device);
1196                            }
1197                            else if (Validator.isNotNull(deviceThemeId)) {
1198                                    deviceColorSchemeId = getColorSchemeId(
1199                                            companyId, deviceThemeId, deviceColorSchemeId,
1200                                            deviceWapTheme);
1201    
1202                                    updateThemeSettingsProperties(
1203                                            actionRequest, companyId, typeSettingsProperties, themeId,
1204                                            device, deviceThemeId, deviceWapTheme);
1205                            }
1206    
1207                            long groupId = liveGroupId;
1208    
1209                            if (stagingGroupId > 0) {
1210                                    groupId = stagingGroupId;
1211                            }
1212    
1213                            LayoutServiceUtil.updateLayout(
1214                                    groupId, privateLayout, layoutId,
1215                                    typeSettingsProperties.toString());
1216    
1217                            LayoutServiceUtil.updateLookAndFeel(
1218                                    groupId, privateLayout, layoutId, deviceThemeId,
1219                                    deviceColorSchemeId, deviceCss, deviceWapTheme);
1220                    }
1221            }
1222    
1223            protected UnicodeProperties updateThemeSettingsProperties(
1224                            ActionRequest actionRequest, long companyId,
1225                            UnicodeProperties typeSettingsProperties, String themeId,
1226                            String device, String deviceThemeId, boolean wapTheme)
1227                    throws Exception {
1228    
1229                    Theme theme = ThemeLocalServiceUtil.getTheme(
1230                            companyId, deviceThemeId, wapTheme);
1231    
1232                    deleteThemeSettingsProperties(typeSettingsProperties, device);
1233    
1234                    Map<String, ThemeSetting> themeSettings =
1235                            theme.getConfigurableSettings();
1236    
1237                    if (themeSettings.isEmpty()) {
1238                            return typeSettingsProperties;
1239                    }
1240    
1241                    setThemeSettingProperties(
1242                            actionRequest, typeSettingsProperties, themeId, themeSettings,
1243                            device, deviceThemeId);
1244    
1245                    return typeSettingsProperties;
1246            }
1247    
1248            private static final boolean _CHECK_METHOD_ON_PROCESS_ACTION = false;
1249    
1250            private static Log _log = LogFactoryUtil.getLog(EditLayoutsAction.class);
1251    
1252    }