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.impl;
18  
19  import java.io.ByteArrayInputStream;
20  import java.io.InputStream;
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.Collections;
24  import java.util.GregorianCalendar;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Set;
31  
32  import javax.jcr.Node;
33  import javax.jcr.NodeIterator;
34  import javax.jcr.PathNotFoundException;
35  import javax.jcr.Property;
36  import javax.jcr.PropertyIterator;
37  import javax.jcr.PropertyType;
38  import javax.jcr.RepositoryException;
39  import javax.jcr.Session;
40  import javax.jcr.Value;
41  import javax.jcr.ValueFormatException;
42  import javax.jcr.Workspace;
43  import javax.jcr.nodetype.NodeDefinition;
44  import javax.jcr.nodetype.NodeType;
45  import javax.jcr.nodetype.NodeTypeManager;
46  import javax.jcr.nodetype.PropertyDefinition;
47  
48  import org.apache.commons.lang.ArrayUtils;
49  import org.apache.commons.lang.StringUtils;
50  import org.apache.commons.lang.Validate;
51  import org.exoplatform.commons.utils.ISO8601;
52  import org.exoplatform.ecm.utils.text.Text;
53  import org.exoplatform.services.cms.CmsService;
54  import org.exoplatform.services.cms.JcrInputProperty;
55  import org.exoplatform.services.cms.jcrext.activity.ActivityCommonService;
56  import org.exoplatform.services.cms.link.LinkManager;
57  import org.exoplatform.services.idgenerator.IDGeneratorService;
58  import org.exoplatform.services.jcr.RepositoryService;
59  import org.exoplatform.services.jcr.impl.core.NodeImpl;
60  import org.exoplatform.services.jcr.impl.core.nodetype.ItemDefinitionImpl;
61  import org.exoplatform.services.listener.ListenerService;
62  import org.exoplatform.services.log.ExoLogger;
63  import org.exoplatform.services.log.Log;
64  import org.exoplatform.services.wcm.core.NodetypeConstant;
65  import org.exoplatform.services.wcm.utils.WCMCoreUtils;
66  
67  
68  /**
69   * @author benjaminmestrallet
70   */
71  public class CmsServiceImpl implements CmsService {
72  
73    private RepositoryService jcrService;
74    private IDGeneratorService idGeneratorService;
75    private static final String MIX_REFERENCEABLE = "mix:referenceable" ;
76    private static final Log LOG  = ExoLogger.getLogger(CmsServiceImpl.class.getName());
77    private ListenerService listenerService;
78    private ActivityCommonService activityService = null;
79  
80    public static Map<String, Object> properties = new HashMap<String, Object>();  
81    public Map<String, Object> getPreProperties() { return properties; }  
82  
83    /**
84     * Method constructor
85     * @param jcrService: Manage repository
86     * @param idGeneratorService: Generate an identify string
87     * @param listenerService: Register listener, broadcast some event after create/edit node
88     */
89    public CmsServiceImpl(RepositoryService jcrService, IDGeneratorService idGeneratorService, ListenerService listenerService) {
90      this.idGeneratorService = idGeneratorService;
91      this.jcrService = jcrService;
92      this.listenerService = listenerService;
93    }
94  
95    /**
96     * {@inheritDoc}
97     */
98    @Override
99    public String storeNode(String workspace, String nodeTypeName, String storePath, Map mappings) throws Exception {
100     Session session = jcrService.getCurrentRepository().login(workspace);
101     Node storeHomeNode = (Node) session.getItem(storePath);
102     String path = storeNode(nodeTypeName, storeHomeNode, mappings, true);
103     storeHomeNode.save();
104     session.logout();
105     return path;
106   }
107 
108   /**
109    * {@inheritDoc}
110    */
111   @Override
112   public String storeNode(String nodeTypeName, Node storeHomeNode, Map mappings,
113                           boolean isAddNew) throws Exception {
114     Set keys = mappings.keySet();
115     String nodePath = extractNodeName(keys);
116     JcrInputProperty relRootProp = (JcrInputProperty) mappings.get(nodePath);
117     String nodeName = (String)relRootProp.getValue();
118     if (nodeName == null || nodeName.length() == 0) {
119       nodeName = idGeneratorService.generateStringID(nodeTypeName);
120     }
121     nodeName = Text.escapeIllegalJcrChars(nodeName);
122     String primaryType = relRootProp.getNodetype() ;
123     if(primaryType == null || primaryType.length() == 0) {
124       primaryType = nodeTypeName ;
125     }
126     Session session = storeHomeNode.getSession();
127     NodeTypeManager nodetypeManager = session.getWorkspace().getNodeTypeManager();
128     NodeType nodeType = nodetypeManager.getNodeType(primaryType);
129     Node currentNode = null;
130     String[] mixinTypes = null ;
131     String mixintypeName = relRootProp.getMixintype();
132     if(mixintypeName != null && mixintypeName.trim().length() > 0) {
133       if(mixintypeName.indexOf(",") > -1){
134         mixinTypes = mixintypeName.split(",") ;
135       }else {
136         mixinTypes = new String[] {mixintypeName} ;
137       }
138     }
139     if (activityService==null) {
140       activityService = WCMCoreUtils.getService(ActivityCommonService.class);
141     }
142     if (isAddNew) {
143       //Broadcast CmsService.event.preCreate event
144       listenerService.broadcast(PRE_CREATE_CONTENT_EVENT,storeHomeNode,mappings);
145       currentNode = storeHomeNode.addNode(nodeName, primaryType);
146       activityService.setCreating(currentNode, true);
147       createNodeRecursively(NODE, currentNode, nodeType, mappings);
148       createNodeRecursively(NODE, currentNode, nodetypeManager.getNodeType("exo:sortable"), mappings);
149 
150       if(mixinTypes != null){
151         for(String type : mixinTypes){
152           if(!currentNode.isNodeType(type)) {
153             currentNode.addMixin(type);
154           }
155           NodeType mixinType = nodetypeManager.getNodeType(type);
156           for (Iterator<String> iter = keys.iterator(); iter.hasNext();) {
157             String keyJCRPath = (String) iter.next();
158             JcrInputProperty jcrInputProperty = (JcrInputProperty) mappings.get(keyJCRPath);
159             if (!jcrInputProperty.getJcrPath().equals(NODE)) {
160               String inputMixinTypeName = jcrInputProperty.getMixintype();
161               String[] inputMixinTypes = null ;
162               if(inputMixinTypeName != null && inputMixinTypeName.trim().length() > 0) {
163                 if(inputMixinTypeName.indexOf(",") > -1){
164                   inputMixinTypes = inputMixinTypeName.split(",");
165                 }else {
166                   inputMixinTypes = new String[] {inputMixinTypeName};
167                 }
168               }
169               if (inputMixinTypes != null) {
170                 for(String inputType : inputMixinTypes) {
171                   if (inputType.equals(type)) {
172                     String childPath = jcrInputProperty.getJcrPath().replaceAll(NODE + "/", "");
173                     if (currentNode.hasNode(childPath)) {
174                       createNodeRecursively(jcrInputProperty.getJcrPath(), currentNode.getNode(childPath), mixinType, mappings);
175                     }
176                   }
177                 }
178               }
179             }
180           }
181           createNodeRecursively(NODE, currentNode, mixinType, mappings);
182         }
183       }
184       //all document node should be mix:referenceable that allow retrieve UUID by method Node.getUUID()
185       if(!currentNode.isNodeType(MIX_REFERENCEABLE)) {
186         currentNode.addMixin(MIX_REFERENCEABLE);
187       }      
188       //Broadcast CmsService.event.postCreate event
189       listenerService.broadcast(POST_CREATE_CONTENT_EVENT,this,currentNode);
190     } else {
191       currentNode = storeHomeNode.getNode(nodeName);
192       activityService.setEditing(currentNode, true);
193 
194       //Broadcast CmsService.event.preEdit event
195       listenerService.broadcast(PRE_EDIT_CONTENT_EVENT,currentNode,mappings);
196 
197       updateNodeRecursively(NODE, currentNode, nodeType, mappings);
198       if (currentNode.isNodeType("exo:datetime")) {
199         currentNode.setProperty("exo:dateModified", new GregorianCalendar());
200       }
201       listenerService.broadcast(POST_EDIT_CONTENT_EVENT, this, currentNode);
202 
203     }
204 
205     activityService.setCreating(currentNode, false);
206 
207     //
208     if (currentNode.isNodeType(ActivityCommonService.MIX_COMMENT)) {
209       currentNode.setProperty(ActivityCommonService.MIX_COMMENT_ACTIVITY_ID, StringUtils.EMPTY);
210     }
211 
212     storeHomeNode.save();
213     return currentNode.getPath();
214   }
215 
216   /**
217    * {@inheritDoc}
218    */
219   public String storeEditedNode(String nodeTypeName, Node storeNode, Map mappings,
220                                 boolean isAddNew) throws Exception {
221     Set keys = mappings.keySet();
222     String nodePath = extractNodeName(keys);
223     JcrInputProperty relRootProp = (JcrInputProperty) mappings.get(nodePath);
224 
225     String primaryType = relRootProp.getNodetype() ;
226     if(primaryType == null || primaryType.length() == 0) {
227       primaryType = nodeTypeName ;
228     }
229     Session session = storeNode.getSession();
230     NodeTypeManager nodetypeManager = session.getWorkspace().getNodeTypeManager();
231     NodeType nodeType = nodetypeManager.getNodeType(primaryType);
232 
233     //Broadcast CmsService.event.preEdit event
234     listenerService.broadcast(PRE_EDIT_CONTENT_EVENT,storeNode,mappings);
235     updateNodeRecursively(NODE, storeNode, nodeType, mappings);
236     if (storeNode.isNodeType("exo:datetime")) {
237       storeNode.setProperty("exo:dateModified", new GregorianCalendar());
238     }
239     listenerService.broadcast(POST_EDIT_CONTENT_EVENT, this, storeNode);
240     //add lastModified property to jcr:content
241     storeNode.save();
242     return storeNode.getPath();
243   }
244 
245   /**
246    * {@inheritDoc}
247    */
248   @Override
249   public String storeNodeByUUID(String nodeTypeName, Node storeHomeNode, Map mappings,
250                                 boolean isAddNew) throws Exception {
251     Set keys = mappings.keySet();
252     String nodePath = extractNodeName(keys);
253     JcrInputProperty relRootProp = (JcrInputProperty) mappings.get(nodePath);
254     String nodeName = (String)relRootProp.getValue();
255     if (nodeName == null || nodeName.length() == 0) {
256       nodeName = idGeneratorService.generateStringID(nodeTypeName);
257     }
258     String primaryType = relRootProp.getNodetype() ;
259     if(primaryType == null || primaryType.length() == 0) {
260       primaryType = nodeTypeName ;
261     }
262     Session session = storeHomeNode.getSession();
263     NodeTypeManager nodetypeManager = session.getWorkspace().getNodeTypeManager();
264     NodeType nodeType = nodetypeManager.getNodeType(primaryType);
265     Node currentNode = null;
266     String[] mixinTypes = null ;
267     String mixintypeName = relRootProp.getMixintype();
268     if(mixintypeName != null && mixintypeName.trim().length() > 0) {
269       if(mixintypeName.indexOf(",") > -1){
270         mixinTypes = mixintypeName.split(",") ;
271       }else {
272         mixinTypes = new String[] {mixintypeName} ;
273       }
274     }
275     String currentNodePath;
276     if (isAddNew) {
277       //Broadcast CmsService.event.preCreate event
278       listenerService.broadcast(PRE_CREATE_CONTENT_EVENT,storeHomeNode,mappings);
279       currentNode = storeHomeNode.addNode(nodeName, primaryType);
280       currentNodePath = currentNode.getPath();
281       if(mixinTypes != null){
282         for(String type : mixinTypes){
283           if(!currentNode.isNodeType(type)) {
284             currentNode.addMixin(type);
285           }
286           NodeType mixinType = nodetypeManager.getNodeType(type);
287           createNodeRecursively(NODE, currentNode, mixinType, mappings);
288         }
289       }
290       createNodeRecursively(NODE, currentNode, nodeType, mappings);
291       if(!currentNode.isNodeType(MIX_REFERENCEABLE)) {
292         currentNode.addMixin(MIX_REFERENCEABLE) ;
293       }
294       //Broadcast CmsService.event.postCreate event
295       listenerService.broadcast(POST_CREATE_CONTENT_EVENT,this,currentNode);
296     } else {
297       currentNode = storeHomeNode.getNode(nodeName);
298       currentNodePath = currentNode.getPath();
299       updateNodeRecursively(NODE, currentNode, nodeType, mappings);
300       if(currentNode.isNodeType("exo:datetime")) {
301         currentNode.setProperty("exo:dateModified",new GregorianCalendar()) ;
302       }
303       listenerService.broadcast(POST_EDIT_CONTENT_EVENT, this, currentNode);
304     }
305     //check if currentNode has been moved
306     if (currentNode instanceof NodeImpl && !((NodeImpl)currentNode).isValid()) {
307       currentNode = (Node)session.getItem(currentNodePath);
308       LinkManager linkManager = WCMCoreUtils.getService(LinkManager.class);
309       if (linkManager.isLink(currentNode)) {
310         try {
311           currentNode = linkManager.getTarget(currentNode, false);
312         } catch (Exception ex) {
313           currentNode = linkManager.getTarget(currentNode, true);
314         }
315       }
316     }
317 
318     String uuid = currentNode.getUUID();
319     storeHomeNode.save();
320     return uuid;
321   }
322 
323   /**
324    * Call function processNodeRecursively() to update property for specific node and all its children
325    * @param path            Path to node
326    * @param currentNode     Node is updated
327    * @param currentNodeType Node type
328    * @param jcrVariables    Mapping key = property name and value
329    * @throws Exception
330    * @see {@link #processNodeRecursively(boolean, String, Node, NodeType, Map)}
331    */
332   private void updateNodeRecursively(String path, Node currentNode, NodeType currentNodeType, Map jcrVariables) throws Exception {
333     processNodeRecursively(false, path, currentNode, currentNodeType, jcrVariables);
334   }
335 
336   /**
337    * Call function processNodeRecursively() to add property for specific node and all its children
338    * @param path            Path to node
339    * @param currentNode     Node is updated
340    * @param currentNodeType Node type
341    * @param jcrVariables    Mapping key = property name and value
342    * @throws Exception
343    * @see {@link #processNodeRecursively(boolean, String, Node, NodeType, Map)}
344    */
345   private void createNodeRecursively(String path, Node currentNode,
346                                      NodeType currentNodeType, Map jcrVariables) throws Exception {
347     processNodeRecursively(true, path, currentNode, currentNodeType,
348                            jcrVariables);
349   }
350 
351   /**
352    * Check to set value for a property with definition is autocreated
353    * @param propertyDef PropertyDefinition
354    * @param path String
355    * @param jcrVariables Map of properties
356    * @return Boolean
357    */
358   private boolean isAcceptSetValueForAutoCreated(PropertyDefinition propertyDef, String path,
359                                                  Map jcrVariables) {
360     if(propertyDef.isAutoCreated()) {
361       String propertyName = propertyDef.getName();
362       String currentPath = path + "/" + propertyName;
363       JcrInputProperty inputVariable = (JcrInputProperty) jcrVariables.get(currentPath) ;
364       if(inputVariable != null && inputVariable.getValue() != null) {
365         return true;
366       }
367       return false;
368     }
369     return true;
370   }
371 
372   /**
373    * Add property for current node when create variable = true
374    * Value of property is got in Map jcrVariabes by key = path + / property name
375    * @param create          create = true or false
376    * @param currentNode     Node is updated
377    * @param currentNodeType Node type
378    * @param jcrVariables    Mapping key = property name and value
379    * @throws Exception
380    * @see {@link #processProperty(String, Node, int, Object, boolean)}
381    */
382   private void processAddEditProperty(boolean create, Node currentNode, String path,
383                                       NodeType currentNodeType, Map jcrVariables) throws Exception {
384     if(create) {
385       PropertyDefinition[] propertyDefs = currentNodeType.getPropertyDefinitions();
386       for (int i = 0; i < propertyDefs.length; i++) {
387         PropertyDefinition propertyDef = propertyDefs[i];
388         if (isAcceptSetValueForAutoCreated(propertyDef, path, jcrVariables) &&
389             !propertyDef.isProtected()) {
390           String propertyName = propertyDef.getName();
391           int requiredtype = propertyDef.getRequiredType();
392           String currentPath = path + "/" + propertyName;
393           JcrInputProperty inputVariable = (JcrInputProperty) jcrVariables.get(currentPath) ;
394           Object value = null;
395           if(inputVariable != null) {
396             value = inputVariable.getValue();
397           }
398           if((value != null) || propertyDef.isMandatory()) {
399             processProperty(propertyName, currentNode, requiredtype, value, propertyDef.isMultiple());
400           }
401         }
402       }
403 
404       //process multiple binary data
405       for (Object key : jcrVariables.keySet()) {
406         Object value = jcrVariables.get(key);
407         if (((JcrInputProperty)value).getValue() instanceof Map) {
408           processProperty(key.toString().substring(path.length() + 1), currentNode,
409                           PropertyType.BINARY, ((JcrInputProperty)value).getValue(), true);
410         }
411       }
412     }
413   }
414 
415   /**
416    * Process to update or add property for current node and all its property
417    * Properties of node is given in current NodeType
418    * To add/update property of all node, need check that property is created automatically or protected
419    * When property is not created automatically and not protected then update for all child of node
420    * @param create          create = true: process adding, create = false, process updating
421    * @param itemPath        used with property name as key to get value of one property
422    * @param currentNode     Node is updated
423    * @param currentNodeType Node type
424    * @param jcrVariables    Mapping key = property name and value
425    * @throws Exception
426    */
427   @SuppressWarnings("unchecked")
428   private void processNodeRecursively(boolean create, String itemPath,
429                                       Node currentNode, NodeType currentNodeType, Map jcrVariables)
430                                           throws Exception {
431     if(create) {
432       processAddEditProperty(true, currentNode, itemPath, currentNodeType, jcrVariables) ;
433     } else {
434       List<String> keyList = new ArrayList<String>();
435       for(Object key : jcrVariables.keySet()) {
436         keyList.add(key.toString().substring(key.toString().lastIndexOf("/") + 1));
437       }
438       List<String> currentListPropertyName = new ArrayList<String>();
439       for(PropertyIterator pi = currentNode.getProperties(); pi.hasNext();) {
440         Property property = pi.nextProperty();
441         currentListPropertyName.add(property.getName());
442       }
443       Set keys = jcrVariables.keySet();
444       String nodePath = extractNodeName(keys);
445       JcrInputProperty relRootProp = (JcrInputProperty) jcrVariables.get(nodePath);
446       String[] mixinTypes = {};
447       String mixintypeName = relRootProp.getMixintype();
448       if (mixintypeName != null && mixintypeName.trim().length() > 0) {
449         if (mixintypeName.indexOf(",") > -1) {
450           mixinTypes = mixintypeName.split(",");
451         } else {
452           mixinTypes = new String[] { mixintypeName };
453         }
454       }
455       for(String mixinType : mixinTypes) {
456         if (!currentNode.isNodeType(mixinType)) {
457           if (currentNode.canAddMixin(mixinType)) {
458             currentNode.addMixin(mixinType);
459           }
460         }
461       }
462 
463       PropertyDefinition[] propertyDefs = currentNodeType.getPropertyDefinitions();
464       List<PropertyDefinition> lstPropertyDefinition = Arrays.asList(propertyDefs);
465       List<PropertyDefinition> lstPropertyDefinitionAll = new ArrayList<PropertyDefinition>();
466       NodeType[] mixinNodeTypes = currentNode.getMixinNodeTypes();
467       lstPropertyDefinitionAll.addAll(lstPropertyDefinition);
468       for (NodeType mixinNodeType : mixinNodeTypes) {
469         Collections.addAll(lstPropertyDefinitionAll, mixinNodeType.getPropertyDefinitions());
470       }
471       // process property
472       for (PropertyDefinition propertyDef: lstPropertyDefinitionAll) {
473         String propertyName = propertyDef.getName();
474         Object value = null;
475         String currentPath = itemPath + "/" + propertyName;
476         JcrInputProperty inputVariable = (JcrInputProperty) jcrVariables.get(currentPath) ;
477         if(inputVariable != null) {
478           value = inputVariable.getValue();
479         }
480         if (currentListPropertyName.contains(propertyName) && currentNode.hasProperty(propertyName)) {
481           Property property = currentNode.getProperty(propertyName);
482           int requiredtype = property.getType();
483           if(keyList.contains(propertyName)) {
484             if(!propertyDef.isProtected()) {
485               processProperty(property, currentNode, requiredtype, value, propertyDef.isMultiple());
486             }
487           }
488         } else {
489           if (!propertyDef.isProtected()) {
490             int requiredtype = propertyDef.getRequiredType();
491             if(value != null || propertyDef.isMandatory()) {
492               processProperty(propertyName, currentNode, requiredtype, value, propertyDef.isMultiple()) ;
493             }
494           }
495         }
496       }
497 
498       //process multiple binary data
499       for (Object key : jcrVariables.keySet()) {
500         Object value = jcrVariables.get(key);
501         if (((JcrInputProperty)value).getValue() instanceof Map) {
502           processProperty(key.toString().substring(itemPath.length() + 1), currentNode,
503                           PropertyType.BINARY, ((JcrInputProperty)value).getValue(), true);
504         }
505       }
506     }
507 
508     //process child nodes
509     int itemLevel = StringUtils.countMatches(itemPath, "/") ;
510     List<JcrInputProperty>childNodeInputs = extractNodeInputs(jcrVariables, itemLevel + 1) ;
511     NodeTypeManager nodeTypeManger = currentNode.getSession().getWorkspace().getNodeTypeManager();
512     List<Object> childs = new ArrayList<Object>();
513 
514     if (currentNodeType.isMixin()) {
515       if (create) {
516         for (NodeDefinition childNodeDef : currentNodeType.getChildNodeDefinitions()) {
517           childs.add(childNodeDef);
518         }
519       } else {
520         for(NodeIterator iterator = currentNode.getNodes(); iterator.hasNext();) {
521           childs.add(iterator.nextNode());
522         }
523       }
524     } else {
525       Set<String> childNames = new HashSet<String>();
526 
527       for (NodeDefinition childNodeDef : currentNodeType.getChildNodeDefinitions()) {
528         childs.add(childNodeDef);
529         NodeType declaringNodeType = childNodeDef.getDeclaringNodeType();
530         NodeType defaultPrimaryType = childNodeDef.getDefaultPrimaryType();
531         childNames.add(childNodeDef.getName() +
532                        (declaringNodeType == null ? null : declaringNodeType.getName()) +
533                        (defaultPrimaryType == null? null : defaultPrimaryType.getName()) );
534       }
535       if (currentNode != null) {
536         for(NodeIterator iterator = currentNode.getNodes(); iterator.hasNext();) {
537           NodeDefinition childNodeDef = iterator.nextNode().getDefinition();
538           NodeType declaringNodeType = childNodeDef.getDeclaringNodeType();
539           NodeType defaultPrimaryType = childNodeDef.getDefaultPrimaryType();
540 
541           if (!childNames.contains(childNodeDef.getName() +
542                                    (declaringNodeType == null ? null : declaringNodeType.getName()) +
543                                    (defaultPrimaryType == null? null : defaultPrimaryType.getName()))) {
544             childs.add(childNodeDef);
545           }
546         }
547       }
548     }
549     Set<String> childItemPaths = new HashSet<String>();
550     for(Object obj : childs){
551       NodeDefinition nodeDef;
552       if (obj instanceof Node) {
553         nodeDef = ((Node) obj).getDefinition();
554       } else {
555         nodeDef = (NodeDefinition) obj;
556       }
557       if(nodeDef.isAutoCreated() || nodeDef.isProtected()) {
558         continue ;
559       }
560       if(((ItemDefinitionImpl)nodeDef).isResidualSet()) {
561         for(JcrInputProperty input:childNodeInputs) {
562           String childItemPath = itemPath + "/"+ input.getValue();
563           //Only child node input has dependent path of current node is added as child node
564           if(!childItemPath.equals(input.getJcrPath())) continue ;
565           String primaryNodeType = input.getNodetype();
566           NodeType nodeType = nodeTypeManger.getNodeType(primaryNodeType) ;
567           if(!canAddNode(nodeDef, nodeType)) {
568             continue ;
569           }
570           String[] mixinTypes = null ;
571           if(input.getMixintype()!= null) {
572             mixinTypes = input.getMixintype().split(",") ;
573           }
574           Node childNode = doAddNode(currentNode, (String)input.getValue(), nodeType.getName(), mixinTypes);
575           if (childNode != null && !childItemPaths.contains(childItemPath))
576             processNodeRecursively(create, childItemPath, childNode, childNode.getPrimaryNodeType(), jcrVariables);
577           childItemPaths.add(childItemPath);
578         }
579       } else {
580         String childNodeName = null;
581         if (obj instanceof Node) {
582           childNodeName = ((Node) obj).getName();
583         } else {
584           childNodeName = ((NodeDefinition) obj).getName();
585         }
586         String newItemPath = itemPath + "/" + childNodeName;
587         JcrInputProperty jcrInputVariable = (JcrInputProperty) jcrVariables.get(newItemPath);
588         if(jcrInputVariable == null) {
589           continue ;
590         }
591         String nodeTypeName = jcrInputVariable.getNodetype();
592         String[] mixinTypes = null ;
593         if(jcrInputVariable.getMixintype()!= null) {
594           mixinTypes = jcrInputVariable.getMixintype().split(",") ;
595         }
596         NodeType nodeType = null;
597         if(obj instanceof Node) {
598           nodeType = ((Node) obj).getPrimaryNodeType();
599         } else if (nodeTypeName == null || nodeTypeName.length() == 0) {
600           nodeType = nodeDef.getRequiredPrimaryTypes()[0];
601         } else {
602           nodeType = nodeTypeManger.getNodeType(nodeTypeName);
603         }
604         Node childNode = doAddNode(currentNode, childNodeName, nodeType.getName(), mixinTypes);
605         if (!childItemPaths.contains(newItemPath))
606           processNodeRecursively(create, newItemPath, childNode, childNode.getPrimaryNodeType(), jcrVariables);
607         childItemPaths.add(newItemPath);
608       }
609     }
610   }
611 
612   /**
613    * Process when add property for node.
614    * Base on type of property, needing specific processing
615    * @param propertyName    name of property
616    * @param node            node to process
617    * @param requiredtype    type of property: STRING, BINARY, BOOLEAN, LONG, DOUBLE, DATE, REFERENCE
618    * @param value           value of property
619    * @param isMultiple      value add is multiple or not
620    * @throws Exception
621    */
622 
623   private void processProperty(String propertyName, Node node, int requiredtype, Object value,
624                                boolean isMultiple) throws Exception {
625 
626     switch (requiredtype) {
627     case PropertyType.STRING:
628       if (value == null) {
629         if(isMultiple) {
630           node.setProperty(propertyName, new String[] {StringUtils.EMPTY});
631         } else {
632           node.setProperty(propertyName, StringUtils.EMPTY);
633         }
634       } else {
635         if(isMultiple) {
636           if (value instanceof String) {
637             node.setProperty(propertyName, new String[] { (String)value});
638           } else if (value instanceof String[]) {
639             node.setProperty(propertyName, (String[]) value);
640           }
641         } else {
642           if(!node.hasProperty(propertyName) || (node.hasProperty(propertyName) && 
643               !node.getProperty(propertyName).getString().equals((String)value)))
644             node.setProperty(propertyName, (String) value);
645         }
646       }
647       break;
648     case PropertyType.BINARY:
649       if (isMultiple) {
650         Node storedNode = node.hasNode(propertyName) ? node.getNode(propertyName) :
651           node.addNode(propertyName, NodetypeConstant.NT_UNSTRUCTURED);
652         if(value instanceof Map) {
653           for (Map.Entry<String, List> entry : ((Map<String, List>)value).entrySet()) {
654             String fileName = entry.getKey();
655             List param = entry.getValue();
656             Node fileNode = null;
657             Node jcrContentNode = null;
658             if (!storedNode.hasNode(fileName)) {
659               fileNode = storedNode.addNode(fileName, NodetypeConstant.NT_FILE);
660               jcrContentNode = fileNode.addNode(NodetypeConstant.JCR_CONTENT, NodetypeConstant.NT_RESOURCE);
661               jcrContentNode.setProperty(NodetypeConstant.JCR_MIME_TYPE, (String)param.get(0));
662               jcrContentNode.setProperty(NodetypeConstant.JCR_DATA, new ByteArrayInputStream((byte[])param.get(1)));
663             } else {
664               jcrContentNode = storedNode.getNode(fileName).getNode(NodetypeConstant.JCR_CONTENT);
665             }
666             jcrContentNode.setProperty(NodetypeConstant.JCR_LAST_MODIFIED, new GregorianCalendar());
667           }
668         }
669       } else {
670         if (value == null) {
671           node.setProperty(propertyName, "");
672         } else if(value instanceof InputStream) {
673           node.setProperty(propertyName, (InputStream)value);
674         } else if (value instanceof byte[]) {
675           node.setProperty(propertyName,
676                            new ByteArrayInputStream((byte[]) value));
677         } else if (value instanceof String) {
678           node.setProperty(propertyName, value.toString(), PropertyType.BINARY);
679         } else if (value instanceof String[]) {
680           node.setProperty(propertyName, (String[]) value, PropertyType.BINARY);
681         }
682       }
683       break;
684     case PropertyType.BOOLEAN:
685       if (value == null) {
686         node.setProperty(propertyName, false);
687       } else if (value instanceof String) {
688         node.setProperty(propertyName,
689                          new Boolean((String) value).booleanValue());
690       } else if (value instanceof String[]) {
691         node.setProperty(propertyName, (String[]) value);
692       } else if (value instanceof Boolean) {
693         node.setProperty(propertyName, ((Boolean) value).booleanValue());
694       }
695       break;
696     case PropertyType.LONG:
697       if (value == null || "".equals(value)) {
698         node.setProperty(propertyName, 0);
699       } else if (value instanceof String) {
700         node.setProperty(propertyName, new Long((String) value).longValue());
701       } else if (value instanceof String[]) {
702         node.setProperty(propertyName, (String[]) value);
703       } else if (value instanceof Long) {
704         node.setProperty(propertyName, ((Long) value).longValue());
705       }
706       break;
707     case PropertyType.DOUBLE:
708       if (value == null || "".equals(value)) {
709         node.setProperty(propertyName, 0);
710       } else if (value instanceof String) {
711         node.setProperty(propertyName, new Double((String) value).doubleValue());
712       } else if (value instanceof String[]) {
713         node.setProperty(propertyName, (String[]) value);
714       } else if (value instanceof Double) {
715         node.setProperty(propertyName, ((Double) value).doubleValue());
716       }
717 
718       break;
719     case PropertyType.DATE:
720       if (value == null){
721         boolean mandatory = false;
722         for (PropertyDefinition propertyDef : node.getPrimaryNodeType().getPropertyDefinitions())
723           if (propertyName.equals(propertyDef.getName()) && propertyDef.isMandatory()) {
724             mandatory = true;
725             break;
726           }
727         for (NodeType mixin : node.getMixinNodeTypes()) {
728           for (PropertyDefinition propertyDef : mixin.getPropertyDefinitions()) {
729             if (propertyName.equals(propertyDef.getName()) && propertyDef.isMandatory()) {
730               mandatory = true;
731               break;
732             }
733           }
734         }
735         if (mandatory) {
736           node.setProperty(propertyName, new GregorianCalendar());
737         } else {
738           node.setProperty(propertyName, (Value)null);
739         }
740       } else {
741         if (isMultiple) {
742           Session session = node.getSession();
743           if (value instanceof String) {
744             Value value2add = session.getValueFactory().createValue(ISO8601.parse((String) value));
745             node.setProperty(propertyName, new Value[] {value2add});
746           } else if (value instanceof String[]) {
747             String[] values = (String[]) value;
748             Value[] convertedCalendarValues = new Value[values.length];
749             int i = 0;
750             for (String stringValue : values) {
751               Value value2add = session.getValueFactory().createValue(ISO8601.parse(stringValue));
752               convertedCalendarValues[i] = value2add;
753               i++;
754             }
755             node.setProperty(propertyName, convertedCalendarValues);
756           }else if (value instanceof GregorianCalendar){
757             Value value2add = session.getValueFactory().createValue((GregorianCalendar) value);
758             node.setProperty(propertyName, new Value[]{value2add});
759           }else if (value instanceof GregorianCalendar[]){
760             GregorianCalendar[] values = (GregorianCalendar[]) value;
761             Value[] convertedCalendarValues = new Value[values.length];
762             int i = 0;
763             for (GregorianCalendar cvalue : values) {
764               Value value2add = session.getValueFactory().createValue(cvalue);
765               convertedCalendarValues[i] = value2add;
766               i++;
767             }
768             node.setProperty(propertyName, convertedCalendarValues);
769           }
770         } else {
771           if (value instanceof String) {
772             node.setProperty(propertyName, ISO8601.parse((String)value));
773           } else if (value instanceof GregorianCalendar) {
774             node.setProperty(propertyName, (GregorianCalendar) value);
775           }
776 
777         }
778       }
779       break;
780     case PropertyType.REFERENCE:
781       if (value == null) {
782         if (isMultiple) {
783           if (value instanceof String) {
784             node.setProperty(propertyName, "");
785           } else if (value instanceof String[]) {
786             node.setProperty(propertyName, new String[] {});
787           }
788         } else {
789           node.setProperty(propertyName, "");
790         }
791       }
792       if (value instanceof Value[]) {
793         node.setProperty(propertyName, (Value[]) value);
794       } else if (value instanceof String) {
795         String referenceWorksapce = null;
796         String referenceNodeName = null ;
797         Session session = node.getSession();
798         if (((String) value).indexOf(":/") > -1) {
799           referenceWorksapce = ((String) value).split(":/")[0];
800           referenceNodeName = ((String) value).split(":/")[1];
801           Session session2 = jcrService.getCurrentRepository().getSystemSession(referenceWorksapce);
802           Node rootNode = session2.getRootNode();
803           if (rootNode.hasNode(referenceNodeName)) {
804             Node referenceNode = rootNode.getNode(referenceNodeName);
805             if (referenceNode != null) {
806               if(!referenceNode.isNodeType(MIX_REFERENCEABLE)) {
807                 referenceNode.addMixin(MIX_REFERENCEABLE);
808                 referenceNode.save();
809               }
810               Value value2add = session2.getValueFactory().createValue(referenceNode);
811               node.setProperty(propertyName, value2add);
812             }
813           } else {
814             node.setProperty(propertyName, session2.getValueFactory().createValue((String)value));
815           }
816           session2.logout();
817         } else {
818           Node referenceNode = null;
819           try {
820             referenceNode = (Node) session.getItem((String) value);
821           } catch (PathNotFoundException e) {
822             referenceNode = session.getRootNode().getNode(value.toString());
823           }
824           if (referenceNode != null) {
825             if(!referenceNode.isNodeType(MIX_REFERENCEABLE)) {
826               referenceNode.addMixin(MIX_REFERENCEABLE);
827               referenceNode.save();
828             }
829             Value value2add = session.getValueFactory().createValue(referenceNode);
830             node.setProperty(propertyName, value2add);
831           } else {
832             node.setProperty(propertyName, session.getValueFactory().createValue(value.toString()));
833           }
834         }
835         node.save();
836       } else if(value instanceof String[]) {
837         String[] values = (String[]) value;
838         String referenceWorksapce = null;
839         String referenceNodeName = null ;
840         Session session = node.getSession();
841         List<Value> list = new ArrayList<Value>() ;
842         for (String v : values) {
843           Value valueObj = null;
844           if (v.indexOf(":/") > 0) {
845             referenceWorksapce = v.split(":/")[0];
846             referenceNodeName = v.split(":/")[1];
847             Session session2 = jcrService.getCurrentRepository().getSystemSession(referenceWorksapce);
848             Node rootNode = session2.getRootNode();
849             if(rootNode.hasNode(referenceNodeName)) {
850               Node referenceNode = rootNode.getNode(referenceNodeName);
851               valueObj = session2.getValueFactory().createValue(referenceNode);
852             }else {
853               valueObj = session2.getValueFactory().createValue(v);
854             }
855             session2.logout();
856           }else {
857             Node rootNode = session.getRootNode();
858             if(rootNode.hasNode(v)) {
859               Node referenceNode = rootNode.getNode(v);
860               valueObj = session.getValueFactory().createValue(referenceNode);
861             }else {
862               valueObj = session.getValueFactory().createValue(v);
863             }
864           }
865           list.add(valueObj);
866         }
867         node.setProperty(propertyName,list.toArray(new Value[list.size()]));
868       }
869       break;
870     default:
871       throw new RepositoryException("unknown type " + requiredtype);
872     }
873   }
874 
875   /**
876    * Process when update property for node.
877    * Base on type of property, needing specific processing
878    * @param property        Property of node
879    * @param node            node to process
880    * @param requiredtype    type of property: STRING, BINARY, BOOLEAN, LONG, DOUBLE, DATE, REFERENCE
881    * @param value           value of property
882    * @param isMultiple      value add is multiple or not
883    * @throws Exception
884    */
885   private void processProperty(Property property, Node node, int requiredtype,
886                                Object value, boolean isMultiple) throws Exception {
887     String nodeUUID = "";
888     if(node.isNodeType(NodetypeConstant.MIX_REFERENCEABLE)) nodeUUID = node.getUUID();
889     else nodeUUID = node.getName();
890     String propertyName = property.getName() ;
891     String updatedProperty = nodeUUID + "_" + propertyName;
892     if(isMultiple) properties.put(updatedProperty, property.getValues());
893     else properties.put(updatedProperty, property.getValue());
894     switch (requiredtype) {
895     case PropertyType.STRING:
896       if (value == null) {
897         if(isMultiple) {
898           node.setProperty(propertyName, new String[] {StringUtils.EMPTY});          
899         } else {
900           if(property.getValue() != null && !property.getValue().getString().equals(StringUtils.EMPTY)) {
901             node.setProperty(propertyName, StringUtils.EMPTY);        		
902           }            
903         }        
904       } else {
905         if(isMultiple) {
906           if (value instanceof String) { 
907             if(!property.getValues().equals(value)) {
908               node.setProperty(propertyName, new String[] { (String)value});              
909             }
910           } else if (value instanceof String[]) {
911             if(!isEqualsValueStringArrays(property.getValues(), (String[]) value)) {
912               node.setProperty(propertyName, (String[]) value);
913             }
914           }
915         } else {
916           if(!property.getValue().getString().equals(value)) {
917             node.setProperty(propertyName, (String) value);            
918           }
919         }
920       }
921       break;
922     case PropertyType.BINARY:
923       if (isMultiple) {
924         Node storedNode = node.hasNode(propertyName) ? node.getNode(propertyName) : node.addNode(propertyName);
925         if(value instanceof Map) {
926           for (Map.Entry<String, List> entry : ((Map<String, List>)value).entrySet()) {
927             String fileName = entry.getKey();
928             List param = entry.getValue();
929             Node fileNode = null;
930             Node jcrContentNode = null;
931             if (!storedNode.hasNode(fileName)) {
932 
933               fileNode = storedNode.addNode(fileName, NodetypeConstant.NT_FILE);
934               jcrContentNode = fileNode.addNode(NodetypeConstant.JCR_CONTENT);
935               jcrContentNode.setProperty(NodetypeConstant.JCR_MIME_TYPE, (String)param.get(0));
936               jcrContentNode.setProperty(NodetypeConstant.JCR_DATA, new ByteArrayInputStream((byte[])param.get(1)));              
937             } else {
938               jcrContentNode = storedNode.getNode(fileName).getNode(NodetypeConstant.JCR_CONTENT);
939             }
940             jcrContentNode.setProperty(NodetypeConstant.JCR_LAST_MODIFIED, new GregorianCalendar());
941           }
942         }
943       } else {
944         if (value == null ) {
945           if(node.getProperty(propertyName) != null && !node.getProperty(propertyName).getString().equals("")) {
946             node.setProperty(propertyName, "");            
947           }
948         } else if(value instanceof InputStream) {
949           if(!property.getValue().getStream().equals(value)) {
950             node.setProperty(propertyName, (InputStream)value);
951           }
952         } else if (value instanceof byte[]) {
953           if(!property.getValue().getStream().equals(new ByteArrayInputStream((byte[]) value))) {
954             node.setProperty(propertyName, new ByteArrayInputStream((byte[]) value));
955           }
956         } else if (value instanceof String) {
957           if(!property.getValue().getString().equals(value)) {
958             node.setProperty(propertyName, value.toString(), PropertyType.BINARY);
959           }
960         }
961       }
962       break;
963     case PropertyType.BOOLEAN:
964       if (value == null) {
965         node.setProperty(propertyName, false);
966       } else if (value instanceof Boolean) {
967         node.setProperty(propertyName, ((Boolean) value).booleanValue());
968       }else if (value instanceof String) {
969         if(property.getValue().getBoolean() != new Boolean((String) value).booleanValue()) {
970           node.setProperty(propertyName, new Boolean((String) value).booleanValue());
971         }
972       } else if (value instanceof String[]) {
973         if(!checkEqual(property.getValues(), (String[])value)) {
974           node.setProperty(propertyName, (String[]) value);
975         }
976       }
977       break;
978     case PropertyType.LONG:
979       if (value == null || "".equals(value)) {
980         node.setProperty(propertyName, 0);
981       } else if (value instanceof String) {
982         if(property.getValue().getLong() != new Long((String) value).longValue()) {
983           node.setProperty(propertyName, new Long((String) value).longValue());
984         }
985       } else if (value instanceof String[]) {
986         if(!checkEqual(property.getValues(), (String[])value)) {
987           node.setProperty(propertyName, (String[]) value);
988         }
989       } else if (value instanceof Long) {
990         node.setProperty(propertyName, ((Long) value).longValue());
991       }
992       break;
993     case PropertyType.DOUBLE:
994       if (value == null || "".equals(value)) {
995         node.setProperty(propertyName, 0);
996       } else if (value instanceof String) {
997         if(property.getValue().getDouble() != new Double((String) value).doubleValue()) {
998           node.setProperty(propertyName, new Double((String) value).doubleValue());
999         }
1000       } else if (value instanceof String[]) {
1001         if(!checkEqual(property.getValues(), (String[])value)) {
1002           node.setProperty(propertyName, (String[]) value);
1003         }
1004       } else if (value instanceof Double) {
1005         node.setProperty(propertyName, ((Double) value).doubleValue());
1006       }
1007       break;
1008     case PropertyType.DATE:
1009       if (value == null){
1010         boolean mandatory = false;
1011         for (PropertyDefinition propertyDef : node.getPrimaryNodeType().getPropertyDefinitions())
1012           if (propertyName.equals(propertyDef.getName()) && propertyDef.isMandatory()) {
1013             mandatory = true;
1014             break;
1015           }
1016         for (NodeType mixin : node.getMixinNodeTypes()) {
1017           for (PropertyDefinition propertyDef : mixin.getPropertyDefinitions()) {
1018             if (propertyName.equals(propertyDef.getName()) && propertyDef.isMandatory()) {
1019               mandatory = true;
1020               break;
1021             }
1022           }
1023         }
1024         if (mandatory) {
1025           node.setProperty(propertyName, new GregorianCalendar());
1026         } else {
1027           if(isMultiple)
1028             node.setProperty(propertyName, (Value[])null);
1029           else
1030             node.setProperty(propertyName, (Value)null);
1031         }
1032       } else {
1033         if(isMultiple) {
1034           Session session = node.getSession();
1035           if (value instanceof String) {
1036             Value value2add = session.getValueFactory().createValue(ISO8601.parse((String) value));
1037             if(!property.getValues().equals(new Value[] {value2add})) {
1038               node.setProperty(propertyName, new Value[] {value2add});
1039             }
1040           } else if (value instanceof String[]) {
1041             String[] values = (String[]) value;
1042             Value[] convertedCalendarValues = new Value[values.length];
1043             int i = 0;
1044             for (String stringValue : values) {
1045               Value value2add = session.getValueFactory().createValue(ISO8601.parse(stringValue));
1046               convertedCalendarValues[i] = value2add;
1047               i++;
1048             }
1049             if(!property.getValues().equals(convertedCalendarValues)) {
1050               node.setProperty(propertyName, convertedCalendarValues);
1051             }
1052           }else if (value instanceof GregorianCalendar){
1053             Value value2add = session.getValueFactory().createValue((GregorianCalendar)value);
1054             if(!property.getValues().equals(new Value[]{value2add})) {
1055               node.setProperty(propertyName, new Value[]{value2add});
1056             }
1057           }else if (value instanceof GregorianCalendar[]){
1058             GregorianCalendar[] values = (GregorianCalendar[]) value;
1059             Value[] convertedCalendarValues = new Value[values.length];
1060             int i = 0;
1061             for (GregorianCalendar cvalue : values) {
1062               Value value2add = session.getValueFactory().createValue(cvalue);
1063               convertedCalendarValues[i] = value2add;
1064               i++;
1065             }
1066             if(!property.getValues().equals(convertedCalendarValues)) {
1067               node.setProperty(propertyName, convertedCalendarValues);
1068             }
1069           }
1070         } else {
1071           if (value instanceof String) {
1072             if(!property.getValue().getString().equals(ISO8601.parse((String)value))) {
1073               node.setProperty(propertyName, ISO8601.parse((String)value));
1074             }
1075           } else if (value instanceof GregorianCalendar) {
1076             if(!property.getValue().getDate().equals(value)) {
1077               node.setProperty(propertyName, (GregorianCalendar) value);
1078             }
1079           }
1080         }
1081       }
1082       break;
1083     case PropertyType.REFERENCE:
1084       if (value == null) {
1085         if (isMultiple) {
1086           if (value instanceof String) {
1087             node.setProperty(propertyName, "");
1088           } else if (value instanceof String[]) {
1089             node.setProperty(propertyName, new String[] {});
1090           }
1091         } else {
1092           node.setProperty(propertyName, "");
1093         }
1094       }
1095       if (value instanceof Value[]) {
1096         if(!property.getValues().equals(value)) {
1097           node.setProperty(propertyName, (Value[]) value);
1098         }
1099       } else if (value instanceof String) {
1100         String referenceWorksapce = null;
1101         String referenceNodeName = null ;
1102         Session session = node.getSession();
1103         if (((String) value).indexOf(":/") > -1) {
1104           referenceWorksapce = ((String) value).split(":/")[0];
1105           referenceNodeName = ((String) value).split(":/")[1];
1106           Session session2 = jcrService.getCurrentRepository().getSystemSession(referenceWorksapce);
1107           Node rootNode = session2.getRootNode();
1108           if(rootNode.hasNode(referenceNodeName)) {
1109             Node referenceNode = rootNode.getNode(referenceNodeName);
1110             Value value2add = session2.getValueFactory().createValue(referenceNode);
1111             if(!property.getValue().getString().equals(value2add)) {
1112               node.setProperty(propertyName, value2add);
1113             }
1114           }else {
1115             if(!property.getValue().getString().equals(session2.getValueFactory().createValue((String)value))) {
1116               node.setProperty(propertyName, session2.getValueFactory().createValue((String)value));
1117             }
1118           }
1119           session2.logout();
1120         } else {
1121           Node referenceNode = null;
1122           try {
1123             referenceNode = (Node) session.getItem((String) value);
1124           } catch (PathNotFoundException e) {
1125             referenceNode = session.getRootNode().getNode(value.toString());
1126           }
1127           if (referenceNode != null) {
1128             if(!referenceNode.isNodeType(MIX_REFERENCEABLE)) {
1129               referenceNode.addMixin(MIX_REFERENCEABLE);
1130               referenceNode.save();
1131             }
1132             Value value2add = session.getValueFactory().createValue(referenceNode);
1133             if(!property.getValue().getString().equals(value2add)) {
1134               node.setProperty(propertyName, value2add);
1135             }
1136           } else {
1137             if(!property.getValue().getString().equals(session.getValueFactory().createValue(value.toString()))) {
1138               node.setProperty(propertyName, session.getValueFactory().createValue(value.toString()));
1139             }
1140           }
1141         }
1142         node.save();
1143       } else if(value instanceof String[]) {
1144         String[] values = (String[]) value;
1145         String referenceWorksapce = null;
1146         String referenceNodeName = null ;
1147         Session session = node.getSession();
1148         List<Value> list = new ArrayList<Value>() ;
1149         for (String v : values) {
1150           Value valueObj = null;
1151           if (v.indexOf(":/") > 0) {
1152             referenceWorksapce = v.split(":/")[0];
1153             referenceNodeName = v.split(":/")[1];
1154             Session session2 = jcrService.getCurrentRepository().getSystemSession(referenceWorksapce);
1155             Node rootNode = session2.getRootNode();
1156             if(rootNode.hasNode(referenceNodeName)) {
1157               Node referenceNode = rootNode.getNode(referenceNodeName);
1158               valueObj = session2.getValueFactory().createValue(referenceNode);
1159             }else {
1160               valueObj = session2.getValueFactory().createValue(v);
1161             }
1162             session2.logout();
1163           } else {
1164             Node rootNode = session.getRootNode();
1165             if(rootNode.hasNode(v)) {
1166               Node referenceNode = rootNode.getNode(v);
1167               valueObj = session.getValueFactory().createValue(referenceNode);
1168             } else {
1169               valueObj = session.getValueFactory().createValue(v);
1170             }
1171           }
1172           list.add(valueObj) ;
1173         }
1174         if (!property.getValues().equals(list.toArray(new Value[list.size()]))) {
1175           node.setProperty(propertyName, list.toArray(new Value[list.size()]));
1176         }
1177         node.save();
1178       }
1179       break ;
1180     default:
1181       throw new RepositoryException("unknown type " + requiredtype);
1182     }
1183   }
1184 
1185   /**
1186    * Get node name from set
1187    * In set, node name ends with NODE
1188    * @param keys
1189    * @return
1190    */
1191   private String extractNodeName(Set keys) {
1192     for (Iterator iter = keys.iterator(); iter.hasNext();) {
1193       String key = (String) iter.next();
1194       if (key.endsWith(NODE)) {
1195         return key;
1196       }
1197     }
1198     return null;
1199   }
1200 
1201   public boolean isEqualsValueStringArrays(Value[] arrayValue1, String[] arrayValue2) throws ValueFormatException, 
1202   IllegalStateException, RepositoryException {
1203     if(arrayValue1 != null) {
1204       String[] stringArray = new String[arrayValue1.length];
1205       int i = 0;
1206       for (Value valueItem : arrayValue1) {  	  	
1207         if(valueItem != null && valueItem.getString() != null)
1208           stringArray[i] = valueItem.getString();
1209         i++;
1210       }
1211       if(stringArray != null && stringArray.length > 0)
1212         Arrays.sort(stringArray);
1213       if(arrayValue2 != null && arrayValue2.length > 0)
1214         Arrays.sort(arrayValue2);
1215       return ArrayUtils.isEquals(stringArray, arrayValue2);  	    
1216     } else {
1217       if(arrayValue2 != null) return false;
1218       else return true;
1219     }	
1220   }
1221 
1222   /**
1223    * {@inheritDoc}
1224    */
1225   @Override
1226   public void moveNode(String nodePath, String srcWorkspace, String destWorkspace, String destPath) {
1227     Session srcSession = null ;
1228     Session destSession = null ;
1229     if (!srcWorkspace.equals(destWorkspace)) {
1230       try {
1231         srcSession = jcrService.getCurrentRepository().getSystemSession(srcWorkspace);
1232         destSession = jcrService.getCurrentRepository().getSystemSession(destWorkspace);
1233         Workspace workspace = destSession.getWorkspace();
1234         Node srcNode = (Node) srcSession.getItem(nodePath);
1235         try {
1236           destSession.getItem(destPath);
1237         } catch (PathNotFoundException e) {
1238           createNode(destSession, destPath);
1239         }
1240         workspace.clone(srcWorkspace, nodePath, destPath, true);
1241         try {
1242           if (activityService==null) {
1243             activityService = WCMCoreUtils.getService(ActivityCommonService.class);
1244           }
1245           if (listenerService!=null && activityService.isAcceptedNode(srcNode)) {
1246             listenerService.broadcast(ActivityCommonService.NODE_MOVED_ACTIVITY, srcNode, destPath);
1247           }
1248         }catch (Exception e) {
1249           if (LOG.isErrorEnabled()) {
1250             LOG.error("Can not notify NodeMovedActivity: " + e.getMessage());
1251           }
1252         }
1253         //Remove src node
1254         srcNode.remove();
1255         srcSession.save();
1256         destSession.save() ;
1257         srcSession.logout();
1258         destSession.logout();
1259       } catch (Exception e) {
1260         if (LOG.isWarnEnabled()) {
1261           LOG.warn(e.getMessage());
1262         }
1263       } finally {
1264         if(srcSession != null) srcSession.logout();
1265         if(destSession !=null) destSession.logout();
1266       }
1267     } else {
1268       Session session = null ;
1269       try{
1270         session = jcrService.getCurrentRepository().getSystemSession(srcWorkspace);
1271         Workspace workspace = session.getWorkspace();
1272         try {
1273           session.getItem(destPath);
1274         } catch (PathNotFoundException e) {
1275           createNode(session, destPath);
1276           session.refresh(false) ;
1277         }
1278 
1279         workspace.move(nodePath, destPath);
1280         try {
1281           Node movedNode =(Node) session.getItem(destPath);
1282           if (activityService==null) {
1283             activityService = WCMCoreUtils.getService(ActivityCommonService.class);
1284           }
1285           if (listenerService!=null && activityService.isAcceptedNode(movedNode)) {
1286             listenerService.broadcast(ActivityCommonService.NODE_MOVED_ACTIVITY, movedNode, destPath);
1287           }
1288         }catch (Exception e) {
1289           if (LOG.isErrorEnabled()) {
1290             LOG.error("Can not notify NodeMovedActivity: " + e.getMessage());
1291           }
1292         }
1293         session.logout();
1294       } catch (Exception e) {
1295         if (LOG.isWarnEnabled()) {
1296           LOG.warn(e.getMessage());
1297         }
1298       } finally {
1299         if (session != null && session.isLive())
1300           session.logout();
1301       }
1302     }
1303   }
1304 
1305   /**
1306    * Create node following path in uri
1307    * @param session Session
1308    * @param uri     path to created node
1309    * @throws RepositoryException
1310    */
1311   private void createNode(Session session, String uri) throws RepositoryException {
1312     String[] splittedName = StringUtils.split(uri, "/");
1313     Node rootNode = session.getRootNode();
1314     for (int i = 0; i < splittedName.length - 1; i++) {
1315       try {
1316         rootNode.getNode(splittedName[i]);
1317       } catch (PathNotFoundException exc) {
1318         rootNode.addNode(splittedName[i], "nt:unstructured");
1319         rootNode.save() ;
1320       }
1321       rootNode = rootNode.getNode(splittedName[i]) ;
1322     }
1323   }
1324 
1325   /**
1326    * Get all value in Map.
1327    * Base on key, iterate each key to get value in map
1328    * @param map       Map of key and value of property
1329    * @param itemLevel level of child of specific node
1330    * @return
1331    * @see {@link #processNodeRecursively(boolean, String, Node, NodeType, Map)}
1332    */
1333   private List<JcrInputProperty> extractNodeInputs(Map<String, JcrInputProperty> map, int itemLevel) {
1334     List<JcrInputProperty> list = new ArrayList<JcrInputProperty>() ;
1335     for(Iterator<String> iterator = map.keySet().iterator();iterator.hasNext();) {
1336       String jcrPath = iterator.next();
1337       if(itemLevel == StringUtils.countMatches(jcrPath, "/")) {
1338         JcrInputProperty input = map.get(jcrPath) ;
1339         if(input.getType() == JcrInputProperty.NODE) {
1340           list.add(input) ;
1341         }
1342       }
1343     }
1344     return list ;
1345   }
1346 
1347   /**
1348    * Check whether node type can add property in NodeDefinition
1349    * @param nodeDef   NodeDefinition
1350    * @param nodeType  NodeType
1351    * @return  true: can add property to node
1352    *          false: can't add
1353    */
1354   private boolean canAddNode(NodeDefinition nodeDef, NodeType nodeType) {
1355     for(NodeType type: nodeDef.getRequiredPrimaryTypes()) {
1356       if(nodeType.isNodeType(type.getName())) {
1357         return true ;
1358       }
1359     }
1360     return false ;
1361   }
1362 
1363   /**
1364    * Add child node for current node
1365    * @param currentNode current node
1366    * @param nodeName    name of child node
1367    * @param nodeType    nodetype of child node
1368    * @param mixinTypes  array of mixin type
1369    * @return child node
1370    * @throws Exception
1371    */
1372   private Node doAddNode(Node currentNode, String nodeName, String nodeType, String[] mixinTypes) throws Exception {
1373     if (StringUtils.isEmpty(nodeName))
1374       return null;
1375     Node childNode = null;
1376     try {
1377       childNode = currentNode.getNode(nodeName);
1378     } catch(PathNotFoundException pe) {
1379       childNode = currentNode.addNode(nodeName, nodeType);
1380     }
1381     if (mixinTypes != null && mixinTypes.length > 0) {
1382       for (String mixinName : mixinTypes) {
1383         if(!childNode.isNodeType(mixinName)) {
1384           childNode.addMixin(mixinName);
1385         }
1386       }
1387     }
1388     return childNode ;
1389   }
1390 
1391 
1392   /**
1393    * Compare if content of Value array equal to String array
1394    *
1395    * @param arrValues Value array
1396    * @param arrStrings String array
1397    * @return true: equal, false: not equal
1398    * @throws ValueFormatException
1399    * @throws IllegalStateException
1400    * @throws RepositoryException
1401    */
1402   private boolean checkEqual(Value[] arrValues, String[] arrStrings)
1403       throws ValueFormatException, IllegalStateException, RepositoryException
1404       {
1405     Validate.isTrue(arrValues != null, "arrValues must not null");
1406     Validate.isTrue(arrStrings != null, "arrStrings must not null");
1407 
1408     int arrValuesLenth = arrValues.length;
1409     boolean isEqual = true;
1410 
1411     if (arrValuesLenth != arrStrings.length)
1412     {
1413       isEqual = false;
1414     }
1415     else
1416     {
1417       for (int i = 0; i < arrValuesLenth; i++ )
1418       {
1419         if (!arrValues[i].getString().equals(arrStrings[i]))
1420         {
1421           isEqual = false;
1422           break;
1423         }
1424       }
1425     }
1426 
1427     return isEqual;
1428       }
1429 }