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