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.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.util.CharPool;
29  import com.liferay.portal.kernel.util.HttpUtil;
30  import com.liferay.portal.kernel.util.LocaleUtil;
31  import com.liferay.portal.kernel.util.StringPool;
32  import com.liferay.portal.kernel.util.StringUtil;
33  import com.liferay.portal.kernel.util.UnicodeProperties;
34  import com.liferay.portal.kernel.util.Validator;
35  import com.liferay.portal.model.ColorScheme;
36  import com.liferay.portal.model.Group;
37  import com.liferay.portal.model.Layout;
38  import com.liferay.portal.model.LayoutConstants;
39  import com.liferay.portal.model.LayoutSet;
40  import com.liferay.portal.model.LayoutType;
41  import com.liferay.portal.model.LayoutTypePortlet;
42  import com.liferay.portal.model.Theme;
43  import com.liferay.portal.security.permission.ActionKeys;
44  import com.liferay.portal.security.permission.PermissionChecker;
45  import com.liferay.portal.service.GroupLocalServiceUtil;
46  import com.liferay.portal.service.LayoutLocalServiceUtil;
47  import com.liferay.portal.service.LayoutSetLocalServiceUtil;
48  import com.liferay.portal.service.ThemeLocalServiceUtil;
49  import com.liferay.portal.service.permission.LayoutPermissionUtil;
50  import com.liferay.portal.theme.ThemeDisplay;
51  import com.liferay.portal.util.CookieKeys;
52  import com.liferay.portal.util.LayoutClone;
53  import com.liferay.portal.util.LayoutCloneFactory;
54  import com.liferay.portal.util.PortalUtil;
55  import com.liferay.portal.util.PropsKeys;
56  import com.liferay.portal.util.PropsUtil;
57  import com.liferay.portal.util.PropsValues;
58  import com.liferay.portal.util.WebKeys;
59  import com.liferay.portlet.PortletURLImpl;
60  import com.liferay.util.LocalizationUtil;
61  
62  import java.io.IOException;
63  
64  import java.util.ArrayList;
65  import java.util.Iterator;
66  import java.util.List;
67  import java.util.Locale;
68  
69  import javax.portlet.PortletException;
70  import javax.portlet.PortletMode;
71  import javax.portlet.PortletRequest;
72  import javax.portlet.WindowState;
73  
74  import javax.servlet.http.HttpServletRequest;
75  
76  import org.apache.commons.logging.Log;
77  import org.apache.commons.logging.LogFactory;
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);
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);
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);
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 = 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);
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 isSelected(
566         boolean selectable, Layout layout, long ancestorPlid) {
567 
568         if (selectable) {
569             long plid = getPlid();
570 
571             if ((plid == layout.getPlid()) || (plid == ancestorPlid)) {
572                 return true;
573             }
574         }
575 
576         return false;
577     }
578 
579     private LayoutTypePortlet _getLayoutTypePortletClone(
580             HttpServletRequest request)
581         throws IOException {
582 
583         LayoutTypePortlet layoutTypePortlet = null;
584 
585         LayoutClone layoutClone = LayoutCloneFactory.getInstance();
586 
587         if (layoutClone != null) {
588             String typeSettings = layoutClone.get(request, getPlid());
589 
590             if (typeSettings != null) {
591                 UnicodeProperties props = new UnicodeProperties(true);
592 
593                 props.load(typeSettings);
594 
595                 String stateMax = props.getProperty(
596                     LayoutTypePortletImpl.STATE_MAX);
597                 String stateMin = props.getProperty(
598                     LayoutTypePortletImpl.STATE_MIN);
599 
600                 Layout layout = (Layout)this.clone();
601 
602                 layoutTypePortlet = (LayoutTypePortlet)layout.getLayoutType();
603 
604                 layoutTypePortlet.setStateMax(stateMax);
605                 layoutTypePortlet.setStateMin(stateMin);
606             }
607         }
608 
609         if (layoutTypePortlet == null) {
610             layoutTypePortlet = (LayoutTypePortlet)getLayoutType();
611         }
612 
613         return layoutTypePortlet;
614     }
615 
616     private String _getURL(
617             HttpServletRequest request, boolean resetMaxState,
618             boolean resetRenderParameters)
619         throws SystemException {
620 
621         ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
622             WebKeys.THEME_DISPLAY);
623 
624         if (resetMaxState) {
625             Layout layout = themeDisplay.getLayout();
626 
627             LayoutTypePortlet layoutTypePortlet = null;
628 
629             if (layout.equals(this)) {
630                 layoutTypePortlet = themeDisplay.getLayoutTypePortlet();
631             }
632             else {
633                 try {
634                     layoutTypePortlet = _getLayoutTypePortletClone(request);
635                 }
636                 catch (IOException ioe) {
637                     _log.error("Unable to clone layout settings", ioe);
638 
639                     layoutTypePortlet = (LayoutTypePortlet)getLayoutType();
640                 }
641             }
642 
643             if (layoutTypePortlet.hasStateMax()) {
644                 String portletId =
645                     StringUtil.split(layoutTypePortlet.getStateMax())[0];
646 
647                 PortletURLImpl portletURLImpl = new PortletURLImpl(
648                     request, portletId, getPlid(), PortletRequest.ACTION_PHASE);
649 
650                 try {
651                     portletURLImpl.setWindowState(WindowState.NORMAL);
652                     portletURLImpl.setPortletMode(PortletMode.VIEW);
653                 }
654                 catch (PortletException pe) {
655                     throw new SystemException(pe);
656                 }
657 
658                 portletURLImpl.setAnchor(false);
659 
660                 if (PropsValues.LAYOUT_DEFAULT_P_L_RESET &&
661                     !resetRenderParameters) {
662 
663                     portletURLImpl.setParameter("p_l_reset", "0");
664                 }
665                 else if (!PropsValues.LAYOUT_DEFAULT_P_L_RESET &&
666                          resetRenderParameters) {
667 
668                     portletURLImpl.setParameter("p_l_reset", "1");
669                 }
670 
671                 return portletURLImpl.toString();
672             }
673         }
674 
675         String url = PortalUtil.getLayoutURL(this, themeDisplay);
676 
677         if (!CookieKeys.hasSessionId(request)) {
678             url = PortalUtil.getURLWithSessionId(
679                 url, request.getSession().getId());
680         }
681 
682         if (!resetMaxState && !resetMaxState) {
683             return url;
684         }
685 
686         if (PropsValues.LAYOUT_DEFAULT_P_L_RESET && !resetRenderParameters) {
687             url = HttpUtil.addParameter(url, "p_l_reset", 0);
688         }
689         else if (!PropsValues.LAYOUT_DEFAULT_P_L_RESET &&
690                  resetRenderParameters) {
691 
692             url = HttpUtil.addParameter(url, "p_l_reset", 1);
693         }
694 
695         return url;
696     }
697 
698     private static Log _log = LogFactory.getLog(LayoutImpl.class);
699 
700     private UnicodeProperties _typeSettingsProperties = null;
701 
702 }