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