1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.service.impl;
16  
17  import com.liferay.portal.kernel.exception.SystemException;
18  import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
19  import com.liferay.portal.kernel.log.Log;
20  import com.liferay.portal.kernel.log.LogFactoryUtil;
21  import com.liferay.portal.kernel.plugin.PluginPackage;
22  import com.liferay.portal.kernel.util.GetterUtil;
23  import com.liferay.portal.kernel.util.HttpUtil;
24  import com.liferay.portal.kernel.util.ListUtil;
25  import com.liferay.portal.kernel.util.ObjectValuePair;
26  import com.liferay.portal.kernel.util.StringBundler;
27  import com.liferay.portal.kernel.util.StringPool;
28  import com.liferay.portal.kernel.util.Validator;
29  import com.liferay.portal.kernel.velocity.VelocityContext;
30  import com.liferay.portal.kernel.velocity.VelocityEngineUtil;
31  import com.liferay.portal.kernel.xml.Document;
32  import com.liferay.portal.kernel.xml.Element;
33  import com.liferay.portal.kernel.xml.SAXReaderUtil;
34  import com.liferay.portal.model.LayoutTemplate;
35  import com.liferay.portal.model.LayoutTemplateConstants;
36  import com.liferay.portal.model.PluginSetting;
37  import com.liferay.portal.model.impl.LayoutTemplateImpl;
38  import com.liferay.portal.service.base.LayoutTemplateLocalServiceBaseImpl;
39  import com.liferay.portal.util.PropsValues;
40  import com.liferay.portlet.layoutconfiguration.util.velocity.InitColumnProcessor;
41  
42  import java.io.IOException;
43  import java.io.PrintWriter;
44  
45  import java.util.ArrayList;
46  import java.util.HashSet;
47  import java.util.Iterator;
48  import java.util.LinkedHashMap;
49  import java.util.List;
50  import java.util.Map;
51  import java.util.Set;
52  
53  import javax.servlet.ServletContext;
54  
55  /**
56   * <a href="LayoutTemplateLocalServiceImpl.java.html"><b><i>View Source</i></b>
57   * </a>
58   *
59   * @author Ivica Cardic
60   * @author Jorge Ferrer
61   * @author Brian Wing Shun Chan
62   * @author Raymond Augé
63   */
64  public class LayoutTemplateLocalServiceImpl
65      extends LayoutTemplateLocalServiceBaseImpl {
66  
67      public String getContent(
68              String layoutTemplateId, boolean standard, String themeId)
69          throws SystemException {
70  
71          LayoutTemplate layoutTemplate = getLayoutTemplate(
72              layoutTemplateId, standard, themeId);
73  
74          if (layoutTemplate == null) {
75              if (_log.isWarnEnabled()) {
76                  _log.warn(
77                      "Layout template " + layoutTemplateId + " does not exist");
78              }
79  
80              layoutTemplate = getLayoutTemplate(
81                  PropsValues.DEFAULT_LAYOUT_TEMPLATE_ID, standard, themeId);
82  
83              if (layoutTemplate == null) {
84                  _log.error(
85                      "Layout template " + layoutTemplateId +
86                          " and default layout template " +
87                              PropsValues.DEFAULT_LAYOUT_TEMPLATE_ID +
88                                  " do not exist");
89  
90                  return StringPool.BLANK;
91              }
92          }
93  
94          if (PropsValues.LAYOUT_TEMPLATE_CACHE_ENABLED) {
95              return layoutTemplate.getContent();
96          }
97          else {
98              try {
99                  return layoutTemplate.getUncachedContent();
100             }
101             catch (IOException ioe) {
102                 throw new SystemException(ioe);
103             }
104         }
105     }
106 
107     public LayoutTemplate getLayoutTemplate(
108         String layoutTemplateId, boolean standard, String themeId) {
109 
110         if (Validator.isNull(layoutTemplateId)) {
111             return null;
112         }
113 
114         LayoutTemplate layoutTemplate = null;
115 
116         if (themeId != null) {
117             if (standard) {
118                 layoutTemplate = _getThemesStandard(themeId).get(
119                     layoutTemplateId);
120             }
121             else {
122                 layoutTemplate = _getThemesCustom(themeId).get(
123                     layoutTemplateId);
124             }
125 
126             if (layoutTemplate != null) {
127                 return layoutTemplate;
128             }
129         }
130 
131         if (standard) {
132             layoutTemplate = _warStandard.get(layoutTemplateId);
133 
134             if (layoutTemplate == null) {
135                 layoutTemplate = _portalStandard.get(layoutTemplateId);
136             }
137         }
138         else {
139             layoutTemplate = _warCustom.get(layoutTemplateId);
140 
141             if (layoutTemplate == null) {
142                 layoutTemplate = _portalCustom.get(layoutTemplateId);
143             }
144         }
145 
146         return layoutTemplate;
147     }
148 
149     public List<LayoutTemplate> getLayoutTemplates() {
150         List<LayoutTemplate> customLayoutTemplates =
151             new ArrayList<LayoutTemplate>(
152                             _portalCustom.size() + _warCustom.size());
153 
154         customLayoutTemplates.addAll(
155             ListUtil.fromCollection(_portalCustom.values()));
156 
157         customLayoutTemplates.addAll(
158             ListUtil.fromCollection(_warCustom.values()));
159 
160         return customLayoutTemplates;
161     }
162 
163     public List<LayoutTemplate> getLayoutTemplates(String themeId) {
164         Map<String, LayoutTemplate> _themesCustom = _getThemesCustom(themeId);
165 
166         List<LayoutTemplate> customLayoutTemplates =
167             new ArrayList<LayoutTemplate>(
168                 _portalCustom.size() + _warCustom.size() +
169                     _themesCustom.size());
170 
171         Iterator<Map.Entry<String, LayoutTemplate>> itr =
172             _portalCustom.entrySet().iterator();
173 
174         while (itr.hasNext()) {
175             Map.Entry<String, LayoutTemplate> entry = itr.next();
176 
177             String layoutTemplateId = entry.getKey();
178             LayoutTemplate layoutTemplate = entry.getValue();
179 
180             if (_themesCustom.containsKey(layoutTemplateId)) {
181                 customLayoutTemplates.add(_themesCustom.get(layoutTemplateId));
182             }
183             else if (_warCustom.containsKey(layoutTemplateId)) {
184                 customLayoutTemplates.add(_warCustom.get(layoutTemplateId));
185             }
186             else {
187                 customLayoutTemplates.add(layoutTemplate);
188             }
189         }
190 
191         itr = _warCustom.entrySet().iterator();
192 
193         while (itr.hasNext()) {
194             Map.Entry<String, LayoutTemplate> entry = itr.next();
195 
196             String layoutTemplateId = entry.getKey();
197 
198             if (!_portalCustom.containsKey(layoutTemplateId) &&
199                 !_themesCustom.containsKey(layoutTemplateId)) {
200 
201                 customLayoutTemplates.add(_warCustom.get(layoutTemplateId));
202             }
203         }
204 
205         itr = _themesCustom.entrySet().iterator();
206 
207         while (itr.hasNext()) {
208             Map.Entry<String, LayoutTemplate> entry = itr.next();
209 
210             String layoutTemplateId = entry.getKey();
211 
212             if (!_portalCustom.containsKey(layoutTemplateId) &&
213                 !_warCustom.containsKey(layoutTemplateId)) {
214 
215                 customLayoutTemplates.add(_themesCustom.get(layoutTemplateId));
216             }
217         }
218 
219         return customLayoutTemplates;
220     }
221 
222     public String getWapContent(
223             String layoutTemplateId, boolean standard, String themeId)
224         throws SystemException {
225 
226         LayoutTemplate layoutTemplate = getLayoutTemplate(
227             layoutTemplateId, standard, themeId);
228 
229         if (layoutTemplate == null) {
230             if (_log.isWarnEnabled()) {
231                 _log.warn(
232                     "Layout template " + layoutTemplateId + " does not exist");
233             }
234 
235             layoutTemplate = getLayoutTemplate(
236                 PropsValues.DEFAULT_LAYOUT_TEMPLATE_ID, standard, themeId);
237 
238             if (layoutTemplate == null) {
239                 _log.error(
240                     "Layout template " + layoutTemplateId +
241                         " and default layout template " +
242                             PropsValues.DEFAULT_LAYOUT_TEMPLATE_ID +
243                                 " do not exist");
244 
245                 return StringPool.BLANK;
246             }
247         }
248 
249         if (PropsValues.LAYOUT_TEMPLATE_CACHE_ENABLED) {
250             return layoutTemplate.getWapContent();
251         }
252         else {
253             try {
254                 return layoutTemplate.getUncachedWapContent();
255             }
256             catch (IOException ioe) {
257                 throw new SystemException(ioe);
258             }
259         }
260     }
261 
262     public List<ObjectValuePair<String, Boolean>> init(
263         ServletContext servletContext, String[] xmls,
264         PluginPackage pluginPackage) {
265 
266         return init(null, servletContext, xmls, pluginPackage);
267     }
268 
269     public List<ObjectValuePair<String, Boolean>> init(
270         String servletContextName, ServletContext servletContext, String[] xmls,
271         PluginPackage pluginPackage) {
272 
273         List<ObjectValuePair<String, Boolean>> layoutTemplateIds =
274             new ArrayList<ObjectValuePair<String, Boolean>>();
275 
276         try {
277             for (int i = 0; i < xmls.length; i++) {
278                 Set<ObjectValuePair<String, Boolean>> curLayoutTemplateIds =
279                     _readLayoutTemplates(
280                         servletContextName, servletContext, xmls[i],
281                         pluginPackage);
282 
283                 Iterator<ObjectValuePair<String, Boolean>> itr =
284                     curLayoutTemplateIds.iterator();
285 
286                 while (itr.hasNext()) {
287                     ObjectValuePair<String, Boolean> ovp = itr.next();
288 
289                     if (!layoutTemplateIds.contains(ovp)) {
290                         layoutTemplateIds.add(ovp);
291                     }
292                 }
293             }
294         }
295         catch (Exception e) {
296             _log.error(e, e);
297         }
298 
299         return layoutTemplateIds;
300     }
301 
302     public void readLayoutTemplate(
303         String servletContextName, ServletContext servletContext,
304         Set<ObjectValuePair<String, Boolean>> layoutTemplateIds,
305         com.liferay.portal.kernel.xml.Element el, boolean standard,
306         String themeId, PluginPackage pluginPackage) {
307 
308         Map<String, LayoutTemplate> layoutTemplates = null;
309 
310         if (themeId != null) {
311             if (standard) {
312                 layoutTemplates = _getThemesStandard(themeId);
313             }
314             else {
315                 layoutTemplates = _getThemesCustom(themeId);
316             }
317         }
318         else if (servletContextName != null) {
319             if (standard) {
320                 layoutTemplates = _warStandard;
321             }
322             else {
323                 layoutTemplates = _warCustom;
324             }
325         }
326         else {
327             if (standard) {
328                 layoutTemplates = _portalStandard;
329             }
330             else {
331                 layoutTemplates = _portalCustom;
332             }
333         }
334 
335         Iterator<com.liferay.portal.kernel.xml.Element> itr = el.elements(
336             "layout-template").iterator();
337 
338         while (itr.hasNext()) {
339             com.liferay.portal.kernel.xml.Element layoutTemplate = itr.next();
340 
341             String layoutTemplateId = layoutTemplate.attributeValue("id");
342 
343             if (layoutTemplateIds != null) {
344                 ObjectValuePair<String, Boolean> ovp =
345                     new ObjectValuePair<String, Boolean>(
346                         layoutTemplateId, standard);
347 
348                 layoutTemplateIds.add(ovp);
349             }
350 
351             LayoutTemplate layoutTemplateModel = layoutTemplates.get(
352                 layoutTemplateId);
353 
354             if (layoutTemplateModel == null) {
355                 layoutTemplateModel = new LayoutTemplateImpl(layoutTemplateId);
356 
357                 layoutTemplates.put(layoutTemplateId, layoutTemplateModel);
358             }
359 
360             PluginSetting pluginSetting =
361                 pluginSettingLocalService.getDefaultPluginSetting();
362 
363             layoutTemplateModel.setPluginPackage(pluginPackage);
364             layoutTemplateModel.setServletContext(servletContext);
365 
366             if (servletContextName != null) {
367                 layoutTemplateModel.setServletContextName(servletContextName);
368             }
369 
370             layoutTemplateModel.setStandard(standard);
371             layoutTemplateModel.setThemeId(themeId);
372             layoutTemplateModel.setName(GetterUtil.getString(
373                 layoutTemplate.attributeValue("name"),
374                 layoutTemplateModel.getName()));
375             layoutTemplateModel.setTemplatePath(GetterUtil.getString(
376                 layoutTemplate.elementText("template-path"),
377                 layoutTemplateModel.getTemplatePath()));
378             layoutTemplateModel.setWapTemplatePath(GetterUtil.getString(
379                 layoutTemplate.elementText("wap-template-path"),
380                 layoutTemplateModel.getWapTemplatePath()));
381             layoutTemplateModel.setThumbnailPath(GetterUtil.getString(
382                 layoutTemplate.elementText("thumbnail-path"),
383                 layoutTemplateModel.getThumbnailPath()));
384 
385             String content = null;
386 
387             try {
388                 content = HttpUtil.URLtoString(servletContext.getResource(
389                     layoutTemplateModel.getTemplatePath()));
390             }
391             catch (Exception e) {
392                 _log.error(
393                     "Unable to get content at template path " +
394                         layoutTemplateModel.getTemplatePath() + ": " +
395                             e.getMessage());
396             }
397 
398             if (Validator.isNull(content)) {
399                 _log.error(
400                     "No content found at template path " +
401                         layoutTemplateModel.getTemplatePath());
402             }
403             else {
404                 StringBundler sb = new StringBundler(3);
405 
406                 sb.append(themeId);
407 
408                 if (standard) {
409                     sb.append(LayoutTemplateConstants.STANDARD_SEPARATOR);
410                 }
411                 else {
412                     sb.append(LayoutTemplateConstants.CUSTOM_SEPARATOR);
413                 }
414 
415                 sb.append(layoutTemplateId);
416 
417                 String velocityTemplateId = sb.toString();
418 
419                 layoutTemplateModel.setContent(content);
420                 layoutTemplateModel.setColumns(
421                     _getColumns(velocityTemplateId, content));
422             }
423 
424             if (Validator.isNull(layoutTemplateModel.getWapTemplatePath())) {
425                 _log.error(
426                     "The element wap-template-path is not defined for " +
427                         layoutTemplateId);
428             }
429             else {
430                 String wapContent = null;
431 
432                 try {
433                     wapContent = HttpUtil.URLtoString(
434                         servletContext.getResource(
435                             layoutTemplateModel.getWapTemplatePath()));
436                 }
437                 catch (Exception e) {
438                     _log.error(
439                         "Unable to get content at WAP template path " +
440                             layoutTemplateModel.getWapTemplatePath() + ": " +
441                                 e.getMessage());
442                 }
443 
444                 if (Validator.isNull(wapContent)) {
445                     _log.error(
446                         "No content found at WAP template path " +
447                             layoutTemplateModel.getWapTemplatePath());
448                 }
449                 else {
450                     layoutTemplateModel.setWapContent(wapContent);
451                 }
452             }
453 
454             com.liferay.portal.kernel.xml.Element rolesEl =
455                 layoutTemplate.element("roles");
456 
457             if (rolesEl != null) {
458                 Iterator<com.liferay.portal.kernel.xml.Element> itr2 =
459                     rolesEl.elements("role-name").iterator();
460 
461                 while (itr2.hasNext()) {
462                     com.liferay.portal.kernel.xml.Element roleNameEl =
463                         itr2.next();
464 
465                     pluginSetting.addRole(roleNameEl.getText());
466                 }
467             }
468 
469             layoutTemplateModel.setDefaultPluginSetting(pluginSetting);
470         }
471     }
472 
473     public void uninstallLayoutTemplate(
474         String layoutTemplateId, boolean standard) {
475 
476         if (standard) {
477             VelocityEngineUtil.flushTemplate(
478                 "null" + LayoutTemplateConstants.STANDARD_SEPARATOR +
479                     layoutTemplateId);
480 
481             _warStandard.remove(layoutTemplateId);
482         }
483         else {
484             VelocityEngineUtil.flushTemplate(
485                 "null" + LayoutTemplateConstants.CUSTOM_SEPARATOR +
486                     layoutTemplateId);
487 
488             _warCustom.remove(layoutTemplateId);
489         }
490     }
491 
492     public void uninstallLayoutTemplates(String themeId) {
493         Map<String, LayoutTemplate> _themesStandard =
494             _getThemesStandard(themeId);
495 
496         for (Map.Entry<String, LayoutTemplate> entry :
497                 _themesStandard.entrySet()) {
498 
499             LayoutTemplate layoutTemplate = entry.getValue();
500 
501             VelocityEngineUtil.flushTemplate(
502                 themeId + LayoutTemplateConstants.STANDARD_SEPARATOR +
503                     layoutTemplate.getLayoutTemplateId());
504         }
505 
506         _themesStandard.clear();
507 
508         Map<String, LayoutTemplate> _themesCustom = _getThemesCustom(themeId);
509 
510         for (Map.Entry<String, LayoutTemplate> entry :
511                 _themesCustom.entrySet()) {
512 
513             LayoutTemplate layoutTemplate = entry.getValue();
514 
515             VelocityEngineUtil.flushTemplate(
516                 themeId + LayoutTemplateConstants.CUSTOM_SEPARATOR +
517                     layoutTemplate.getLayoutTemplateId());
518         }
519 
520         _themesCustom.clear();
521     }
522 
523     private List<String> _getColumns(
524         String velocityTemplateId, String velocityTemplateContent) {
525 
526         try {
527             InitColumnProcessor processor = new InitColumnProcessor();
528 
529             VelocityContext velocityContext =
530                 VelocityEngineUtil.getStandardToolsContext();
531 
532             velocityContext.put("processor", processor);
533 
534             VelocityEngineUtil.mergeTemplate(
535                 velocityTemplateId, velocityTemplateContent, velocityContext,
536                 new PrintWriter(new UnsyncStringWriter(true)));
537 
538             return ListUtil.sort(processor.getColumns());
539         }
540         catch (Exception e) {
541             _log.error(e);
542 
543             return new ArrayList<String>();
544         }
545     }
546 
547     private Set<ObjectValuePair<String, Boolean>> _readLayoutTemplates(
548             String servletContextName, ServletContext servletContext,
549             String xml, PluginPackage pluginPackage)
550         throws Exception {
551 
552         Set<ObjectValuePair<String, Boolean>> layoutTemplateIds =
553             new HashSet<ObjectValuePair<String, Boolean>>();
554 
555         if (xml == null) {
556             return layoutTemplateIds;
557         }
558 
559         Document doc = SAXReaderUtil.read(xml, true);
560 
561         Element root = doc.getRootElement();
562 
563         Element standardEl = root.element("standard");
564 
565         if (standardEl != null) {
566             readLayoutTemplate(
567                 servletContextName, servletContext, layoutTemplateIds,
568                 standardEl, true, null, pluginPackage);
569         }
570 
571         Element customEl = root.element("custom");
572 
573         if (customEl != null) {
574             readLayoutTemplate(
575                 servletContextName, servletContext, layoutTemplateIds,
576                 customEl, false, null, pluginPackage);
577         }
578 
579         return layoutTemplateIds;
580     }
581 
582     private Map<String, LayoutTemplate> _getThemesCustom(String themeId) {
583         String key = themeId + LayoutTemplateConstants.CUSTOM_SEPARATOR;
584 
585         Map<String, LayoutTemplate> layoutTemplates = _themes.get(key);
586 
587         if (layoutTemplates == null) {
588             layoutTemplates = new LinkedHashMap<String, LayoutTemplate>();
589 
590             _themes.put(key, layoutTemplates);
591         }
592 
593         return layoutTemplates;
594     }
595 
596     private Map<String, LayoutTemplate> _getThemesStandard(String themeId) {
597         String key = themeId + LayoutTemplateConstants.STANDARD_SEPARATOR;
598 
599         Map<String, LayoutTemplate> layoutTemplates = _themes.get(key);
600 
601         if (layoutTemplates == null) {
602             layoutTemplates = new LinkedHashMap<String, LayoutTemplate>();
603 
604             _themes.put(key, layoutTemplates);
605         }
606 
607         return layoutTemplates;
608     }
609 
610     private static Log _log = LogFactoryUtil.getLog(
611         LayoutTemplateLocalServiceImpl.class);
612 
613     private static Map<String, LayoutTemplate> _portalStandard =
614         new LinkedHashMap<String, LayoutTemplate>();
615     private static Map<String, LayoutTemplate> _portalCustom =
616         new LinkedHashMap<String, LayoutTemplate>();
617 
618     private static Map<String, LayoutTemplate> _warStandard =
619         new LinkedHashMap<String, LayoutTemplate>();
620     private static Map<String, LayoutTemplate> _warCustom =
621         new LinkedHashMap<String, LayoutTemplate>();
622 
623     private static Map<String, Map<String, LayoutTemplate>> _themes =
624         new LinkedHashMap<String, Map<String, LayoutTemplate>>();
625 
626 }