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