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