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