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