1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.events;
24  
25  import com.liferay.portal.LayoutPermissionException;
26  import com.liferay.portal.NoSuchGroupException;
27  import com.liferay.portal.NoSuchLayoutException;
28  import com.liferay.portal.PortalException;
29  import com.liferay.portal.SystemException;
30  import com.liferay.portal.kernel.events.Action;
31  import com.liferay.portal.kernel.events.ActionException;
32  import com.liferay.portal.kernel.language.LanguageUtil;
33  import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
34  import com.liferay.portal.kernel.portlet.LiferayWindowState;
35  import com.liferay.portal.kernel.security.permission.ActionKeys;
36  import com.liferay.portal.kernel.security.permission.PermissionChecker;
37  import com.liferay.portal.kernel.servlet.BrowserSniffer;
38  import com.liferay.portal.kernel.servlet.ImageServletTokenUtil;
39  import com.liferay.portal.kernel.util.GetterUtil;
40  import com.liferay.portal.kernel.util.LocaleUtil;
41  import com.liferay.portal.kernel.util.NullSafeProperties;
42  import com.liferay.portal.kernel.util.ParamUtil;
43  import com.liferay.portal.kernel.util.PropertiesUtil;
44  import com.liferay.portal.kernel.util.StringPool;
45  import com.liferay.portal.kernel.util.StringUtil;
46  import com.liferay.portal.kernel.util.Validator;
47  import com.liferay.portal.model.ColorScheme;
48  import com.liferay.portal.model.Company;
49  import com.liferay.portal.model.Group;
50  import com.liferay.portal.model.Image;
51  import com.liferay.portal.model.Layout;
52  import com.liferay.portal.model.LayoutSet;
53  import com.liferay.portal.model.LayoutTypePortlet;
54  import com.liferay.portal.model.Theme;
55  import com.liferay.portal.model.User;
56  import com.liferay.portal.model.impl.ColorSchemeImpl;
57  import com.liferay.portal.model.impl.GroupImpl;
58  import com.liferay.portal.model.impl.LayoutImpl;
59  import com.liferay.portal.model.impl.LayoutTypePortletImpl;
60  import com.liferay.portal.model.impl.ThemeImpl;
61  import com.liferay.portal.security.permission.PermissionCheckerFactory;
62  import com.liferay.portal.security.permission.PermissionCheckerImpl;
63  import com.liferay.portal.security.permission.PermissionThreadLocal;
64  import com.liferay.portal.service.GroupLocalServiceUtil;
65  import com.liferay.portal.service.LayoutLocalServiceUtil;
66  import com.liferay.portal.service.OrganizationLocalServiceUtil;
67  import com.liferay.portal.service.UserLocalServiceUtil;
68  import com.liferay.portal.service.impl.ImageLocalUtil;
69  import com.liferay.portal.service.impl.ThemeLocalUtil;
70  import com.liferay.portal.service.permission.GroupPermissionUtil;
71  import com.liferay.portal.service.permission.LayoutPermissionUtil;
72  import com.liferay.portal.service.permission.OrganizationPermissionUtil;
73  import com.liferay.portal.service.permission.UserPermissionUtil;
74  import com.liferay.portal.theme.ThemeDisplay;
75  import com.liferay.portal.theme.ThemeDisplayFactory;
76  import com.liferay.portal.util.CookieKeys;
77  import com.liferay.portal.util.LayoutClone;
78  import com.liferay.portal.util.LayoutCloneFactory;
79  import com.liferay.portal.util.PortalUtil;
80  import com.liferay.portal.util.PortletKeys;
81  import com.liferay.portal.util.PropsUtil;
82  import com.liferay.portal.util.PropsValues;
83  import com.liferay.portal.util.WebKeys;
84  import com.liferay.portlet.PortletURLImpl;
85  import com.liferay.util.CookieUtil;
86  import com.liferay.util.ListUtil;
87  import com.liferay.util.dao.hibernate.QueryUtil;
88  import com.liferay.util.servlet.SessionErrors;
89  
90  import java.io.File;
91  
92  import java.util.ArrayList;
93  import java.util.HashMap;
94  import java.util.LinkedHashMap;
95  import java.util.List;
96  import java.util.Locale;
97  import java.util.Map;
98  import java.util.Properties;
99  import java.util.TimeZone;
100 
101 import javax.portlet.PortletMode;
102 import javax.portlet.PortletURL;
103 import javax.portlet.WindowState;
104 
105 import javax.servlet.http.HttpServletRequest;
106 import javax.servlet.http.HttpServletResponse;
107 import javax.servlet.http.HttpSession;
108 
109 import org.apache.commons.lang.time.StopWatch;
110 import org.apache.commons.logging.Log;
111 import org.apache.commons.logging.LogFactory;
112 import org.apache.struts.Globals;
113 
114 /**
115  * <a href="ServicePreAction.java.html"><b><i>View Source</i></b></a>
116  *
117  * @author Brian Wing Shun Chan
118  * @author Felix Ventero
119  *
120  */
121 public class ServicePreAction extends Action {
122 
123     public ServicePreAction() {
124         initImportLARFiles();
125     }
126 
127     public void run(HttpServletRequest req, HttpServletResponse res)
128         throws ActionException {
129 
130         StopWatch stopWatch = null;
131 
132         if (_log.isDebugEnabled()) {
133             stopWatch = new StopWatch();
134 
135             stopWatch.start();
136         }
137 
138         try {
139             servicePre(req, res);
140         }
141         catch (Exception e) {
142             _log.error(e, e);
143 
144             throw new ActionException(e);
145         }
146 
147         if (_log.isDebugEnabled()) {
148             _log.debug("Running takes " + stopWatch.getTime() + " ms");
149         }
150     }
151 
152     protected void addDefaultLayouts(User user)
153         throws PortalException, SystemException {
154 
155         if (user.hasPrivateLayouts()) {
156             return;
157         }
158 
159         Group userGroup = user.getGroup();
160 
161         if (privateLARFile != null) {
162             importLayoutsByLAR(
163                 user.getUserId(), userGroup.getGroupId(), true, privateLARFile);
164         }
165         else {
166             importLayoutsByProperties(user.getUserId(), userGroup.getGroupId());
167         }
168 
169         if (publicLARFile != null) {
170             importLayoutsByLAR(
171                 user.getUserId(), userGroup.getGroupId(), false, publicLARFile);
172         }
173     }
174 
175     protected void deleteDefaultLayouts(User user)
176         throws PortalException, SystemException {
177 
178         if (user.hasPrivateLayouts()) {
179             Group userGroup = user.getGroup();
180 
181             LayoutLocalServiceUtil.deleteLayouts(userGroup.getGroupId(), true);
182         }
183 
184         if (user.hasPublicLayouts()) {
185             Group userGroup = user.getGroup();
186 
187             LayoutLocalServiceUtil.deleteLayouts(userGroup.getGroupId(), false);
188         }
189     }
190 
191     protected void fixState(HttpServletRequest req, ThemeDisplay themeDisplay)
192         throws PortalException, SystemException {
193 
194         String requestURI = GetterUtil.getString(req.getRequestURI());
195 
196         if (!requestURI.endsWith("/portal/layout")) {
197             return;
198         }
199 
200         Layout layout = themeDisplay.getLayout();
201 
202         if ((layout == null) ||
203             (!layout.getType().equals(LayoutImpl.TYPE_PORTLET))) {
204 
205             return;
206         }
207 
208         LayoutTypePortlet layoutTypePortlet =
209             themeDisplay.getLayoutTypePortlet();
210 
211         // Fix pop up state
212 
213         String stateMaxPrevious = layoutTypePortlet.getStateMaxPrevious();
214 
215         if (stateMaxPrevious != null && !themeDisplay.isStatePopUp()) {
216             layoutTypePortlet.removeStateMaxPrevious();
217 
218             if (stateMaxPrevious.equals(StringPool.BLANK)) {
219                 layoutTypePortlet.setStateMax(StringPool.BLANK);
220             }
221             else {
222                 layoutTypePortlet.setStateMax(stateMaxPrevious);
223             }
224         }
225 
226         // Fix maximized state
227 
228         if (layoutTypePortlet.hasStateMax()) {
229             String portletId =
230                 StringUtil.split(layoutTypePortlet.getStateMax())[0];
231 
232             boolean removeStateMax = false;
233 
234             if (!PropsValues.LAYOUT_REMEMBER_REQUEST_WINDOW_STATE_MAXIMIZED &&
235                 Validator.isNotNull(portletId)) {
236 
237                 removeStateMax = true;
238             }
239 
240             // If a user accesses a maximized portlet that is not a part of the
241             // layout, the maximized portlet should be removed the next time the
242             // layout is accessed.
243 
244             if (!layoutTypePortlet.hasPortletId(portletId)) {
245                 removeStateMax = true;
246             }
247 
248             if (removeStateMax) {
249                 String ppState = ParamUtil.getString(req, "p_p_state");
250 
251                 if (Validator.isNull(ppState) ||
252                     ppState.equals(WindowState.NORMAL.toString())) {
253 
254                     layoutTypePortlet.removeStateMaxPortletId(portletId);
255                 }
256             }
257         }
258     }
259 
260     protected Object[] getDefaultLayout(
261             HttpServletRequest req, User user, boolean signedIn)
262         throws PortalException, SystemException {
263 
264         // Check the virtual host
265 
266         LayoutSet layoutSet = (LayoutSet)req.getAttribute(
267             WebKeys.VIRTUAL_HOST_LAYOUT_SET);
268 
269         if (layoutSet != null) {
270             List layouts = LayoutLocalServiceUtil.getLayouts(
271                 layoutSet.getGroupId(), layoutSet.isPrivateLayout(),
272                 LayoutImpl.DEFAULT_PARENT_LAYOUT_ID);
273 
274             if (layouts.size() > 0) {
275                 Layout layout = (Layout)layouts.get(0);
276 
277                 return new Object[] {layout, layouts};
278             }
279         }
280 
281         Layout layout = null;
282         List layouts = null;
283 
284         if (signedIn) {
285 
286             // Check the user's personal layouts
287 
288             Group userGroup = user.getGroup();
289 
290             layouts = LayoutLocalServiceUtil.getLayouts(
291                 userGroup.getGroupId(), true,
292                 LayoutImpl.DEFAULT_PARENT_LAYOUT_ID);
293 
294             if (layouts.size() == 0) {
295                 layouts = LayoutLocalServiceUtil.getLayouts(
296                     userGroup.getGroupId(), false,
297                     LayoutImpl.DEFAULT_PARENT_LAYOUT_ID);
298             }
299 
300             if (layouts.size() > 0) {
301                 layout = (Layout)layouts.get(0);
302             }
303 
304             // Check the user's communities
305 
306             if (layout == null) {
307                 LinkedHashMap groupParams = new LinkedHashMap();
308 
309                 groupParams.put("usersGroups", new Long(user.getUserId()));
310 
311                 List groups = GroupLocalServiceUtil.search(
312                     user.getCompanyId(), null, null, groupParams,
313                     QueryUtil.ALL_POS, QueryUtil.ALL_POS);
314 
315                 for (int i = 0; i < groups.size(); i++) {
316                     Group group = (Group)groups.get(i);
317 
318                     layouts = LayoutLocalServiceUtil.getLayouts(
319                         group.getGroupId(), true,
320                         LayoutImpl.DEFAULT_PARENT_LAYOUT_ID);
321 
322                     if (layouts.size() == 0) {
323                         layouts = LayoutLocalServiceUtil.getLayouts(
324                             group.getGroupId(), false,
325                             LayoutImpl.DEFAULT_PARENT_LAYOUT_ID);
326                     }
327 
328                     if (layouts.size() > 0) {
329                         layout = (Layout)layouts.get(0);
330 
331                         break;
332                     }
333                 }
334             }
335         }
336         else {
337 
338             // Check the guest community
339 
340             Group guestGroup = GroupLocalServiceUtil.getGroup(
341                 user.getCompanyId(), GroupImpl.GUEST);
342 
343             layouts = LayoutLocalServiceUtil.getLayouts(
344                 guestGroup.getGroupId(), false,
345                 LayoutImpl.DEFAULT_PARENT_LAYOUT_ID);
346 
347             if (layouts.size() > 0) {
348                 layout = (Layout)layouts.get(0);
349             }
350         }
351 
352         return new Object[] {layout, layouts};
353     }
354 
355     protected void importLayoutsByLAR(
356             long userId, long groupId, boolean privateLayout, File larFile)
357         throws PortalException, SystemException {
358 
359         Map parameterMap = new HashMap();
360 
361         parameterMap.put(
362             PortletDataHandlerKeys.PERMISSIONS, Boolean.TRUE.toString());
363         parameterMap.put(
364             PortletDataHandlerKeys.USER_PERMISSIONS, Boolean.FALSE.toString());
365         parameterMap.put(
366             PortletDataHandlerKeys.PORTLET_DATA, Boolean.TRUE.toString());
367         parameterMap.put(
368             PortletDataHandlerKeys.PORTLET_DATA_CONTROL_DEFAULT,
369             Boolean.TRUE.toString());
370         parameterMap.put(
371             PortletDataHandlerKeys.PORTLET_SETUP, Boolean.TRUE.toString());
372 
373         LayoutLocalServiceUtil.importLayouts(
374             userId, groupId, privateLayout, parameterMap, larFile);
375     }
376 
377     protected void importLayoutsByProperties(long userId, long groupId)
378         throws PortalException, SystemException {
379 
380         String name = PropsValues.DEFAULT_USER_LAYOUT_NAME;
381 
382         Layout layout = LayoutLocalServiceUtil.addLayout(
383             userId, groupId, true, LayoutImpl.DEFAULT_PARENT_LAYOUT_ID, name,
384             StringPool.BLANK, StringPool.BLANK, LayoutImpl.TYPE_PORTLET, false,
385             StringPool.BLANK);
386 
387         LayoutTypePortlet layoutTypePortlet =
388             (LayoutTypePortlet)layout.getLayoutType();
389 
390         String layoutTemplateId = PropsValues.DEFAULT_USER_LAYOUT_TEMPLATE_ID;
391 
392         layoutTypePortlet.setLayoutTemplateId(0, layoutTemplateId, false);
393 
394         for (int i = 0; i < 10; i++) {
395             String columnId = "column-" + i;
396             String portletIds = PropsUtil.get(
397                 PropsUtil.DEFAULT_USER_LAYOUT_COLUMN + i);
398 
399             String[] portletIdsArray = StringUtil.split(portletIds);
400 
401             layoutTypePortlet.addPortletIds(
402                 0, portletIdsArray, columnId, false);
403         }
404 
405         LayoutLocalServiceUtil.updateLayout(
406             layout.getGroupId(), layout.isPrivateLayout(), layout.getLayoutId(),
407             layout.getTypeSettings());
408     }
409 
410     protected Object[] getViewableLayouts(
411             HttpServletRequest req, User user,
412             PermissionChecker permissionChecker, Layout layout, List layouts)
413         throws PortalException, SystemException {
414 
415         if ((layouts != null) && (layouts.size() > 0)) {
416             boolean replaceLayout = true;
417 
418             if (LayoutPermissionUtil.contains(
419                     permissionChecker, layout, ActionKeys.VIEW)) {
420 
421                 replaceLayout = false;
422             }
423 
424             List accessibleLayouts = new ArrayList();
425 
426             for (int i = 0; i < layouts.size(); i++) {
427                 Layout curLayout = (Layout)layouts.get(i);
428 
429                 if (!curLayout.isHidden() &&
430                     LayoutPermissionUtil.contains(
431                         permissionChecker, curLayout, ActionKeys.VIEW)) {
432 
433                     if ((accessibleLayouts.size() == 0) && replaceLayout) {
434                         layout = curLayout;
435                     }
436 
437                     accessibleLayouts.add(curLayout);
438                 }
439             }
440 
441             if (accessibleLayouts.size() == 0) {
442                 layouts = null;
443 
444                 SessionErrors.add(
445                     req, LayoutPermissionException.class.getName());
446             }
447             else {
448                 layouts = accessibleLayouts;
449             }
450         }
451 
452         return new Object[] {layout, layouts};
453     }
454 
455     protected void initImportLARFiles() {
456         String privateLARFileName = PropsValues.DEFAULT_USER_PRIVATE_LAYOUT_LAR;
457 
458         if (_log.isDebugEnabled()) {
459             _log.debug("Reading private LAR file " + privateLARFileName);
460         }
461 
462         if (Validator.isNotNull(privateLARFileName)) {
463             privateLARFile = new File(privateLARFileName);
464 
465             if (!privateLARFile.exists()) {
466                 _log.error(
467                     "Private LAR file " + privateLARFile + " does not exist");
468 
469                 privateLARFile = null;
470             }
471             else {
472                 if (_log.isDebugEnabled()) {
473                     _log.debug("Using private LAR file " + privateLARFileName);
474                 }
475             }
476         }
477 
478         String publicLARFileName = PropsValues.DEFAULT_USER_PUBLIC_LAYOUT_LAR;
479 
480         if (_log.isDebugEnabled()) {
481             _log.debug("Reading public LAR file " + publicLARFileName);
482         }
483 
484         if (Validator.isNotNull(publicLARFileName)) {
485             publicLARFile = new File(publicLARFileName);
486 
487             if (!publicLARFile.exists()) {
488                 _log.error(
489                     "Public LAR file " + publicLARFile + " does not exist");
490 
491                 publicLARFile = null;
492             }
493             else {
494                 if (_log.isDebugEnabled()) {
495                     _log.debug("Using public LAR file " + publicLARFileName);
496                 }
497             }
498         }
499     }
500 
501     protected boolean isViewableCommunity(
502             User user, long groupId, boolean privateLayout,
503             PermissionChecker permissionChecker)
504         throws PortalException, SystemException {
505 
506         Group group = GroupLocalServiceUtil.getGroup(groupId);
507 
508         // Inactive communities are not viewable
509 
510         if (!group.isActive()) {
511             return false;
512         }
513         else if (group.isStagingGroup()) {
514             Group liveGroup = group.getLiveGroup();
515 
516             if (!liveGroup.isActive()) {
517                 return false;
518             }
519         }
520 
521         // User private layouts are only viewable by the user and anyone who can
522         // update the user. The user must also be active.
523 
524         if (group.isUser()) {
525             long groupUserId = group.getClassPK();
526 
527             if (groupUserId == user.getUserId()) {
528                 return true;
529             }
530             else {
531                 User groupUser = UserLocalServiceUtil.getUserById(groupUserId);
532 
533                 if (!groupUser.isActive()) {
534                     return false;
535                 }
536 
537                 if (privateLayout) {
538                     if (UserPermissionUtil.contains(
539                             permissionChecker, groupUserId,
540                             groupUser.getOrganizationIds(),
541                             ActionKeys.UPDATE)) {
542 
543                         return true;
544                     }
545                     else {
546                         return false;
547                     }
548                 }
549             }
550         }
551 
552         // Most public layouts are viewable
553 
554         if (!privateLayout) {
555             return true;
556         }
557 
558         // If the current group is staging, the live group should be checked
559         // for membership instead
560 
561         if (group.isStagingGroup()) {
562             groupId = group.getLiveGroupId();
563         }
564 
565         // Community or organization layouts are only viewable by users who
566         // belong to the community or organization, or by users who can update
567         // the community or organization
568 
569         if (group.isCommunity()) {
570             if (GroupLocalServiceUtil.hasUserGroup(user.getUserId(), groupId)) {
571                 return true;
572             }
573             else if (GroupPermissionUtil.contains(
574                         permissionChecker, groupId, ActionKeys.UPDATE)) {
575 
576                 return true;
577             }
578         }
579         else if (group.isOrganization()) {
580             long organizationId = group.getClassPK();
581 
582             if (OrganizationLocalServiceUtil.hasUserOrganization(
583                     user.getUserId(), organizationId)) {
584 
585                 return true;
586             }
587             else if (OrganizationPermissionUtil.contains(
588                         permissionChecker, organizationId, ActionKeys.UPDATE)) {
589 
590                 return true;
591             }
592         }
593 
594         return false;
595     }
596 
597     protected List mergeAdditionalLayouts(
598             User user, Layout layout, List layouts, HttpServletRequest req)
599         throws PortalException, SystemException {
600 
601         if ((layout == null) || layout.isPrivateLayout()) {
602             return layouts;
603         }
604 
605         long layoutGroupId = layout.getGroupId();
606 
607         Group guestGroup = GroupLocalServiceUtil.getGroup(
608             user.getCompanyId(), GroupImpl.GUEST);
609 
610         if (layoutGroupId != guestGroup.getGroupId()) {
611             Group layoutGroup = GroupLocalServiceUtil.getGroup(layoutGroupId);
612 
613             Properties props = layoutGroup.getTypeSettingsProperties();
614 
615             boolean mergeGuestPublicPages = GetterUtil.getBoolean(
616                 props.getProperty("mergeGuestPublicPages"));
617 
618             if (!mergeGuestPublicPages) {
619                 return layouts;
620             }
621 
622             List guestLayouts = LayoutLocalServiceUtil.getLayouts(
623                 guestGroup.getGroupId(), false,
624                 LayoutImpl.DEFAULT_PARENT_LAYOUT_ID);
625 
626             layouts.addAll(0, guestLayouts);
627         }
628         else {
629             HttpSession ses = req.getSession();
630 
631             Long previousGroupId = (Long)ses.getAttribute(
632                 WebKeys.LIFERAY_SHARED_VISITED_GROUP_ID_PREVIOUS);
633 
634             if ((previousGroupId != null) &&
635                 (previousGroupId.longValue() != layoutGroupId)) {
636 
637                 Group previousGroup = null;
638 
639                 try {
640                     previousGroup = GroupLocalServiceUtil.getGroup(
641                         previousGroupId.longValue());
642                 }
643                 catch (NoSuchGroupException nsge) {
644                     if (_log.isWarnEnabled()) {
645                         _log.warn(nsge);
646                     }
647 
648                     return layouts;
649                 }
650 
651                 Properties props = previousGroup.getTypeSettingsProperties();
652 
653                 boolean mergeGuestPublicPages = GetterUtil.getBoolean(
654                     props.getProperty("mergeGuestPublicPages"));
655 
656                 if (!mergeGuestPublicPages) {
657                     return layouts;
658                 }
659 
660                 List previousLayouts = LayoutLocalServiceUtil.getLayouts(
661                     previousGroupId.longValue(), false,
662                     LayoutImpl.DEFAULT_PARENT_LAYOUT_ID);
663 
664                 layouts.addAll(previousLayouts);
665             }
666         }
667 
668         return layouts;
669     }
670 
671     protected void rememberVisitedGroupIds(
672         long currentGroupId, HttpServletRequest req) {
673 
674         String requestURI = GetterUtil.getString(req.getRequestURI());
675 
676         if (!requestURI.endsWith(_PATH_PORTAL_LAYOUT)) {
677             return;
678         }
679 
680         HttpSession ses = req.getSession();
681 
682         Long recentGroupId = (Long)ses.getAttribute(
683             WebKeys.LIFERAY_SHARED_VISITED_GROUP_ID_RECENT);
684 
685         Long previousGroupId = (Long)ses.getAttribute(
686             WebKeys.LIFERAY_SHARED_VISITED_GROUP_ID_PREVIOUS);
687 
688         if (recentGroupId == null) {
689             recentGroupId = new Long(currentGroupId);
690 
691             ses.setAttribute(
692                 WebKeys.LIFERAY_SHARED_VISITED_GROUP_ID_RECENT,
693                 recentGroupId);
694         }
695         else if (recentGroupId.longValue() != currentGroupId) {
696             previousGroupId = new Long(recentGroupId.longValue());
697 
698             recentGroupId = new Long(currentGroupId);
699 
700             ses.setAttribute(
701                 WebKeys.LIFERAY_SHARED_VISITED_GROUP_ID_RECENT,
702                 recentGroupId);
703 
704             ses.setAttribute(
705                 WebKeys.LIFERAY_SHARED_VISITED_GROUP_ID_PREVIOUS,
706                 previousGroupId);
707         }
708 
709         if (_log.isDebugEnabled()) {
710             _log.debug("Current group id " + currentGroupId);
711             _log.debug("Recent group id " + recentGroupId);
712             _log.debug("Previous group id " + previousGroupId);
713         }
714     }
715 
716     protected void servicePre(HttpServletRequest req, HttpServletResponse res)
717         throws Exception {
718 
719         HttpSession ses = req.getSession();
720 
721         // Company
722 
723         Company company = PortalUtil.getCompany(req);
724 
725         long companyId = company.getCompanyId();
726 
727         // CDN host
728 
729         String cdnHost = ParamUtil.getString(
730             req, "cdn_host", PortalUtil.getCDNHost());
731 
732         // Paths
733 
734         String contextPath = PortalUtil.getPathContext();
735         String friendlyURLPrivateGroupPath =
736             PortalUtil.getPathFriendlyURLPrivateGroup();
737         String friendlyURLPrivateUserPath =
738             PortalUtil.getPathFriendlyURLPrivateUser();
739         String friendlyURLPublicPath = PortalUtil.getPathFriendlyURLPublic();
740         String imagePath = PortalUtil.getPathImage();
741         String mainPath = PortalUtil.getPathMain();
742 
743         // Company logo
744 
745         String companyLogo =
746             imagePath + "/company_logo?img_id=" + company.getLogoId() + "&t=" +
747                 ImageServletTokenUtil.getToken(company.getLogoId());
748 
749         Image companyLogoImage = ImageLocalUtil.getCompanyLogo(
750             company.getLogoId());
751 
752         int companyLogoHeight = companyLogoImage.getHeight();
753         int companyLogoWidth = companyLogoImage.getWidth();
754 
755         String realCompanyLogo = companyLogo;
756         int realCompanyLogoHeight = companyLogoHeight;
757         int realCompanyLogoWidth = companyLogoWidth;
758 
759         // User
760 
761         User user = PortalUtil.getUser(req);
762 
763         boolean signedIn = false;
764 
765         if (user == null) {
766             user = company.getDefaultUser();
767         }
768         else if (!user.isDefaultUser()) {
769             signedIn = true;
770         }
771 
772         User realUser = user;
773 
774         Long realUserId = (Long)ses.getAttribute(WebKeys.USER_ID);
775 
776         if (realUserId != null) {
777             if (user.getUserId() != realUserId.longValue()) {
778                 realUser = UserLocalServiceUtil.getUserById(
779                     realUserId.longValue());
780             }
781         }
782 
783         String doAsUserId = ParamUtil.getString(req, "doAsUserId");
784 
785         // Permission checker
786 
787         PermissionCheckerImpl permissionChecker =
788             PermissionCheckerFactory.create(user, true);
789 
790         PermissionThreadLocal.setPermissionChecker(permissionChecker);
791 
792         // Locale
793 
794         Locale locale = (Locale)ses.getAttribute(Globals.LOCALE_KEY);
795 
796         if (locale == null) {
797             if (signedIn) {
798                 locale = user.getLocale();
799             }
800             else {
801 
802                 // User previously set their preferred language
803 
804                 String languageId = CookieUtil.get(
805                     req.getCookies(), CookieKeys.GUEST_LANGUAGE_ID);
806 
807                 if (Validator.isNotNull(languageId)) {
808                     locale = LocaleUtil.fromLanguageId(languageId);
809                 }
810 
811                 // Get locale from the request
812 
813                 if ((locale == null) && PropsValues.LOCALE_DEFAULT_REQUEST) {
814                     locale = req.getLocale();
815                 }
816 
817                 // Get locale from the default user
818 
819                 if (locale == null) {
820                     locale = user.getLocale();
821                 }
822 
823                 if (Validator.isNull(locale.getCountry())) {
824 
825                     // Locales must contain the country code
826 
827                     locale = LanguageUtil.getLocale(locale.getLanguage());
828                 }
829 
830                 List availableLocales = ListUtil.fromArray(
831                     LanguageUtil.getAvailableLocales());
832 
833                 if (!availableLocales.contains(locale)) {
834                     locale = user.getLocale();
835                 }
836             }
837 
838             ses.setAttribute(Globals.LOCALE_KEY, locale);
839 
840             LanguageUtil.updateCookie(res, locale);
841         }
842 
843         // Cookie support
844 
845         try {
846 
847             // LEP-4069
848 
849             CookieKeys.validateSupportCookie(req);
850         }
851         catch (Exception e) {
852             CookieKeys.addSupportCookie(res);
853         }
854 
855         // Time zone
856 
857         TimeZone timeZone = user.getTimeZone();
858 
859         if (timeZone == null) {
860             timeZone = company.getTimeZone();
861         }
862 
863         // Layouts
864 
865         if (signedIn) {
866             boolean layoutsRequired = user.isLayoutsRequired();
867 
868             if (layoutsRequired) {
869                 addDefaultLayouts(user);
870             }
871             else {
872                 deleteDefaultLayouts(user);
873             }
874         }
875 
876         Layout layout = null;
877         List layouts = null;
878 
879         long plid = ParamUtil.getLong(req, "p_l_id");
880 
881         if (plid > 0) {
882             layout = LayoutLocalServiceUtil.getLayout(plid);
883         }
884         else {
885             long groupId = ParamUtil.getLong(req, "groupId");
886             boolean privateLayout = ParamUtil.getBoolean(req, "privateLayout");
887             long layoutId = ParamUtil.getLong(req, "layoutId");
888 
889             if ((groupId > 0) && layoutId > 0) {
890                 layout = LayoutLocalServiceUtil.getLayout(
891                     groupId, privateLayout, layoutId);
892             }
893         }
894 
895         if (layout != null) {
896             try {
897                 if (!signedIn && PropsValues.AUTH_FORWARD_BY_REDIRECT) {
898                     req.setAttribute(WebKeys.REQUESTED_LAYOUT, layout);
899                 }
900 
901                 boolean isViewableCommunity = isViewableCommunity(
902                     user, layout.getGroupId(), layout.isPrivateLayout(),
903                     permissionChecker);
904 
905                 if (!isViewableCommunity) {
906                     layout = null;
907                 }
908                 else if (isViewableCommunity &&
909                         !LayoutPermissionUtil.contains(
910                             permissionChecker, layout, ActionKeys.VIEW)) {
911 
912                     layout = null;
913                 }
914                 else {
915                     layouts = LayoutLocalServiceUtil.getLayouts(
916                         layout.getGroupId(), layout.isPrivateLayout(),
917                         LayoutImpl.DEFAULT_PARENT_LAYOUT_ID);
918                 }
919             }
920             catch (NoSuchLayoutException nsle) {
921             }
922         }
923 
924         if (layout == null) {
925             Object[] defaultLayout = getDefaultLayout(req, user, signedIn);
926 
927             layout = (Layout)defaultLayout[0];
928             layouts = (List)defaultLayout[1];
929 
930             req.setAttribute(WebKeys.LAYOUT_DEFAULT, Boolean.TRUE);
931         }
932 
933         Object[] viewableLayouts = getViewableLayouts(
934             req, user, permissionChecker, layout, layouts);
935 
936         String layoutSetLogo = null;
937 
938         layout = (Layout)viewableLayouts[0];
939         layouts = (List)viewableLayouts[1];
940 
941         long portletGroupId = PortalUtil.getPortletGroupId(layout);
942 
943         rememberVisitedGroupIds(portletGroupId, req);
944 
945         layouts = mergeAdditionalLayouts(user, layout, layouts, req);
946 
947         if (layout != null) {
948             if (company.isCommunityLogo()) {
949                 LayoutSet layoutSet = layout.getLayoutSet();
950 
951                 if (layoutSet.isLogo()) {
952                     long logoId = layoutSet.getLogoId();
953 
954                     layoutSetLogo =
955                         imagePath + "/layout_set_logo?img_id=" + logoId +
956                             "&t=" + ImageServletTokenUtil.getToken(logoId);
957 
958                     Image layoutSetLogoImage = ImageLocalUtil.getCompanyLogo(
959                         logoId);
960 
961                     companyLogo = layoutSetLogo;
962                     companyLogoHeight = layoutSetLogoImage.getHeight();
963                     companyLogoWidth = layoutSetLogoImage.getWidth();
964                 }
965             }
966 
967             plid = layout.getPlid();
968         }
969 
970         if (layout != null) {
971 
972             // Updates to shared layouts are not reflected until the next time
973             // the user logs in because group layouts are cached in the session
974 
975             layout = (Layout)((LayoutImpl)layout).clone();
976 
977             LayoutClone layoutClone = LayoutCloneFactory.getInstance();
978 
979             if (layoutClone != null) {
980                 String typeSettings = layoutClone.get(req, layout.getPlid());
981 
982                 if (typeSettings != null) {
983                     Properties props = new NullSafeProperties();
984 
985                     PropertiesUtil.load(props, typeSettings);
986 
987                     String stateMax = props.getProperty(
988                         LayoutTypePortletImpl.STATE_MAX);
989                     String stateMaxPrevious = props.getProperty(
990                         LayoutTypePortletImpl.STATE_MAX_PREVIOUS);
991                     String stateMin = props.getProperty(
992                         LayoutTypePortletImpl.STATE_MIN);
993                     String modeAbout = props.getProperty(
994                         LayoutTypePortletImpl.MODE_ABOUT);
995                     String modeConfig = props.getProperty(
996                         LayoutTypePortletImpl.MODE_CONFIG);
997                     String modeEdit = props.getProperty(
998                         LayoutTypePortletImpl.MODE_EDIT);
999                     String modeEditDefaults = props.getProperty(
1000                        LayoutTypePortletImpl.MODE_EDIT_DEFAULTS);
1001                    String modeEditGuest = props.getProperty(
1002                        LayoutTypePortletImpl.MODE_EDIT_GUEST);
1003                    String modeHelp = props.getProperty(
1004                        LayoutTypePortletImpl.MODE_HELP);
1005                    String modePreview = props.getProperty(
1006                        LayoutTypePortletImpl.MODE_PREVIEW);
1007                    String modePrint = props.getProperty(
1008                        LayoutTypePortletImpl.MODE_PRINT);
1009
1010                    LayoutTypePortlet layoutTypePortlet =
1011                        (LayoutTypePortlet)layout.getLayoutType();
1012
1013                    layoutTypePortlet.setStateMax(stateMax);
1014                    layoutTypePortlet.setStateMaxPrevious(stateMaxPrevious);
1015                    layoutTypePortlet.setStateMin(stateMin);
1016                    layoutTypePortlet.setModeAbout(modeAbout);
1017                    layoutTypePortlet.setModeConfig(modeConfig);
1018                    layoutTypePortlet.setModeEdit(modeEdit);
1019                    layoutTypePortlet.setModeEditDefaults(modeEditDefaults);
1020                    layoutTypePortlet.setModeEditGuest(modeEditGuest);
1021                    layoutTypePortlet.setModeHelp(modeHelp);
1022                    layoutTypePortlet.setModePreview(modePreview);
1023                    layoutTypePortlet.setModePrint(modePrint);
1024                }
1025            }
1026        }
1027
1028        LayoutTypePortlet layoutTypePortlet = null;
1029
1030        if (layout != null) {
1031            req.setAttribute(WebKeys.LAYOUT, layout);
1032            req.setAttribute(WebKeys.LAYOUTS, layouts);
1033
1034            layoutTypePortlet = (LayoutTypePortlet)layout.getLayoutType();
1035
1036            if (layout.isPrivateLayout()) {
1037                permissionChecker.setCheckGuest(false);
1038            }
1039        }
1040
1041        // Theme and color scheme
1042
1043        Theme theme = null;
1044        ColorScheme colorScheme = null;
1045
1046        boolean wapTheme = BrowserSniffer.is_wap_xhtml(req);
1047
1048        if (layout != null) {
1049            if (wapTheme) {
1050                theme = layout.getWapTheme();
1051                colorScheme = layout.getWapColorScheme();
1052            }
1053            else {
1054                theme = layout.getTheme();
1055                colorScheme = layout.getColorScheme();
1056            }
1057        }
1058        else {
1059            String themeId = null;
1060            String colorSchemeId = null;
1061
1062            if (wapTheme) {
1063                themeId = ThemeImpl.getDefaultWapThemeId();
1064                colorSchemeId = ColorSchemeImpl.getDefaultWapColorSchemeId();
1065            }
1066            else {
1067                themeId = ThemeImpl.getDefaultRegularThemeId();
1068                colorSchemeId =
1069                    ColorSchemeImpl.getDefaultRegularColorSchemeId();
1070            }
1071
1072            theme = ThemeLocalUtil.getTheme(companyId, themeId, wapTheme);
1073            colorScheme = ThemeLocalUtil.getColorScheme(
1074                companyId, theme.getThemeId(), colorSchemeId, wapTheme);
1075        }
1076
1077        req.setAttribute(WebKeys.THEME, theme);
1078        req.setAttribute(WebKeys.COLOR_SCHEME, colorScheme);
1079
1080        // Theme display
1081
1082        ThemeDisplay themeDisplay = ThemeDisplayFactory.create();
1083
1084        // Set the CDN host first because other methods (setLookAndFeel) depend
1085        // on it being set
1086
1087        themeDisplay.setCDNHost(cdnHost);
1088
1089        themeDisplay.setCompany(company);
1090        themeDisplay.setCompanyLogo(companyLogo);
1091        themeDisplay.setCompanyLogoHeight(companyLogoHeight);
1092        themeDisplay.setCompanyLogoWidth(companyLogoWidth);
1093        themeDisplay.setRealCompanyLogo(realCompanyLogo);
1094        themeDisplay.setRealCompanyLogoHeight(realCompanyLogoHeight);
1095        themeDisplay.setRealCompanyLogoWidth(realCompanyLogoWidth);
1096        themeDisplay.setUser(user);
1097        themeDisplay.setRealUser(realUser);
1098        themeDisplay.setDoAsUserId(doAsUserId);
1099        themeDisplay.setLayoutSetLogo(layoutSetLogo);
1100        themeDisplay.setLayout(layout);
1101        themeDisplay.setLayouts(layouts);
1102        themeDisplay.setPlid(plid);
1103        themeDisplay.setLayoutTypePortlet(layoutTypePortlet);
1104        themeDisplay.setPortletGroupId(portletGroupId);
1105        themeDisplay.setSignedIn(signedIn);
1106        themeDisplay.setPermissionChecker(permissionChecker);
1107        themeDisplay.setLocale(locale);
1108        themeDisplay.setLanguageId(LocaleUtil.toLanguageId(locale));
1109        themeDisplay.setTimeZone(timeZone);
1110        themeDisplay.setLookAndFeel(contextPath, theme, colorScheme);
1111        themeDisplay.setThemeCssFastLoad(PropsValues.THEME_CSS_FAST_LOAD);
1112        themeDisplay.setServerName(req.getServerName());
1113        themeDisplay.setServerPort(req.getServerPort());
1114        themeDisplay.setSecure(req.isSecure());
1115        themeDisplay.setStateExclusive(LiferayWindowState.isExclusive(req));
1116        themeDisplay.setStateMaximized(LiferayWindowState.isMaximized(req));
1117        themeDisplay.setStatePopUp(LiferayWindowState.isPopUp(req));
1118        themeDisplay.setPathApplet(contextPath + "/applets");
1119        themeDisplay.setPathCms(contextPath + "/cms");
1120        themeDisplay.setPathContext(contextPath);
1121        themeDisplay.setPathFlash(contextPath + "/flash");
1122        themeDisplay.setPathFriendlyURLPrivateGroup(
1123            friendlyURLPrivateGroupPath);
1124        themeDisplay.setPathFriendlyURLPrivateUser(friendlyURLPrivateUserPath);
1125        themeDisplay.setPathFriendlyURLPublic(friendlyURLPublicPath);
1126        themeDisplay.setPathImage(imagePath);
1127        themeDisplay.setPathJavaScript(cdnHost + contextPath + "/html/js");
1128        themeDisplay.setPathMain(mainPath);
1129        themeDisplay.setPathSound(contextPath + "/html/sound");
1130
1131        // URLs
1132
1133        themeDisplay.setShowAddContentIcon(false);
1134        themeDisplay.setShowHomeIcon(true);
1135        themeDisplay.setShowMyAccountIcon(signedIn);
1136        themeDisplay.setShowPageSettingsIcon(false);
1137        themeDisplay.setShowPortalIcon(true);
1138        themeDisplay.setShowSignInIcon(!signedIn);
1139        themeDisplay.setShowSignOutIcon(signedIn);
1140
1141        PortletURL createAccountURL = new PortletURLImpl(
1142            req, PortletKeys.MY_ACCOUNT, plid, true);
1143
1144        createAccountURL.setWindowState(WindowState.MAXIMIZED);
1145        createAccountURL.setPortletMode(PortletMode.VIEW);
1146
1147        createAccountURL.setParameter(
1148            "struts_action", "/my_account/create_account");
1149
1150        themeDisplay.setURLCreateAccount(createAccountURL);
1151
1152        String currentURL = PortalUtil.getCurrentURL(req);
1153
1154        themeDisplay.setURLCurrent(currentURL);
1155
1156        String urlHome = PortalUtil.getPortalURL(req) + contextPath;
1157
1158        if (!PropsValues.SESSION_ENABLE_PERSISTENT_COOKIES) {
1159            urlHome = PortalUtil.getURLWithSessionId(urlHome, ses.getId());
1160        }
1161
1162        themeDisplay.setURLHome(urlHome);
1163
1164        if (layout != null) {
1165            if (layout.getType().equals(LayoutImpl.TYPE_PORTLET)) {
1166                boolean freeformLayout =
1167                    layoutTypePortlet.getLayoutTemplateId().equals(
1168                        "freeform");
1169
1170                themeDisplay.setFreeformLayout(freeformLayout);
1171
1172                boolean hasUpdateLayoutPermission =
1173                    LayoutPermissionUtil.contains(
1174                        permissionChecker, layout, ActionKeys.UPDATE);
1175
1176                if (hasUpdateLayoutPermission) {
1177                    if (!LiferayWindowState.isMaximized(req)) {
1178                        themeDisplay.setShowAddContentIcon(true);
1179                    }
1180
1181                    themeDisplay.setShowLayoutTemplatesIcon(true);
1182
1183                    themeDisplay.setURLAddContent(
1184                        "LayoutConfiguration.toggle('" + plid + "', '" +
1185                            PortletKeys.LAYOUT_CONFIGURATION + "', '" +
1186                                doAsUserId + "');");
1187
1188                    themeDisplay.setURLLayoutTemplates(
1189                        "showLayoutTemplates();");
1190                }
1191            }
1192
1193            boolean hasManageLayoutsPermission =
1194                GroupPermissionUtil.contains(
1195                    permissionChecker, portletGroupId,
1196                    ActionKeys.MANAGE_LAYOUTS);
1197
1198            if (hasManageLayoutsPermission) {
1199                themeDisplay.setShowPageSettingsIcon(true);
1200
1201                PortletURL pageSettingsURL = new PortletURLImpl(
1202                    req, PortletKeys.LAYOUT_MANAGEMENT, plid, false);
1203
1204                pageSettingsURL.setWindowState(WindowState.MAXIMIZED);
1205                pageSettingsURL.setPortletMode(PortletMode.VIEW);
1206
1207                pageSettingsURL.setParameter(
1208                    "struts_action", "/layout_management/edit_pages");
1209
1210                if (layout.isPrivateLayout()) {
1211                    pageSettingsURL.setParameter("tabs2", "private");
1212                }
1213                else {
1214                    pageSettingsURL.setParameter("tabs2", "public");
1215                }
1216
1217                pageSettingsURL.setParameter("redirect", currentURL);
1218                pageSettingsURL.setParameter(
1219                    "groupId", String.valueOf(portletGroupId));
1220                pageSettingsURL.setParameter("selPlid", String.valueOf(plid));
1221
1222                themeDisplay.setURLPageSettings(pageSettingsURL);
1223
1224                // Publish To Live
1225
1226                PortletURL publishToLiveURL = new PortletURLImpl(
1227                    req, PortletKeys.LAYOUT_MANAGEMENT, plid, false);
1228
1229                publishToLiveURL.setWindowState(LiferayWindowState.EXCLUSIVE);
1230                publishToLiveURL.setPortletMode(PortletMode.VIEW);
1231
1232                publishToLiveURL.setParameter(
1233                    "struts_action", "/layout_management/export_pages");
1234
1235                publishToLiveURL.setParameter("popupId", "publish-to-live");
1236
1237                if (layout.isPrivateLayout()) {
1238                    publishToLiveURL.setParameter("tabs2", "private");
1239                }
1240                else {
1241                    publishToLiveURL.setParameter("tabs2", "public");
1242                }
1243
1244                publishToLiveURL.setParameter("pagesRedirect", currentURL);
1245                publishToLiveURL.setParameter(
1246                    "groupId", String.valueOf(portletGroupId));
1247                publishToLiveURL.setParameter("selPlid", String.valueOf(plid));
1248
1249                themeDisplay.setURLPublishToLive(publishToLiveURL);
1250            }
1251
1252            String myAccountNamespace = PortalUtil.getPortletNamespace(
1253                PortletKeys.MY_ACCOUNT);
1254
1255            String myAccountRedirect = ParamUtil.getString(
1256                req, myAccountNamespace + "backURL", currentURL);
1257
1258            PortletURL myAccountURL = new PortletURLImpl(
1259                req, PortletKeys.MY_ACCOUNT, plid, false);
1260
1261            myAccountURL.setWindowState(WindowState.MAXIMIZED);
1262            myAccountURL.setPortletMode(PortletMode.VIEW);
1263
1264            myAccountURL.setParameter("struts_action", "/my_account/edit_user");
1265            myAccountURL.setParameter("backURL", myAccountRedirect);
1266
1267            themeDisplay.setURLMyAccount(myAccountURL);
1268        }
1269
1270        if ((!user.isActive()) ||
1271            (PropsValues.TERMS_OF_USE_REQUIRED &&
1272             !user.isAgreedToTermsOfUse())) {
1273
1274            themeDisplay.setShowAddContentIcon(false);
1275            themeDisplay.setShowMyAccountIcon(false);
1276            themeDisplay.setShowPageSettingsIcon(false);
1277        }
1278
1279        themeDisplay.setURLPortal(themeDisplay.getURLHome());
1280        themeDisplay.setURLSignIn(mainPath + "/portal/login");
1281        themeDisplay.setURLSignOut(mainPath + "/portal/logout");
1282
1283        PortletURL updateManagerURL = new PortletURLImpl(
1284            req, PortletKeys.UPDATE_MANAGER, plid, false);
1285
1286        updateManagerURL.setWindowState(WindowState.MAXIMIZED);
1287        updateManagerURL.setPortletMode(PortletMode.VIEW);
1288
1289        updateManagerURL.setParameter("struts_action", "/update_manager/view");
1290
1291        themeDisplay.setURLUpdateManager(updateManagerURL);
1292
1293        req.setAttribute(WebKeys.THEME_DISPLAY, themeDisplay);
1294
1295        // Parallel render
1296
1297        boolean parallelRenderEnable = true;
1298
1299        if (layout != null) {
1300            if (layoutTypePortlet.getPortletIds().size() == 1) {
1301                parallelRenderEnable = false;
1302            }
1303        }
1304
1305        Boolean parallelRenderEnableObj = Boolean.valueOf(
1306            ParamUtil.getBoolean(req, "p_p_parallel", parallelRenderEnable));
1307
1308        req.setAttribute(
1309            WebKeys.PORTLET_PARALLEL_RENDER, parallelRenderEnableObj);
1310
1311        // Fix state
1312
1313        fixState(req, themeDisplay);
1314    }
1315
1316    protected File privateLARFile;
1317    protected File publicLARFile;
1318
1319    private static final String _PATH_PORTAL_LAYOUT = "/portal/layout";
1320
1321    private static Log _log = LogFactory.getLog(ServicePreAction.class);
1322
1323}