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