View Javadoc
1   /*
2    * Copyright (C) 2003-2007 eXo Platform SAS.
3    *
4    * This program is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Affero General Public License
6    * as published by the Free Software Foundation; either version 3
7    * of the License, or (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program; if not, see<http://www.gnu.org/licenses/>.
16   */
17  package org.exoplatform.services.cms.templates.impl;
18  
19  import java.io.ByteArrayInputStream;
20  import java.io.InputStream;
21  import java.security.AccessControlException;
22  import java.util.ArrayList;
23  import java.util.GregorianCalendar;
24  import java.util.HashMap;
25  import java.util.HashSet;
26  import java.util.List;
27  import java.util.Set;
28  import java.util.Arrays;
29  
30  import javax.jcr.AccessDeniedException;
31  import javax.jcr.Node;
32  import javax.jcr.NodeIterator;
33  import javax.jcr.PathNotFoundException;
34  import javax.jcr.RepositoryException;
35  import javax.jcr.Session;
36  import javax.jcr.Value;
37  import javax.jcr.ValueFormatException;
38  import javax.jcr.nodetype.NodeType;
39  
40  import org.apache.commons.lang.StringUtils;
41  import org.exoplatform.container.component.ComponentPlugin;
42  import org.exoplatform.services.cache.CacheService;
43  import org.exoplatform.services.cache.ExoCache;
44  import org.exoplatform.services.cms.BasePath;
45  import org.exoplatform.services.cms.impl.DMSConfiguration;
46  import org.exoplatform.services.cms.impl.DMSRepositoryConfiguration;
47  import org.exoplatform.services.cms.impl.Utils;
48  import org.exoplatform.services.cms.templates.ContentTypeFilterPlugin;
49  import org.exoplatform.services.cms.templates.ContentTypeFilterPlugin.FolderFilterConfig;
50  import org.exoplatform.services.cms.templates.TemplateService;
51  import org.exoplatform.services.context.DocumentContext;
52  import org.exoplatform.services.jcr.RepositoryService;
53  import org.exoplatform.services.jcr.access.DynamicIdentity;
54  import org.exoplatform.services.jcr.core.ManageableRepository;
55  import org.exoplatform.services.jcr.ext.common.SessionProvider;
56  import org.exoplatform.services.jcr.ext.hierarchy.NodeHierarchyCreator;
57  import org.exoplatform.services.jcr.impl.Constants;
58  import org.exoplatform.services.jcr.impl.core.nodetype.NodeTypeImpl;
59  import org.exoplatform.services.log.ExoLogger;
60  import org.exoplatform.services.log.Log;
61  import org.exoplatform.services.resources.LocaleConfigService;
62  import org.exoplatform.services.resources.Orientation;
63  import org.exoplatform.services.security.Identity;
64  import org.exoplatform.services.security.IdentityConstants;
65  import org.exoplatform.services.security.IdentityRegistry;
66  import org.exoplatform.services.security.MembershipEntry;
67  import org.exoplatform.services.wcm.core.NodetypeConstant;
68  import org.exoplatform.services.wcm.utils.WCMCoreUtils;
69  import org.picocontainer.Startable;
70  
71  /**
72   * @author benjaminmestrallet
73   */
74  public class TemplateServiceImpl implements TemplateService, Startable {
75  
76    private RepositoryService    repositoryService_;
77    private IdentityRegistry     identityRegistry_;
78    private String               cmsTemplatesBasePath_;
79    private List<TemplatePlugin> plugins_ = new ArrayList<TemplatePlugin>();
80    private Set<String> configuredNodeTypes;
81  
82    /**
83     * The key is a folder type, the value is the List of content types.
84     */
85    private HashMap<String, List<String>> foldersFilterMap = null;
86  
87    /**
88     * The key is a repository name, the value is the List of template names.
89     */
90    private HashMap<String, List<String>> managedDocumentTypesMap = new HashMap<String, List<String>>();
91  
92    private org.exoplatform.groovyscript.text.TemplateService templateService;
93    private LocaleConfigService localeConfigService_;
94  
95    private static final Log LOG  = ExoLogger.getLogger(TemplateService.class.getName());
96  
97    private final static String CACHE_NAME = "ecms.TemplateService";
98  
99    /**
100    * DMS configuration which used to store informations
101    */
102   private DMSConfiguration dmsConfiguration_;
103 
104   private static final String NODETYPE_LIST = "nodeTypeList";
105   private static final String EDITED_CONFIGURED_NODE_TYPES = "EditedConfiguredNodeTypes";
106 
107   private ExoCache nodeTypeListCached ;
108 
109   /**
110    * Constructor method.
111    * Init jcrService, nodeHierarchyCreator, identityRegistry, localeConfigService, caService,
112    * dmsConfiguration
113    * @param jcrService              RepositoryService
114    * @param nodeHierarchyCreator    NodeHierarchyCreator
115    * @param identityRegistry        IdentityRegistry
116    * @param localeConfigService     LocaleConfigService
117    * @param caService               CacheService
118    * @param dmsConfiguration        DMSConfiguration
119    * @throws Exception
120    */
121   public TemplateServiceImpl(RepositoryService jcrService,
122                              NodeHierarchyCreator nodeHierarchyCreator, IdentityRegistry identityRegistry,
123                              org.exoplatform.groovyscript.text.TemplateService templateService,
124                              DMSConfiguration dmsConfiguration, LocaleConfigService localeConfigService,
125                              CacheService caService) throws Exception {
126     identityRegistry_ = identityRegistry;
127     repositoryService_ = jcrService;
128     cmsTemplatesBasePath_ = nodeHierarchyCreator.getJcrPath(BasePath.CMS_TEMPLATES_PATH);
129     this.templateService = templateService;
130     dmsConfiguration_ = dmsConfiguration;
131     localeConfigService_ = localeConfigService;
132     nodeTypeListCached = caService.getCacheInstance(CACHE_NAME);
133   }
134 
135   /**
136    * {@inheritDoc}
137    */
138   public void start() {
139     configuredNodeTypes = new HashSet<String>();
140     try {
141       for (TemplatePlugin plugin : plugins_) {
142         plugin.init();
143         configuredNodeTypes.addAll(plugin.getAllConfiguredNodeTypes());
144       }
145 
146       // Cached all nodetypes that is document type in the map
147       getDocumentTemplates();
148     } catch (Exception e) {
149       if (LOG.isErrorEnabled()) {
150         LOG.error("An unexpected exception occurs when init plugins", e);
151       }
152     }
153   }
154 
155   /**
156    * {@inheritDoc}
157    */
158   public void stop() {
159   }
160 
161   /**
162    * {@inheritDoc}
163    */
164   public void addContentTypeFilterPlugin(ContentTypeFilterPlugin filterPlugin) {
165     HashMap<String,List<String>> folderFilterMap = foldersFilterMap;
166     if (folderFilterMap == null) {
167       folderFilterMap = new HashMap<String,List<String>>();
168     }
169     for (FolderFilterConfig filterConfig : filterPlugin.getFolderFilterConfigList()) {
170       String folderType = filterConfig.getFolderType();
171       List<String> contentTypes = filterConfig.getContentTypes();
172       List<String> value = folderFilterMap.get(folderType);
173       if (value == null) {
174         folderFilterMap.put(folderType, contentTypes);
175       } else {
176         value.addAll(contentTypes);
177         folderFilterMap.put(folderType, value);
178       }
179     }
180     foldersFilterMap = folderFilterMap;
181   }
182 
183   /**
184    * {@inheritDoc}
185    */
186   public Set<String> getAllowanceFolderType() {
187     HashMap<String, List<String>> map = foldersFilterMap;
188     if (map != null)
189       return map.keySet();
190     return null;
191   }
192 
193   /**
194    * {@inheritDoc}
195    */
196   public void addTemplates(ComponentPlugin plugin) {
197     if (plugin instanceof TemplatePlugin)
198       plugins_.add((TemplatePlugin) plugin);
199   }
200 
201   /**
202    * {@inheritDoc}
203    */
204   public void init() throws Exception {
205     for (TemplatePlugin plugin : plugins_) {
206       plugin.init();
207     }
208   }
209 
210   /**
211    * {@inheritDoc}
212    */
213   public Node getTemplatesHome(SessionProvider provider) throws Exception {
214     try {
215       Session session = getSession(provider);
216       return (Node) session.getItem(cmsTemplatesBasePath_);
217     } catch (AccessDeniedException ace) {
218       if (LOG.isErrorEnabled()) {
219         LOG.error("Access denied. You can not access to this template");
220       }
221       return null;
222     }
223   }
224 
225   /**
226    * {@inheritDoc}
227    */
228   public List<String> getCreationableContentTypes(Node node) throws Exception {
229     String folderType = node.getPrimaryNodeType().getName();
230     List<String> testContentTypes = null;
231     HashMap<String,List<String>> folderFilterMap = foldersFilterMap;
232     if (folderFilterMap != null) {
233       List<String> list = folderFilterMap.get(folderType);
234       if (list != null && list.size() != 0) {
235         testContentTypes = list;
236       }
237     }
238     if (testContentTypes == null) {
239       testContentTypes = getDocumentTemplates();
240     }
241     List<String> result = new ArrayList<String>();
242     for (String contentType : testContentTypes) {
243       if (isChildNodePrimaryTypeAllowed(node, contentType)) {
244         result.add(contentType);
245       }
246     }
247     return result;
248   }
249 
250   /**
251    * {@inheritDoc}
252    */
253   public boolean isChildNodePrimaryTypeAllowed(Node parent, String childNodeTypeName) throws Exception{
254     NodeType childNodeType = parent.getSession().getWorkspace().getNodeTypeManager().getNodeType(childNodeTypeName);
255     //In some cases, the child node is mixins type of a nt:file example
256     if(childNodeType.isMixin()) return true;
257     List<NodeType> allNodeTypes = new ArrayList<NodeType>();
258     allNodeTypes.add(parent.getPrimaryNodeType());
259     for(NodeType mixin: parent.getMixinNodeTypes()) {
260       allNodeTypes.add(mixin);
261     }
262     for (NodeType nodetype:allNodeTypes) {
263       if (((NodeTypeImpl)nodetype).isChildNodePrimaryTypeAllowed(
264                                                                  Constants.JCR_ANY_NAME,
265                                                                  ((NodeTypeImpl)childNodeType).getQName())) {
266         return true;
267       }
268     }
269     return false;
270   }
271 
272   /**
273    * {@inheritDoc}
274    */
275   public boolean isManagedNodeType(String nodeTypeName) throws RepositoryException {
276     //check if the node type is document type first
277     List<String> managedDocumentTypes = getManagedDocumentTypesMap();
278     if(managedDocumentTypes != null && managedDocumentTypes.contains(nodeTypeName))
279       return true;
280     SessionProvider provider = SessionProvider.createSystemProvider();
281     Session session = getSession(provider);
282     try {
283       Node systemTemplatesHome = (Node) session.getItem(cmsTemplatesBasePath_);
284       return systemTemplatesHome.hasNode(nodeTypeName);
285     } finally {
286       provider.close();
287     }
288   }
289 
290   /**
291    * {@inheritDoc}
292    */
293   public String getTemplatePath(Node node, boolean isDialog) throws Exception {
294     String userId = node.getSession().getUserID();
295     String templateType = null;
296     if (node.isNodeType("exo:presentationable") && node.hasProperty("exo:presentationType")) {
297       templateType = node.getProperty("exo:presentationType").getString();
298     } else if (node.isNodeType("nt:frozenNode")) {
299       templateType = node.getProperty("jcr:frozenPrimaryType").getString();
300     } else {
301       templateType = node.getPrimaryNodeType().getName();
302     }
303     if (isManagedNodeType(templateType)) {
304       return getTemplatePathByUser(isDialog, templateType, userId);
305     }
306 
307     // Check if node's nodetype or its supper type has managed template type
308     String managedTemplateType = getManagedTemplateType(node);
309     if (StringUtils.isNotEmpty(managedTemplateType)) {
310       return getTemplatePathByUser(isDialog, managedTemplateType, userId);
311     }
312 
313     throw new Exception("The content type: " + templateType + " isn't supported by any template");
314   }
315 
316   /**
317    * {@inheritDoc}
318    */
319   public NodeIterator getAllTemplatesOfNodeType(boolean isDialog, String nodeTypeName,
320                                                 SessionProvider provider) throws Exception {
321     Node nodeTypeHome = getTemplatesHome(provider).getNode(nodeTypeName);
322     if (isDialog) {
323       if(!nodeTypeHome.hasNode(DIALOGS)) return null;
324       return nodeTypeHome.getNode(DIALOGS).getNodes();
325     }
326     if(!nodeTypeHome.hasNode(VIEWS)) return null;
327     return nodeTypeHome.getNode(VIEWS).getNodes();
328   }
329 
330   /**
331    * {@inheritDoc}
332    */
333   public String getDefaultTemplatePath(boolean isDialog, String nodeTypeName) {
334     if (isDialog)
335       return cmsTemplatesBasePath_ + "/" + nodeTypeName + DEFAULT_DIALOGS_PATH;
336     return cmsTemplatesBasePath_ + "/" + nodeTypeName + DEFAULT_VIEWS_PATH;
337   }
338 
339   /**
340    * {@inheritDoc}
341    */
342   public Node getTemplateNode(String type, String nodeTypeName, String templateName,
343                               SessionProvider provider) throws Exception {
344     Node nodeTypeNode = getTemplatesHome(provider).getNode(nodeTypeName);
345     return nodeTypeNode.getNode(type).getNode(templateName);
346   }
347 
348   /**
349    * {@inheritDoc}
350    */
351   public String getTemplatePathByUser(boolean isDialog, String nodeTypeName, String userName) throws RepositoryException {
352     if(IdentityConstants.ANONIM.equals(userName) || DynamicIdentity.DYNAMIC.equals(userName) || userName == null) {
353       return getTemplatePathByAnonymous(isDialog, nodeTypeName);
354     }
355     Node templateHomeNode =
356         (Node) getSession(WCMCoreUtils.getSystemSessionProvider()).getItem(cmsTemplatesBasePath_);
357     String type = DIALOGS;
358     if (!isDialog)
359       type = VIEWS;
360     Node nodeTypeNode = templateHomeNode.getNode(nodeTypeName);
361     NodeIterator templateIter = nodeTypeNode.getNode(type).getNodes();
362     while (templateIter.hasNext()) {
363       Node node = templateIter.nextNode();
364       String roles = getTemplateRoles(node);
365       if(hasPermission(userName, roles, identityRegistry_)) {
366         String templatePath = node.getPath() ;
367         return templatePath ;
368       }
369     }
370     throw new AccessControlException("You don't have permission to access any template");
371   }
372 
373   /**
374    * {@inheritDoc}
375    */
376   public String getTemplatePath(boolean isDialog, String nodeTypeName, String templateName) throws Exception {
377     String type = DIALOGS;
378     if (!isDialog)
379       type = VIEWS;
380     Node templateNode = getTemplateNode(type, nodeTypeName, templateName);
381     String path = templateNode.getPath();
382     return path;
383   }
384 
385   /**
386    * {@inheritDoc}
387    */
388   public String getTemplateLabel(String nodeTypeName) throws Exception {
389     SessionProvider provider = SessionProvider.createSystemProvider();
390     try {
391       Node templateHome = getTemplatesHome(provider);
392       Node nodeType = templateHome.getNode(nodeTypeName);
393       if (nodeType.hasProperty("label")) {
394         return nodeType.getProperty("label").getString();
395       }
396     } finally {
397       provider.close();
398     }
399     return "";
400   }
401 
402   /**
403    * {@inheritDoc}
404    */
405   public String getTemplate(String type, String nodeTypeName, String templateName) throws Exception {
406     Node templateNode = getTemplateNode(type, nodeTypeName, templateName);
407     return getTemplate(templateNode);
408   }
409 
410   /**
411    * {@inheritDoc}
412    */
413   public void removeTemplate(String type, String nodeTypeName, String templateName) throws Exception {
414     Node templatesHome =
415         (Node) getSession(WCMCoreUtils.getSystemSessionProvider()).getItem(cmsTemplatesBasePath_);
416     Node nodeTypeHome = templatesHome.getNode(nodeTypeName);
417     Node specifiedTemplatesHome = nodeTypeHome.getNode(type);
418     Node contentNode = specifiedTemplatesHome.getNode(templateName);
419     contentNode.remove();
420     nodeTypeHome.save();
421 
422     // Update list of changed template node type list
423     addEditedConfiguredNodeType(nodeTypeName);
424   }
425 
426   /**
427    * {@inheritDoc}
428    */
429   public void removeManagedNodeType(String nodeTypeName) throws Exception {
430     Node templatesHome =
431         (Node) getSession(WCMCoreUtils.getSystemSessionProvider()).getItem(cmsTemplatesBasePath_);
432     Node managedNodeType = templatesHome.getNode(nodeTypeName);
433     managedNodeType.remove();
434     templatesHome.save();
435     //Update managedDocumentTypeMap
436     List<String> managedDocumentTypes = getManagedDocumentTypesMap();
437     managedDocumentTypes.remove(nodeTypeName);
438     removeTemplateNodeTypeList();
439 
440     // Add to edited predefined template node type list
441     addEditedConfiguredNodeType(nodeTypeName);
442   }
443 
444   /**
445    * {@inheritDoc}
446    */
447   public List<String> getDocumentTemplates() throws RepositoryException {
448     List<String> templates = getManagedDocumentTypesMap();
449     if (templates != null)
450       return new ArrayList<String>(templates);
451     templates = getAllDocumentNodeTypes();
452     setManagedDocumentTypesMap(templates);
453     return templates == null ? templates : new ArrayList<String>(templates);
454   }
455 
456   /**
457    * {@inheritDoc}
458    */
459   public String getTemplatePathByAnonymous(boolean isDialog, String nodeTypeName) throws RepositoryException {
460     String type = DIALOGS;
461     if (!isDialog)
462       type = VIEWS;
463     Node homeNode =
464         (Node) getSession(WCMCoreUtils.getSystemSessionProvider()).getItem(cmsTemplatesBasePath_);
465     Node nodeTypeNode = homeNode.getNode(nodeTypeName);
466     NodeIterator templateIter = nodeTypeNode.getNode(type).getNodes();
467     while (templateIter.hasNext()) {
468       Node node = templateIter.nextNode();
469       String role = getTemplateRoles(node);
470       if(hasPublicTemplate(role)) {
471         String templatePath = node.getPath() ;
472         return templatePath ;
473       }
474     }
475     return null;
476   }
477 
478   /**
479    * {@inheritDoc}
480    */
481   public void removeCacheTemplate(String name) throws Exception {
482     try {
483       templateService.reloadTemplate(name);
484     } catch (IllegalArgumentException e) {
485       return;
486     }
487   }
488 
489   /**
490    * {@inheritDoc}
491    */
492   public void removeAllTemplateCached() {
493     templateService.reloadTemplates();
494   }
495 
496   @SuppressWarnings("unchecked")
497   public List<String> getAllDocumentNodeTypes() throws PathNotFoundException, RepositoryException {
498     List<String> nodeTypeList = (List<String>) nodeTypeListCached.get(NODETYPE_LIST);
499     if(nodeTypeList != null && nodeTypeList.size() > 0)
500       return nodeTypeList;
501 
502     List<String> contentTypes = new ArrayList<String>();
503     SessionProvider sessionProvider = SessionProvider.createSystemProvider();
504     try {
505       Node templatesHome =
506           (Node) getSession(sessionProvider).getItem(cmsTemplatesBasePath_);
507       for (NodeIterator templateIter = templatesHome.getNodes(); templateIter.hasNext();) {
508         Node template = templateIter.nextNode();
509         if (template.getProperty(DOCUMENT_TEMPLATE_PROP).getBoolean())
510           contentTypes.add(template.getName());
511       }
512       nodeTypeListCached.put(NODETYPE_LIST, contentTypes);
513     } finally {
514       sessionProvider.close();
515     }
516     return contentTypes;
517   }
518 
519   /**
520    * {@inheritDoc}
521    */
522   public String getSkinPath(String nodeTypeName, String skinName, String locale) throws Exception {
523     Node homeNode =
524         (Node) getSession(WCMCoreUtils.getSystemSessionProvider()).getItem(cmsTemplatesBasePath_);
525     Node nodeTypeNode = homeNode.getNode(nodeTypeName);
526     Orientation orientation = getOrientation(locale);
527     String skinPath = null;
528     if(orientation.isLT()) {
529       StringBuilder templateData = new StringBuilder("/**");
530       templateData.append("LTR stylesheet for "+nodeTypeNode.getName()+" template").append("*/");
531       skinPath = addNewSkinNode(homeNode, nodeTypeNode, skinName, "-lt", templateData.toString());
532     } else if(orientation.isRT()) {
533       StringBuilder templateData = new StringBuilder("/**");
534       templateData.append("RTL stylesheet for "+nodeTypeNode.getName()+" template").append("*/");
535       skinPath = addNewSkinNode(homeNode, nodeTypeNode, skinName, "-rt", templateData.toString());
536     }
537     return skinPath;
538   }
539 
540   /**
541    * {@inheritDoc}
542    */
543   public String buildDialogForm(String nodeTypeName) throws Exception {
544     if (plugins_ == null || plugins_.size() == 0) {
545       throw new Exception("Cannot find plugin for template");
546     }
547     TemplatePlugin templatePlugin = plugins_.get(0);
548     ManageableRepository manageRepo = repositoryService_.getCurrentRepository();
549     NodeType nodeType = manageRepo.getNodeTypeManager().getNodeType(nodeTypeName);
550     return templatePlugin.buildDialogForm(nodeType);
551   }
552 
553   /**
554    * {@inheritDoc}
555    */
556   public String buildViewForm(String nodeTypeName) throws Exception {
557     if (plugins_ == null || plugins_.size() == 0) {
558       throw new Exception("Cannot find plugin for template");
559     }
560     TemplatePlugin templatePlugin = plugins_.get(0);
561     ManageableRepository manageRepo = repositoryService_.getCurrentRepository();
562     NodeType nodeType = manageRepo.getNodeTypeManager().getNodeType(nodeTypeName);
563     return templatePlugin.buildViewForm(nodeType);
564   }
565 
566   /**
567    * {@inheritDoc}
568    */
569   public String buildStyleSheet(String nodeTypeName) throws Exception {
570     if (plugins_ == null || plugins_.size() == 0) {
571       throw new Exception("Cannot find plugin for template");
572     }
573     TemplatePlugin templatePlugin = plugins_.get(0);
574     return templatePlugin.buildStyleSheet(null);
575   }
576 
577   /**
578    * Get template with the following specified params
579    * @param session         Session
580    * @param templateType    String
581    *                        The value of template type
582    * @param nodeTypeName    String
583    *                        The name of NodeType
584    * @param templateName    String
585    *                        The name of template
586    * @param repository      String
587    *                        The name of repository
588    * @return
589    * @throws Exception
590    */
591   private Node getTemplateNode(String type, String nodeTypeName,
592                                String templateName) throws Exception {
593     Node homeNode = (Node) getSession(WCMCoreUtils.getSystemSessionProvider()).getItem(cmsTemplatesBasePath_);
594     Node nodeTypeNode = homeNode.getNode(nodeTypeName);
595     return nodeTypeNode.getNode(type).getNode(templateName);
596   }
597 
598   /**
599    * Get content of the specified node
600    * @param isDialog              boolean
601    * @param templatesHome         Node
602    * @param nodeTypeName          String
603    *                              The name of NodeType
604    * @param label                 String
605    *                              The label of template
606    * @param isDocumentTemplate    boolean
607    * @param templateName          String
608    *                              The name of template
609    * @see                         Node
610    * @return
611    * @throws Exception
612    */
613   private String getContentNode(String templateType,
614                                 Node templatesHome,
615                                 String nodeTypeName,
616                                 String label,
617                                 boolean isDocumentTemplate,
618                                 String templateName,
619                                 String[] roles,
620                                 InputStream templateFile) throws Exception {
621     Node nodeTypeHome = null;
622     if (!templatesHome.hasNode(nodeTypeName)) {
623       nodeTypeHome = Utils.makePath(templatesHome, nodeTypeName, NT_UNSTRUCTURED);
624       if (isDocumentTemplate) {
625         nodeTypeHome.setProperty(DOCUMENT_TEMPLATE_PROP, true);
626       } else
627         nodeTypeHome.setProperty(DOCUMENT_TEMPLATE_PROP, false);
628       nodeTypeHome.setProperty(TEMPLATE_LABEL, label);
629     } else {
630       nodeTypeHome = templatesHome.getNode(nodeTypeName);
631     }
632     Node specifiedTemplatesHome = null;
633     try {
634       specifiedTemplatesHome = nodeTypeHome.getNode(templateType);
635     } catch(PathNotFoundException e) {
636       specifiedTemplatesHome = Utils.makePath(nodeTypeHome, templateType, NT_UNSTRUCTURED);
637     }
638     String templatePath = null;
639     if (specifiedTemplatesHome.hasNode(templateName)) {
640       templatePath = specifiedTemplatesHome.getNode(templateName).getPath();
641     } else {
642       templatePath = createTemplate(specifiedTemplatesHome, templateName, templateFile, roles);
643     }
644     templatesHome.save();
645     templatesHome.getSession().save();
646     return templatePath;
647   }
648 
649   /**
650    * Update document template
651    * @param isDocumentTemplate    boolean
652    * @param nodeTypeName          String
653    *                              The name of NodeType
654    * @throws RepositoryException
655    * @see                         Node
656    * @see                         NodeType
657    */
658   private void updateDocumentsTemplate(boolean isDocumentTemplate, String nodeTypeName) throws RepositoryException{
659     if(isDocumentTemplate) {
660       List<String> documentList = getManagedDocumentTypesMap();
661       if(documentList == null) {
662         documentList = new ArrayList<String>();
663         documentList.add(nodeTypeName);
664         setManagedDocumentTypesMap(documentList);
665       } else {
666         if(!documentList.contains(nodeTypeName)) {
667           documentList.add(nodeTypeName);
668           setManagedDocumentTypesMap(documentList);
669         }
670       }
671     }
672   }
673 
674   /**
675    * Return session of the specified repository
676    * @param provider        SessionProvider
677    * @return
678    * @throws RepositoryException
679    * @see                   SessionProvider
680    * @see                   ManageableRepository
681    * @see                   DMSRepositoryConfiguration
682    * @throws Exception
683    */
684   private Session getSession(SessionProvider provider) throws RepositoryException {
685     ManageableRepository manageableRepository = repositoryService_.getCurrentRepository();
686     DMSRepositoryConfiguration dmsRepoConfig = dmsConfiguration_.getConfig();
687     return provider.getSession(dmsRepoConfig.getSystemWorkspace(), manageableRepository);
688   }
689 
690   /**
691    * Check permission of the user with roles
692    * @param userId              String
693    *                            The specified user
694    * @param roles               Value[]
695    * @param identityRegistry    IdentityRegistry
696    * @see                       MembershipEntry
697    * @see                       IdentityRegistry
698    * @return
699    */
700   private boolean hasPermission(String userId, String roles, IdentityRegistry identityRegistry) {
701     if(IdentityConstants.SYSTEM.equalsIgnoreCase(userId)) {
702       return true ;
703     }
704     Identity identity = identityRegistry.getIdentity(userId) ;
705     if(identity == null) {
706       return false ;
707     }
708     String[] listRoles = roles.split(",");
709     for (int i = 0; i < listRoles.length; i++) {
710       String role = listRoles[i].trim();
711       if("*".equalsIgnoreCase(role)) return true ;
712       MembershipEntry membershipEntry = MembershipEntry.parse(role) ;
713       if(identity.isMemberOf(membershipEntry)) {
714         return true ;
715       }
716     }
717     return false ;
718   }
719 
720   /**
721    * Check public template with the roles
722    * @param roles         Value[]
723    * @return
724    */
725   private boolean hasPublicTemplate(String role) {
726     String[] roles = role.split("; ");
727     for (int i = 0; i < roles.length; i++) {
728       if("*".equalsIgnoreCase(roles[i])) return true ;
729     }
730     return false ;
731   }
732 
733   /**
734    * Get orientation of current locate
735    * @param locale      String
736    *                    The locale name which specified by user
737    * @return
738    * @throws Exception
739    */
740   private Orientation getOrientation(String locale) throws Exception {
741     return localeConfigService_.getLocaleConfig(locale).getOrientation();
742   }
743 
744   /**
745    * Add new skin node if the locale specified is not existing
746    * @param templatesHome
747    * @param nodeTypeNode
748    * @param skinName
749    * @param orientation
750    * @param templateData
751    * @return
752    * @throws Exception
753    */
754   private String addNewSkinNode(Node templatesHome,
755                                 Node nodeTypeNode,
756                                 String skinName,
757                                 String orientation,
758                                 String templateData) throws Exception {
759     String label = nodeTypeNode.getProperty(TEMPLATE_LABEL).getString();
760     return getContentNode(SKINS, templatesHome, nodeTypeNode.getName(), label, true, skinName
761                           + orientation, new String[] { "*" }, new ByteArrayInputStream(templateData.getBytes()));
762   }
763 
764   private void removeTemplateNodeTypeList() throws Exception {
765     nodeTypeListCached.clearCache();
766   }
767 
768   /**
769    * {@inheritDoc}
770    */
771   public String addTemplate(String templateType,
772                             String nodeTypeName,
773                             String label,
774                             boolean isDocumentTemplate,
775                             String templateName,
776                             String[] roles,
777                             InputStream templateFile) throws Exception {
778     Session session = getSession(WCMCoreUtils.getSystemSessionProvider());
779     Node templatesHome = (Node) session.getItem(cmsTemplatesBasePath_);
780     String templatePath = null;
781     try {
782       templatePath = templatesHome.getPath() + "/" + nodeTypeName + "/" + templateType + "/" + templateName;
783       Node templateNode = (Node)session.getItem(templatePath);
784       DocumentContext.getCurrent().getAttributes().put(DocumentContext.IS_SKIP_RAISE_ACT, true);
785       updateTemplate(templateNode,templateFile, roles);
786       session.save();
787     } catch(PathNotFoundException e) {
788       DocumentContext.getCurrent().getAttributes().put(DocumentContext.IS_SKIP_RAISE_ACT, true);
789       templatePath = getContentNode(templateType, templatesHome, nodeTypeName, label,
790                                     isDocumentTemplate, templateName, roles, templateFile);
791     }
792     //Update managedDocumentTypesMap
793     removeCacheTemplate(templatePath);
794     removeTemplateNodeTypeList();
795     updateDocumentsTemplate(isDocumentTemplate, nodeTypeName);
796     return templatePath;
797   }
798 
799   /**
800    * {@inheritDoc}
801    */
802   public String addTemplate(String templateType,
803                             String nodeTypeName,
804                             String label,
805                             boolean isDocumentTemplate,
806                             String templateName,
807                             String[] roles,
808                             InputStream templateFile,
809                             Node templatesHome) throws Exception {
810     String templatePath = null;
811     try {
812       templatePath = templatesHome.getPath() + "/" + nodeTypeName + "/" + templateType + "/" + templateName;
813       Node templateNode = (Node)templatesHome.getSession().getItem(templatePath);
814       updateTemplate(templateNode,templateFile, roles);
815       templateNode.save();
816     } catch(PathNotFoundException e) {
817       templatePath = getContentNode(templateType, templatesHome, nodeTypeName, label,
818                                     isDocumentTemplate, templateName, roles, templateFile);
819     }
820     // Update managedDocumentTypesMap
821     removeCacheTemplate(templatePath);
822     removeTemplateNodeTypeList();
823     return templatePath;
824   }
825 
826   /**
827    * {@inheritDoc}
828    */
829   @Deprecated
830   public String createTemplate(Node templateFolder, String name, InputStream data, String[] roles) {
831     return createTemplate(templateFolder, name, name, data, roles);
832   }
833 
834   /**
835    * {@inheritDoc}
836    */
837   public String createTemplate(Node templateFolder, String title, String templateName, InputStream data, String[] roles) {
838     try {
839       Node contentNode = templateFolder.addNode(templateName, NodetypeConstant.NT_FILE);
840       Node resourceNode = contentNode.addNode(NodetypeConstant.JCR_CONTENT, NodetypeConstant.EXO_RESOURCES);
841       resourceNode.setProperty(NodetypeConstant.JCR_ENCODING, "UTF-8");
842       resourceNode.setProperty(NodetypeConstant.JCR_MIME_TYPE, "application/x-groovy+html");
843       resourceNode.setProperty(NodetypeConstant.JCR_LAST_MODIFIED, new GregorianCalendar());
844       resourceNode.setProperty(NodetypeConstant.JCR_DATA, data);
845       if(!Arrays.equals(roles, getRoleNode(resourceNode))){
846         resourceNode.setProperty(NodetypeConstant.EXO_ROLES, roles);
847       }
848       if(!resourceNode.isNodeType(NodetypeConstant.DC_ELEMENT_SET)) {
849         resourceNode.addMixin(NodetypeConstant.DC_ELEMENT_SET);
850       }
851       resourceNode.setProperty(NodetypeConstant.DC_TITLE, new String[] {title});
852       resourceNode.getSession().save();
853       return contentNode.getPath();
854     } catch (Exception e) {
855       if (LOG.isErrorEnabled()) {
856         LOG.error("An error has been occurred when adding template", e);
857       }
858     }
859     return null;
860   }
861 
862   /**
863    * Get string array exo:roles of node
864    * @param node
865    * @return
866    */
867   private String[] getRoleNode(Node node){
868     try {
869       Value[] values = node.getProperty(NodetypeConstant.EXO_ROLES).getValues();
870       StringBuffer roles = new StringBuffer();
871       for (int i = 0; i < values.length; i++) {
872         if (roles.length() > 0)
873           roles.append(";");
874         roles.append(values[i].getString());
875       }
876       return roles.toString().split(";");
877     }catch (RepositoryException re){
878       LOG.warn("Unable get role of node ", re);
879     }
880     return null;
881   }
882 
883   /**
884    * {@inheritDoc}
885    */
886   public String updateTemplate(Node template, InputStream data, String[] roles) {
887     try {
888       Node resourceNode = template.getNode(NodetypeConstant.JCR_CONTENT);
889       resourceNode.setProperty(NodetypeConstant.EXO_ROLES, roles);
890       resourceNode.setProperty(NodetypeConstant.JCR_LAST_MODIFIED, new GregorianCalendar());
891       resourceNode.setProperty(NodetypeConstant.JCR_DATA, data);
892       resourceNode.getSession().save();
893 
894       // Add to edited predefined node type list
895       addEditedConfiguredNodeType(template.getParent().getParent().getName());
896       return template.getPath();
897     } catch (Exception e) {
898       if (LOG.isErrorEnabled()) {
899         LOG.error("An error has been occurred when updating template", e);
900       }
901     }
902     return null;
903   }
904 
905   /**
906    * {@inheritDoc}
907    */
908   public String getTemplate(Node template) {
909     Node resourceNode;
910     try {
911       resourceNode = template.getNode(NodetypeConstant.JCR_CONTENT);
912       return resourceNode.getProperty(NodetypeConstant.JCR_DATA).getString();
913     } catch (ValueFormatException e) {
914       if (LOG.isErrorEnabled()) {
915         LOG.error("Wrong Value format ", e);
916       }
917     } catch (PathNotFoundException e) {
918       if (LOG.isErrorEnabled()) {
919         LOG.error("Can not found the template because of: ", e);
920       }
921     } catch (RepositoryException e) {
922       if (LOG.isErrorEnabled()) {
923         LOG.error("Repository failed ", e);
924       }
925     }
926     return null;
927   }
928 
929   /**
930    * {@inheritDoc}
931    */
932   public String getTemplateRoles(Node template) {
933     try {
934       Value[] values = template.getNode("jcr:content").getProperty(NodetypeConstant.EXO_ROLES).getValues();
935       StringBuffer roles = new StringBuffer();
936       for (int i = 0; i < values.length; i++) {
937         if (roles.length() > 0)
938           roles.append("; ");
939         roles.append(values[i].getString());
940       }
941       return roles.toString();
942     } catch (Exception e) {
943       if (LOG.isErrorEnabled()) {
944         LOG.error("An error has been occurred when getting template's roles", e);
945       }
946     }
947     return null;
948   }
949 
950   private String getRepoName() throws RepositoryException{
951     String repositoryName = repositoryService_.getCurrentRepository().getConfiguration().getName();
952     return repositoryName;
953   }
954 
955   private List<String> getManagedDocumentTypesMap() throws RepositoryException{
956     return managedDocumentTypesMap.get(getRepoName());
957   }
958 
959   private void setManagedDocumentTypesMap(List<String> types) throws RepositoryException{
960     managedDocumentTypesMap.put(getRepoName(), types);
961   }
962 
963   public Set<String> getAllConfiguredNodeTypes() {
964     return configuredNodeTypes;
965   }
966 
967   public Set<String> getAllEditedConfiguredNodeTypes() throws Exception {
968     return Utils.getAllEditedConfiguredData(this.getClass().getSimpleName(), EDITED_CONFIGURED_NODE_TYPES, true);
969   }
970 
971   private void addEditedConfiguredNodeType(String nodeType) throws Exception {
972     Utils.addEditedConfiguredData(nodeType, this.getClass().getSimpleName(), EDITED_CONFIGURED_NODE_TYPES, true);
973   }
974 
975   /**
976    * Check if node's nodetype or its supper type has managed template type and return the template type.
977    *
978    * @param node
979    * @return managed template type. Null value mean not exist template
980    * @throws Exception
981    */
982   private String getManagedTemplateType(Node node) throws Exception {
983     // Check if the node type is document type first
984     List<String> managedDocumentTypes = getManagedDocumentTypesMap();
985     for (String documentType : managedDocumentTypes) {
986       if (node.getPrimaryNodeType().isNodeType(documentType)) {
987         return documentType;
988       }
989     }
990 
991     // Check if node's nodetype or its supper type has managed template type
992     SessionProvider provider = WCMCoreUtils.getSystemSessionProvider();
993     Session session = getSession(provider);
994     Node systemTemplatesHome = (Node) session.getItem(cmsTemplatesBasePath_);
995     NodeIterator templatesIter = systemTemplatesHome.getNodes();
996     while(templatesIter.hasNext()) {
997       String templateName = templatesIter.nextNode().getName();
998       if (node.getPrimaryNodeType().isNodeType(templateName)) {
999         return templateName;
1000       }
1001     }
1002 
1003     return null;
1004   }
1005 }