1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.model.impl;
16  
17  import com.liferay.portal.LayoutFriendlyURLException;
18  import com.liferay.portal.NoSuchGroupException;
19  import com.liferay.portal.kernel.exception.PortalException;
20  import com.liferay.portal.kernel.exception.SystemException;
21  import com.liferay.portal.kernel.log.Log;
22  import com.liferay.portal.kernel.log.LogFactoryUtil;
23  import com.liferay.portal.kernel.util.CharPool;
24  import com.liferay.portal.kernel.util.HttpUtil;
25  import com.liferay.portal.kernel.util.ListUtil;
26  import com.liferay.portal.kernel.util.LocaleUtil;
27  import com.liferay.portal.kernel.util.LocalizationUtil;
28  import com.liferay.portal.kernel.util.PropsKeys;
29  import com.liferay.portal.kernel.util.StringPool;
30  import com.liferay.portal.kernel.util.StringUtil;
31  import com.liferay.portal.kernel.util.UnicodeProperties;
32  import com.liferay.portal.kernel.util.Validator;
33  import com.liferay.portal.model.ColorScheme;
34  import com.liferay.portal.model.Group;
35  import com.liferay.portal.model.Layout;
36  import com.liferay.portal.model.LayoutConstants;
37  import com.liferay.portal.model.LayoutSet;
38  import com.liferay.portal.model.LayoutType;
39  import com.liferay.portal.model.LayoutTypePortlet;
40  import com.liferay.portal.model.LayoutTypePortletConstants;
41  import com.liferay.portal.model.Theme;
42  import com.liferay.portal.security.permission.ActionKeys;
43  import com.liferay.portal.security.permission.PermissionChecker;
44  import com.liferay.portal.service.GroupLocalServiceUtil;
45  import com.liferay.portal.service.LayoutLocalServiceUtil;
46  import com.liferay.portal.service.LayoutSetLocalServiceUtil;
47  import com.liferay.portal.service.ThemeLocalServiceUtil;
48  import com.liferay.portal.service.permission.LayoutPermissionUtil;
49  import com.liferay.portal.theme.ThemeDisplay;
50  import com.liferay.portal.util.CookieKeys;
51  import com.liferay.portal.util.LayoutClone;
52  import com.liferay.portal.util.LayoutCloneFactory;
53  import com.liferay.portal.util.PortalUtil;
54  import com.liferay.portal.util.PropsUtil;
55  import com.liferay.portal.util.PropsValues;
56  import com.liferay.portal.util.WebKeys;
57  import com.liferay.portlet.PortletURLImpl;
58  
59  import java.io.IOException;
60  
61  import java.util.ArrayList;
62  import java.util.Iterator;
63  import java.util.List;
64  import java.util.Locale;
65  
66  import javax.portlet.PortletException;
67  import javax.portlet.PortletMode;
68  import javax.portlet.PortletRequest;
69  import javax.portlet.WindowState;
70  
71  import javax.servlet.http.HttpServletRequest;
72  
73  /**
74   * <a href="LayoutImpl.java.html"><b><i>View Source</i></b></a>
75   *
76   * @author Brian Wing Shun Chan
77   */
78  public class LayoutImpl extends LayoutModelImpl implements Layout {
79  
80      public static int validateFriendlyURL(String friendlyURL) {
81          if (friendlyURL.length() < 2) {
82              return LayoutFriendlyURLException.TOO_SHORT;
83          }
84  
85          if (!friendlyURL.startsWith(StringPool.SLASH)) {
86              return LayoutFriendlyURLException.DOES_NOT_START_WITH_SLASH;
87          }
88  
89          if (friendlyURL.endsWith(StringPool.SLASH)) {
90              return LayoutFriendlyURLException.ENDS_WITH_SLASH;
91          }
92  
93          if (friendlyURL.indexOf(StringPool.DOUBLE_SLASH) != -1) {
94              return LayoutFriendlyURLException.ADJACENT_SLASHES;
95          }
96  
97          for (char c : friendlyURL.toCharArray()) {
98              if ((!Validator.isChar(c)) && (!Validator.isDigit(c)) &&
99                  (c != CharPool.DASH) && (c != CharPool.PERCENT) &&
100                 (c != CharPool.PERIOD)  && (c != CharPool.PLUS) &&
101                 (c != CharPool.SLASH) && (c != CharPool.UNDERLINE)) {
102 
103                 return LayoutFriendlyURLException.INVALID_CHARACTERS;
104             }
105         }
106 
107         return -1;
108     }
109 
110     public static void validateFriendlyURLKeyword(String friendlyURL)
111         throws LayoutFriendlyURLException {
112 
113         String[] keywords = PropsUtil.getArray(
114             PropsKeys.LAYOUT_FRIENDLY_URL_KEYWORDS);
115 
116         for (int i = 0; i < keywords.length; i++) {
117             String keyword = keywords[i];
118 
119             if ((friendlyURL.indexOf(
120                     StringPool.SLASH + keyword + StringPool.SLASH) != -1) ||
121                 (friendlyURL.endsWith(StringPool.SLASH + keyword))) {
122 
123                 LayoutFriendlyURLException lfurle =
124                     new LayoutFriendlyURLException(
125                         LayoutFriendlyURLException.KEYWORD_CONFLICT);
126 
127                 lfurle.setKeywordConflict(keyword);
128 
129                 throw lfurle;
130             }
131         }
132     }
133 
134     public LayoutImpl() {
135     }
136 
137     public List<Layout> getAllChildren() throws SystemException {
138         List<Layout> layouts = new ArrayList<Layout>();
139 
140         Iterator<Layout> itr = getChildren().iterator();
141 
142         while (itr.hasNext()) {
143             Layout layout = itr.next();
144 
145             layouts.add(layout);
146             layouts.addAll(layout.getChildren());
147         }
148 
149         return layouts;
150     }
151 
152     public long getAncestorLayoutId() throws PortalException, SystemException {
153         long layoutId = 0;
154 
155         Layout layout = this;
156 
157         while (true) {
158             if (!layout.isRootLayout()) {
159                 layout = LayoutLocalServiceUtil.getLayout(
160                     layout.getGroupId(), layout.isPrivateLayout(),
161                     layout.getParentLayoutId());
162             }
163             else {
164                 layoutId = layout.getLayoutId();
165 
166                 break;
167             }
168         }
169 
170         return layoutId;
171     }
172 
173     public long getAncestorPlid() throws PortalException, SystemException {
174         long plid = 0;
175 
176         Layout layout = this;
177 
178         while (true) {
179             if (!layout.isRootLayout()) {
180                 layout = LayoutLocalServiceUtil.getLayout(
181                     layout.getGroupId(), layout.isPrivateLayout(),
182                     layout.getParentLayoutId());
183             }
184             else {
185                 plid = layout.getPlid();
186 
187                 break;
188             }
189         }
190 
191         return plid;
192     }
193 
194     public List<Layout> getAncestors() throws PortalException, SystemException {
195         List<Layout> layouts = new ArrayList<Layout>();
196 
197         Layout layout = this;
198 
199         while (true) {
200             if (!layout.isRootLayout()) {
201                 layout = LayoutLocalServiceUtil.getLayout(
202                     layout.getGroupId(), layout.isPrivateLayout(),
203                     layout.getParentLayoutId());
204 
205                 layouts.add(layout);
206             }
207             else {
208                 break;
209             }
210         }
211 
212         return layouts;
213     }
214 
215     public List<Layout> getChildren() throws SystemException {
216         return LayoutLocalServiceUtil.getLayouts(
217             getGroupId(), isPrivateLayout(), getLayoutId());
218     }
219 
220     public List<Layout> getChildren(PermissionChecker permissionChecker)
221         throws PortalException, SystemException {
222 
223         List<Layout> layouts = ListUtil.copy(getChildren());
224 
225         Iterator<Layout> itr = layouts.iterator();
226 
227         while (itr.hasNext()) {
228             Layout layout = itr.next();
229 
230             if (layout.isHidden() ||
231                 !LayoutPermissionUtil.contains(
232                     permissionChecker, layout, ActionKeys.VIEW)) {
233 
234                 itr.remove();
235             }
236         }
237 
238         return layouts;
239     }
240 
241     public ColorScheme getColorScheme()
242         throws PortalException, SystemException {
243 
244         if (isInheritLookAndFeel()) {
245             return getLayoutSet().getColorScheme();
246         }
247         else {
248             return ThemeLocalServiceUtil.getColorScheme(
249                 getCompanyId(), getTheme().getThemeId(), getColorSchemeId(),
250                 false);
251         }
252     }
253 
254     public String getCssText() throws PortalException, SystemException {
255         if (isInheritLookAndFeel()) {
256             return getLayoutSet().getCss();
257         }
258         else {
259             return getCss();
260         }
261     }
262 
263     public Group getGroup() throws PortalException, SystemException {
264         return GroupLocalServiceUtil.getGroup(getGroupId());
265     }
266 
267     public String getHTMLTitle(Locale locale) {
268         String localeLanguageId = LocaleUtil.toLanguageId(locale);
269 
270         return getHTMLTitle(localeLanguageId);
271     }
272 
273     public String getHTMLTitle(String localeLanguageId) {
274         String htmlTitle = getTitle(localeLanguageId);
275 
276         if (Validator.isNull(htmlTitle)) {
277             htmlTitle = getName(localeLanguageId);
278         }
279 
280         return htmlTitle;
281     }
282 
283     public LayoutSet getLayoutSet() throws PortalException, SystemException {
284         return LayoutSetLocalServiceUtil.getLayoutSet(
285             getGroupId(), isPrivateLayout());
286     }
287 
288     public LayoutType getLayoutType() {
289         return new LayoutTypePortletImpl(this);
290     }
291 
292     public String getName(Locale locale) {
293         String localeLanguageId = LocaleUtil.toLanguageId(locale);
294 
295         return getName(localeLanguageId);
296     }
297 
298     public String getName(Locale locale, boolean useDefault) {
299         String localeLanguageId = LocaleUtil.toLanguageId(locale);
300 
301         return getName(localeLanguageId, useDefault);
302     }
303 
304     public String getName(String localeLanguageId) {
305         return LocalizationUtil.getLocalization(getName(), localeLanguageId);
306     }
307 
308     public String getName(String localeLanguageId, boolean useDefault) {
309         return LocalizationUtil.getLocalization(
310             getName(), localeLanguageId, useDefault);
311     }
312 
313     public long getParentPlid() throws PortalException, SystemException {
314         if (getParentLayoutId() == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
315             return 0;
316         }
317 
318         Layout layout = LayoutLocalServiceUtil.getLayout(
319             getGroupId(), isPrivateLayout(), getParentLayoutId());
320 
321         return layout.getPlid();
322     }
323 
324     public String getRegularURL(HttpServletRequest request)
325         throws PortalException, SystemException {
326 
327         return _getURL(request, false, false);
328     }
329 
330     public String getResetLayoutURL(HttpServletRequest request)
331         throws PortalException, SystemException {
332 
333         return _getURL(request, true, true);
334     }
335 
336     public String getResetMaxStateURL(HttpServletRequest request)
337         throws PortalException, SystemException {
338 
339         return _getURL(request, true, false);
340     }
341 
342     public Group getScopeGroup() throws PortalException, SystemException {
343         Group group = null;
344 
345         try {
346             group = GroupLocalServiceUtil.getLayoutGroup(
347                 getCompanyId(), getPlid());
348         }
349         catch (NoSuchGroupException nsge) {
350         }
351 
352         return group;
353     }
354 
355     public String getTarget() {
356         return PortalUtil.getLayoutTarget(this);
357     }
358 
359     public Theme getTheme() throws PortalException, SystemException {
360         if (isInheritLookAndFeel()) {
361             return getLayoutSet().getTheme();
362         }
363         else {
364             return ThemeLocalServiceUtil.getTheme(
365                 getCompanyId(), getThemeId(), false);
366         }
367     }
368 
369     public String getTitle(Locale locale) {
370         String localeLanguageId = LocaleUtil.toLanguageId(locale);
371 
372         return getTitle(localeLanguageId);
373     }
374 
375     public String getTitle(Locale locale, boolean useDefault) {
376         String localeLanguageId = LocaleUtil.toLanguageId(locale);
377 
378         return getTitle(localeLanguageId, useDefault);
379     }
380 
381     public String getTitle(String localeLanguageId) {
382         return LocalizationUtil.getLocalization(getTitle(), localeLanguageId);
383     }
384 
385     public String getTitle(String localeLanguageId, boolean useDefault) {
386         return LocalizationUtil.getLocalization(
387             getTitle(), localeLanguageId, useDefault);
388     }
389 
390     public String getTypeSettings() {
391         if (_typeSettingsProperties == null) {
392             return super.getTypeSettings();
393         }
394         else {
395             return _typeSettingsProperties.toString();
396         }
397     }
398 
399     public UnicodeProperties getTypeSettingsProperties() {
400         if (_typeSettingsProperties == null) {
401             _typeSettingsProperties = new UnicodeProperties(true);
402 
403             _typeSettingsProperties.fastLoad(super.getTypeSettings());
404         }
405 
406         return _typeSettingsProperties;
407     }
408 
409     public ColorScheme getWapColorScheme()
410         throws PortalException, SystemException {
411 
412         if (isInheritLookAndFeel()) {
413             return getLayoutSet().getWapColorScheme();
414         }
415         else {
416             return ThemeLocalServiceUtil.getColorScheme(
417                 getCompanyId(), getWapTheme().getThemeId(),
418                 getWapColorSchemeId(), true);
419         }
420     }
421 
422     public Theme getWapTheme() throws PortalException, SystemException {
423         if (isInheritWapLookAndFeel()) {
424             return getLayoutSet().getWapTheme();
425         }
426         else {
427             return ThemeLocalServiceUtil.getTheme(
428                 getCompanyId(), getWapThemeId(), true);
429         }
430     }
431 
432     public boolean hasAncestor(long layoutId)
433         throws PortalException, SystemException {
434 
435         long parentLayoutId = getParentLayoutId();
436 
437         while (isRootLayout()) {
438             if (parentLayoutId == layoutId) {
439                 return true;
440             }
441             else {
442                 Layout parentLayout = LayoutLocalServiceUtil.getLayout(
443                     getGroupId(), isPrivateLayout(), parentLayoutId);
444 
445                 parentLayoutId = parentLayout.getParentLayoutId();
446             }
447         }
448 
449         return false;
450     }
451 
452     public boolean hasChildren() throws SystemException {
453         return LayoutLocalServiceUtil.hasLayouts(
454             getGroupId(), isPrivateLayout(), getLayoutId());
455     }
456 
457     public boolean hasScopeGroup() throws PortalException, SystemException {
458         Group group = getScopeGroup();
459 
460         if (group != null) {
461             return true;
462         }
463         else {
464             return false;
465         }
466     }
467 
468     public boolean isChildSelected(boolean selectable, Layout layout)
469         throws PortalException, SystemException {
470 
471         if (selectable) {
472             long plid = getPlid();
473 
474             List<Layout> ancestors = layout.getAncestors();
475 
476             for (Layout curLayout : ancestors) {
477                 if (plid == curLayout.getPlid()) {
478                     return true;
479                 }
480             }
481         }
482 
483         return false;
484     }
485 
486     public boolean isFirstChild() {
487         if (getPriority() == 0) {
488             return true;
489         }
490         else {
491             return false;
492         }
493     }
494 
495     public boolean isFirstParent() {
496         if (isFirstChild() && isRootLayout()) {
497             return true;
498         }
499         else {
500             return false;
501         }
502     }
503 
504     public boolean isInheritLookAndFeel() {
505         if (Validator.isNull(getThemeId()) ||
506             Validator.isNull(getColorSchemeId())) {
507 
508             return true;
509         }
510         else {
511             return false;
512         }
513     }
514 
515     public boolean isInheritWapLookAndFeel() {
516         if (Validator.isNull(getWapThemeId()) ||
517             Validator.isNull(getWapColorSchemeId())) {
518 
519             return true;
520         }
521         else {
522             return false;
523         }
524     }
525 
526     public boolean isPublicLayout() {
527         return !isPrivateLayout();
528     }
529 
530     public boolean isRootLayout() {
531         if (getParentLayoutId() == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
532             return true;
533         }
534         else {
535             return false;
536         }
537     }
538 
539     public boolean isSelected(
540         boolean selectable, Layout layout, long ancestorPlid) {
541 
542         if (selectable) {
543             long plid = getPlid();
544 
545             if ((plid == layout.getPlid()) || (plid == ancestorPlid)) {
546                 return true;
547             }
548         }
549 
550         return false;
551     }
552 
553     public boolean isTypeArticle() {
554         if (getType().equals(LayoutConstants.TYPE_ARTICLE)) {
555             return true;
556         }
557         else {
558             return false;
559         }
560     }
561 
562     public boolean isTypeControlPanel() {
563         if (getType().equals(LayoutConstants.TYPE_CONTROL_PANEL)) {
564             return true;
565         }
566         else {
567             return false;
568         }
569     }
570 
571     public boolean isTypeEmbedded() {
572         if (getType().equals(LayoutConstants.TYPE_EMBEDDED)) {
573             return true;
574         }
575         else {
576             return false;
577         }
578     }
579 
580     public boolean isTypeLinkToLayout() {
581         if (getType().equals(LayoutConstants.TYPE_LINK_TO_LAYOUT)) {
582             return true;
583         }
584         else {
585             return false;
586         }
587     }
588 
589     public boolean isTypePanel() {
590         if (getType().equals(LayoutConstants.TYPE_PANEL)) {
591             return true;
592         }
593         else {
594             return false;
595         }
596     }
597 
598     public boolean isTypePortlet() {
599         if (getType().equals(LayoutConstants.TYPE_PORTLET)) {
600             return true;
601         }
602         else {
603             return false;
604         }
605     }
606 
607     public boolean isTypeURL() {
608         if (getType().equals(LayoutConstants.TYPE_URL)) {
609             return true;
610         }
611         else {
612             return false;
613         }
614     }
615 
616     public void setName(String name, Locale locale) {
617         String localeLanguageId = LocaleUtil.toLanguageId(locale);
618 
619         if (Validator.isNotNull(name)) {
620             setName(
621                 LocalizationUtil.updateLocalization(
622                     getName(), "name", name, localeLanguageId));
623         }
624         else {
625             setName(
626                 LocalizationUtil.removeLocalization(
627                     getName(), "name", localeLanguageId));
628         }
629     }
630 
631     public void setTitle(String title, Locale locale) {
632         String localeLanguageId = LocaleUtil.toLanguageId(locale);
633 
634         if (Validator.isNotNull(title)) {
635             setTitle(
636                 LocalizationUtil.updateLocalization(
637                     getTitle(), "title", title, localeLanguageId));
638         }
639         else {
640             setTitle(
641                 LocalizationUtil.removeLocalization(
642                     getTitle(), "title", localeLanguageId));
643         }
644     }
645 
646     public void setTypeSettings(String typeSettings) {
647         _typeSettingsProperties = null;
648 
649         super.setTypeSettings(typeSettings);
650     }
651 
652     public void setTypeSettingsProperties(
653         UnicodeProperties typeSettingsProperties) {
654 
655         _typeSettingsProperties = typeSettingsProperties;
656 
657         super.setTypeSettings(_typeSettingsProperties.toString());
658     }
659 
660     private LayoutTypePortlet _getLayoutTypePortletClone(
661             HttpServletRequest request)
662         throws IOException {
663 
664         LayoutTypePortlet layoutTypePortlet = null;
665 
666         LayoutClone layoutClone = LayoutCloneFactory.getInstance();
667 
668         if (layoutClone != null) {
669             String typeSettings = layoutClone.get(request, getPlid());
670 
671             if (typeSettings != null) {
672                 UnicodeProperties props = new UnicodeProperties(true);
673 
674                 props.load(typeSettings);
675 
676                 String stateMax = props.getProperty(
677                     LayoutTypePortletConstants.STATE_MAX);
678                 String stateMin = props.getProperty(
679                     LayoutTypePortletConstants.STATE_MIN);
680 
681                 Layout layout = (Layout)this.clone();
682 
683                 layoutTypePortlet = (LayoutTypePortlet)layout.getLayoutType();
684 
685                 layoutTypePortlet.setStateMax(stateMax);
686                 layoutTypePortlet.setStateMin(stateMin);
687             }
688         }
689 
690         if (layoutTypePortlet == null) {
691             layoutTypePortlet = (LayoutTypePortlet)getLayoutType();
692         }
693 
694         return layoutTypePortlet;
695     }
696 
697     private String _getURL(
698             HttpServletRequest request, boolean resetMaxState,
699             boolean resetRenderParameters)
700         throws PortalException, SystemException {
701 
702         ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
703             WebKeys.THEME_DISPLAY);
704 
705         if (resetMaxState) {
706             Layout layout = themeDisplay.getLayout();
707 
708             LayoutTypePortlet layoutTypePortlet = null;
709 
710             if (layout.equals(this)) {
711                 layoutTypePortlet = themeDisplay.getLayoutTypePortlet();
712             }
713             else {
714                 try {
715                     layoutTypePortlet = _getLayoutTypePortletClone(request);
716                 }
717                 catch (IOException ioe) {
718                     _log.error("Unable to clone layout settings", ioe);
719 
720                     layoutTypePortlet = (LayoutTypePortlet)getLayoutType();
721                 }
722             }
723 
724             if (layoutTypePortlet.hasStateMax()) {
725                 String portletId =
726                     StringUtil.split(layoutTypePortlet.getStateMax())[0];
727 
728                 PortletURLImpl portletURLImpl = new PortletURLImpl(
729                     request, portletId, getPlid(), PortletRequest.ACTION_PHASE);
730 
731                 try {
732                     portletURLImpl.setWindowState(WindowState.NORMAL);
733                     portletURLImpl.setPortletMode(PortletMode.VIEW);
734                 }
735                 catch (PortletException pe) {
736                     throw new SystemException(pe);
737                 }
738 
739                 portletURLImpl.setAnchor(false);
740 
741                 if (PropsValues.LAYOUT_DEFAULT_P_L_RESET &&
742                     !resetRenderParameters) {
743 
744                     portletURLImpl.setParameter("p_l_reset", "0");
745                 }
746                 else if (!PropsValues.LAYOUT_DEFAULT_P_L_RESET &&
747                          resetRenderParameters) {
748 
749                     portletURLImpl.setParameter("p_l_reset", "1");
750                 }
751 
752                 return portletURLImpl.toString();
753             }
754         }
755 
756         String url = PortalUtil.getLayoutURL(this, themeDisplay);
757 
758         if (!CookieKeys.hasSessionId(request)) {
759             url = PortalUtil.getURLWithSessionId(
760                 url, request.getSession().getId());
761         }
762 
763         if (!resetMaxState && !resetMaxState) {
764             return url;
765         }
766 
767         if (PropsValues.LAYOUT_DEFAULT_P_L_RESET && !resetRenderParameters) {
768             url = HttpUtil.addParameter(url, "p_l_reset", 0);
769         }
770         else if (!PropsValues.LAYOUT_DEFAULT_P_L_RESET &&
771                  resetRenderParameters) {
772 
773             url = HttpUtil.addParameter(url, "p_l_reset", 1);
774         }
775 
776         return url;
777     }
778 
779     private static Log _log = LogFactoryUtil.getLog(LayoutImpl.class);
780 
781     private UnicodeProperties _typeSettingsProperties;
782 
783 }