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