001/*
002 *  Copyright 2013 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.cart;
017
018import java.util.ArrayList;
019import java.util.Calendar;
020import java.util.HashSet;
021import java.util.List;
022import java.util.Set;
023
024import javax.jcr.Node;
025import javax.jcr.NodeIterator;
026import javax.jcr.RepositoryException;
027import javax.jcr.Value;
028
029import org.apache.commons.collections.CollectionUtils;
030import org.apache.commons.lang3.StringUtils;
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033
034import org.ametys.cms.repository.Content;
035import org.ametys.core.group.GroupIdentity;
036import org.ametys.core.user.UserIdentity;
037import org.ametys.plugins.explorer.resources.Resource;
038import org.ametys.plugins.repository.AmetysObject;
039import org.ametys.plugins.repository.AmetysRepositoryException;
040import org.ametys.plugins.repository.RepositoryConstants;
041import org.ametys.plugins.repository.UnknownAmetysObjectException;
042import org.ametys.plugins.repository.jcr.DefaultAmetysObject;
043import org.ametys.runtime.i18n.I18nizableText;
044
045/**
046 * Class representing a cart, backed by a JCR node.<br>
047 */
048public class Cart extends DefaultAmetysObject<CartFactory>
049{
050    private static final String TITLE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":label";
051    private static final String DESCRIPTION = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":description";
052    private static final String AUTHOR = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":author";
053    private static final String VISIBILITY = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":visibility";
054    
055    private static final String PROFILE_READ_ACCESS = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":read-access";
056    private static final String PROFILE_WRITE_ACCESS = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":write-access";
057    private static final String GROUPS = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":groups";
058    private static final String USERS = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":users";
059    
060    private static final String CONTENT_CART_ELEMENTS = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":contents";    
061    private static final String RESOURCE_CART_ELEMENTS = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":resources";
062    private static final String QUERIES_CART_ELEMENTS = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":queries";
063    
064    private static final String QUERY_ID_PROPERTY = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":id";
065    private static final String QUERY_DESCRIPTION_PROPERTY = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":description";
066    private static final String QUERY_AUTHOR_PROPERTY = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":author";
067    private static final String QUERY_TITLE_PROPERTY = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":title";
068    private static final String QUERY_DATE_PROPERTY = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":date";
069    
070    private static Logger _logger = LoggerFactory.getLogger(Cart.class.getName());
071    
072    /**
073     * Visibility of a Cart
074     */
075    public enum Visibility
076    {
077        /** Private visibility. */
078        PRIVATE,
079        /** Shared visibility. */
080        SHARED,
081        /** Public visibility. */
082        PUBLIC;
083        
084        @Override
085        public String toString()
086        {
087            return name().toLowerCase();
088        }
089    }
090    
091    /**
092     * Rights profiles
093     */
094    public enum CartProfile
095    {
096        /** Read access */
097        READ_ACCESS,
098        /** Write access */
099        WRITE_ACCESS;
100        
101        @Override
102        public String toString()
103        {
104            return name().toLowerCase();
105        }
106        
107        /**
108         * Cart profile title getter.
109         * @return The title of the profile
110         */
111        public I18nizableText getTitle()
112        {
113            switch (this)
114            {
115                case READ_ACCESS: 
116                    return new I18nizableText("plugin.cart", "PLUGINS_CART_RIGHT_PROFILE_READ_TITLE");
117                case WRITE_ACCESS: 
118                    return new I18nizableText("plugin.cart", "PLUGINS_CART_RIGHT_PROFILE_WRITE_TITLE");
119                default: 
120                    return null;
121            }
122        }
123
124        /**
125         * Cart profile description getter.
126         * @return The description of the profile
127         */
128        public I18nizableText getDescription()
129        {
130            switch (this)
131            {
132                case READ_ACCESS: 
133                    return new I18nizableText("plugin.cart", "PLUGINS_CART_RIGHT_PROFILE_READ_DESCRIPTION");
134                case WRITE_ACCESS: 
135                    return new I18nizableText("plugin.cart", "PLUGINS_CART_RIGHT_PROFILE_READ_DESCRIPTION");
136                default: 
137                    return null;
138            }
139        }
140    }
141    
142    /**
143     * Types of CartElement
144     */
145    public enum CartElementType
146    {
147        /** Type: content. */
148        CONTENT,
149        /** Type: resource. */
150        RESOURCE,
151        /** Type: cartQuery. */
152        CARTQUERY
153    }
154    
155    /**
156     * Creates an {@link Cart}.
157     * @param node the node backing this {@link AmetysObject}
158     * @param parentPath the parentPath in the Ametys hierarchy
159     * @param factory the DefaultAmetysObjectFactory which created the AmetysObject
160     */
161    public Cart(Node node, String parentPath, CartFactory factory)
162    {
163        super(node, parentPath, factory);
164    }        
165    
166    /**
167     * Set the title of this cart.
168     * @param title the description
169     */
170    public void setTitle (String title)
171    {
172        try
173        {
174            getNode().setProperty(TITLE, title != null ? title : StringUtils.EMPTY);
175        }
176        catch (RepositoryException e)
177        {
178            throw new AmetysRepositoryException("Error while setting title property.", e);
179        }
180    }
181    
182    /**
183     * Set the description of this cart.
184     * @param description the description
185     */
186    public void setDescription (String description)
187    {
188        try
189        {
190            getNode().setProperty(DESCRIPTION, description != null ? description : StringUtils.EMPTY);
191        }
192        catch (RepositoryException e)
193        {
194            throw new AmetysRepositoryException("Error while setting description property.", e);
195        }
196    }
197    
198    /**
199     * Set the author of this cart.
200     * @param author the author
201     */
202    public void setAuthor(UserIdentity author)
203    {
204        try
205        {
206            Node authorNode = _getOrCreateNode(getNode(), AUTHOR, "ametys:user");
207            authorNode.setProperty("ametys:login", author.getLogin());
208            authorNode.setProperty("ametys:population", author.getPopulationId());
209        }
210        catch (RepositoryException e)
211        {
212            throw new AmetysRepositoryException("Error setting the author property.", e);
213        }
214    }
215    
216    /**
217     * Set the cart visibility
218     * @param visibility the visibility
219     */
220    public void setVisibility (Visibility visibility)
221    {
222        try
223        {
224            getNode().setProperty(VISIBILITY, visibility.name());
225        }
226        catch (RepositoryException e)
227        {
228            throw new AmetysRepositoryException("Error while setting title property.", e);
229        }
230    }
231    
232    /**
233     * Get the title of the cart
234     * @return The title
235     */
236    public String getTitle()
237    {        
238        try
239        {
240            if (getNode().hasProperty(TITLE))
241            {
242                return getNode().getProperty(TITLE).getValue().getString();
243            }
244            else
245            {
246                return StringUtils.EMPTY;
247            }
248        }
249        catch (RepositoryException e)
250        {
251            throw new AmetysRepositoryException("Error while getting title property.", e);
252        }
253    }
254    
255    
256    /**
257     * Get the description of the cart
258     * @return The description
259     */
260    public String getDescription()
261    {
262        try
263        {
264            if (getNode().hasProperty(DESCRIPTION))
265            {
266                return getNode().getProperty(DESCRIPTION).getValue().getString();
267            }
268            else
269            {
270                return StringUtils.EMPTY;
271            }
272        }
273        catch (RepositoryException e)
274        {
275            throw new AmetysRepositoryException("Error while getting description property.", e);
276        }
277    }
278    
279    
280    /**
281     * Get the author of the cart
282     * @return The author
283     */
284    public UserIdentity getAuthor ()
285    {
286        try
287        {
288            Node authorNode = getNode().getNode(AUTHOR);
289            return new UserIdentity(authorNode.getProperty("ametys:login").getString(), authorNode.getProperty("ametys:population").getString());
290        }
291        catch (RepositoryException e)
292        {
293            throw new AmetysRepositoryException("Error while getting author property.", e);
294        }
295    }
296    
297    
298    /**
299     * Get the visibility of the cart
300     * @return The visibility
301     */
302    public Visibility getVisibility()
303    {
304        try
305        {
306            return Visibility.valueOf(getNode().getProperty(VISIBILITY).getValue().getString());
307        }
308        catch (RepositoryException e)
309        {
310            throw new AmetysRepositoryException("Error while getting visibility property.", e);
311        }
312    }
313    
314    /**
315     * Get the granted users
316     * @param profile the cart's profile
317     * @return the granted users
318     */
319    public Set<UserIdentity> getGrantedUsers(CartProfile profile)
320    {
321        try
322        {
323            String profileNodeName = null;
324                    
325            switch (profile)
326            {
327                case READ_ACCESS:
328                    profileNodeName = PROFILE_READ_ACCESS;
329                    break;
330                case WRITE_ACCESS:
331                    profileNodeName = PROFILE_WRITE_ACCESS;
332                    break;
333                default:
334                    throw new AmetysRepositoryException("Unexisting Cart profile : " + profile);
335            }
336            
337            Node profileNode = _getOrCreateNode(getNode(), profileNodeName, "nt:unstructured");
338            Set<UserIdentity> grantedUsers = new HashSet<>();
339            
340            grantedUsers.add(this.getAuthor());
341            
342            if (profileNode.hasNode(USERS))
343            {
344                NodeIterator it = profileNode.getNodes(USERS);
345                while (it.hasNext())
346                {
347                    Node next = (Node) it.next();
348                    grantedUsers.add(new UserIdentity(next.getProperty("ametys:login").getString(), next.getProperty("ametys:population").getString()));
349                }
350            }
351            
352            return grantedUsers;
353        }
354        catch (RepositoryException e)
355        {
356            throw new AmetysRepositoryException("Error while getting grantedUsers property.", e);
357        }
358    }
359    
360    /**
361     * Get the granted groups
362     * @param profile the cart's profile
363     * @return the logins of granted groups
364     */
365    public Set<GroupIdentity> getGrantedGroups(CartProfile profile)
366    {
367        try
368        {
369            String profileNodeName = null;
370                    
371            switch (profile)
372            {
373                case READ_ACCESS:
374                    profileNodeName = PROFILE_READ_ACCESS;
375                    break;
376                case WRITE_ACCESS:
377                    profileNodeName = PROFILE_WRITE_ACCESS;
378                    break;
379                default:
380                    throw new AmetysRepositoryException("Unexisting Cart profile : " + profile);
381            }
382            
383            Node profileNode = _getOrCreateNode(getNode(), profileNodeName, "nt:unstructured");
384            Set<GroupIdentity> grantedGroups = new HashSet<>();
385            
386            if (profileNode.hasNode(GROUPS))
387            {
388                NodeIterator it = profileNode.getNodes(GROUPS);
389                while (it.hasNext())
390                {
391                    Node next = (Node) it.next();
392                    grantedGroups.add(new GroupIdentity(next.getProperty("ametys:groupId").getString(), next.getProperty("ametys:groupDirectory").getString()));
393                }
394            }
395            
396            return grantedGroups;
397        }
398        catch (RepositoryException e)
399        {
400            throw new AmetysRepositoryException("Error while getting grantedGroups property.", e);
401        }
402    }
403    
404    /**
405     * Determines if an user has READ access to this cart.
406     * @param user The user
407     * @return <code>true</code> if the user has read access, <code>false</code> otherwise
408     */
409    public boolean canRead(UserIdentity user)
410    {
411        Visibility visibility = getVisibility();
412        
413        switch (visibility)
414        {
415            case PRIVATE:
416                return getAuthor().equals(user);
417                
418            case SHARED:
419                return getGrantedUsers(CartProfile.READ_ACCESS).contains(user) || CollectionUtils.containsAny(getGrantedGroups(CartProfile.READ_ACCESS), _getFactory()._getGroupsManager().getUserGroups(user)) || canWrite(user);
420
421            case PUBLIC:
422            default:
423                return true;
424        }
425    }
426    
427    /**
428     * Determines if an user has WRITE access to this cart.
429     * @param user The user
430     * @return <code>true</code> if the user has write access, <code>false</code> otherwise
431     */
432    public boolean canWrite(UserIdentity user)
433    {
434        Visibility visibility = getVisibility();
435        
436        switch (visibility)
437        {
438            case PRIVATE:
439                return getAuthor().equals(user);
440                
441            case SHARED:
442                return getGrantedUsers(CartProfile.WRITE_ACCESS).contains(user) || CollectionUtils.containsAny(getGrantedGroups(CartProfile.WRITE_ACCESS), _getFactory()._getGroupsManager().getUserGroups(user));
443
444            case PUBLIC:
445            default:
446                return true;
447        }
448    }
449    
450    /**
451     * Set the granted users
452     * @param profile the cart's profile
453     * @param users the granted users
454     */
455    public void setGrantedUsers (CartProfile profile, Set<UserIdentity> users)
456    {
457        try
458        {
459            String profileNodeName = null;
460            
461            switch (profile)
462            {
463                case READ_ACCESS:
464                    profileNodeName = PROFILE_READ_ACCESS;
465                    break;
466                case WRITE_ACCESS:
467                    profileNodeName = PROFILE_WRITE_ACCESS;
468                    break;
469                default:
470                    throw new AmetysRepositoryException("Unexisting Cart profile : " + profile);
471            }
472            
473            Node profileNode = _getOrCreateNode(getNode(), profileNodeName, "nt:unstructured");
474            
475            NodeIterator it = profileNode.getNodes(USERS);
476            while (it.hasNext())
477            {
478                Node next = (Node) it.next();
479                next.remove();
480            }
481            
482            UserIdentity author = this.getAuthor();
483            users.remove(author);
484            
485            for (UserIdentity userIdentity : users)
486            {
487                Node userNode = profileNode.addNode(USERS, "ametys:user");
488                userNode.setProperty("ametys:login", userIdentity.getLogin());
489                userNode.setProperty("ametys:population", userIdentity.getPopulationId());
490            }
491        }
492        catch (RepositoryException e)
493        {
494            throw new AmetysRepositoryException("Error while setting users property.", e);
495        }
496    }
497    
498    /**
499     * Set the granted groups
500     * @param profile the cart's profile
501     * @param groups the granted groups
502     */
503    public void setGrantedGroups(CartProfile profile, Set<GroupIdentity> groups)
504    {
505        try
506        {
507            String profileNodeName = null;
508            
509            switch (profile)
510            {
511                case READ_ACCESS:
512                    profileNodeName = PROFILE_READ_ACCESS;
513                    break;
514                case WRITE_ACCESS:
515                    profileNodeName = PROFILE_WRITE_ACCESS;
516                    break;
517                default:
518                    throw new AmetysRepositoryException("Unexisting Cart profile : " + profile);
519            }
520            
521            Node profileNode = _getOrCreateNode(getNode(), profileNodeName, "nt:unstructured");
522            
523            NodeIterator it = profileNode.getNodes(GROUPS);
524            while (it.hasNext())
525            {
526                Node next = (Node) it.next();
527                next.remove();
528            }
529            
530            for (GroupIdentity groupIdentity : groups)
531            {
532                Node groupNode = profileNode.addNode(GROUPS, "ametys:group");
533                groupNode.setProperty("ametys:groupId", groupIdentity.getId());
534                groupNode.setProperty("ametys:groupDirectory", groupIdentity.getDirectoryId());
535            }
536        }
537        catch (RepositoryException e)
538        {
539            throw new AmetysRepositoryException("Error while setting groups property.", e);
540        }
541    }
542    
543    /**
544     * Add a content to the cart
545     * @param contentId The content id
546     */
547    public void addContent (String contentId)
548    {
549        try
550        {
551            Set<String> contentIds = new HashSet<>();
552            
553            if (getNode().hasProperty(CONTENT_CART_ELEMENTS))
554            {
555                Value[] values = getNode().getProperty(CONTENT_CART_ELEMENTS).getValues();
556                for (Value value : values)
557                {
558                    contentIds.add(value.getString());
559                }
560            }
561            
562            contentIds.add(contentId);
563            
564            getNode().setProperty(CONTENT_CART_ELEMENTS, contentIds.toArray(new String[contentIds.size()]));
565        }
566        catch (RepositoryException e)
567        {
568            throw new AmetysRepositoryException("Error while adding content cart element.", e);
569        }
570    }
571    
572    /**
573     * Add a resource to the cart
574     * @param resourceId The resource id
575     */
576    public void addResource (String resourceId)
577    {
578        try
579        {
580            Set<String> resourceIds = new HashSet<>();
581            
582            if (getNode().hasProperty(RESOURCE_CART_ELEMENTS))
583            {
584                Value[] values = getNode().getProperty(RESOURCE_CART_ELEMENTS).getValues();
585                for (Value value : values)
586                {
587                    resourceIds.add(value.getString());
588                }
589            }
590            
591            resourceIds.add(resourceId);
592            
593            getNode().setProperty(RESOURCE_CART_ELEMENTS, resourceIds.toArray(new String[resourceIds.size()]));
594        }
595        catch (RepositoryException e)
596        {
597            throw new AmetysRepositoryException("Error while adding resource cart element.", e);
598        }
599    }
600    
601    /**
602     * Add a query to the cart
603     * @param author The author of the query
604     * @param title The title of the query 
605     * @param description The query as string
606     */
607    public void addQuery (UserIdentity author, String title, String description)
608    {
609        try
610        {
611            Node queriesNode = _getOrCreateQueriesNode ();
612            
613            Node queryNode = queriesNode.addNode("query");       
614            queryNode.setProperty(QUERY_ID_PROPERTY, org.ametys.core.util.StringUtils.generateKey());
615            queryNode.setProperty(QUERY_TITLE_PROPERTY, title);
616            queryNode.setProperty(QUERY_DESCRIPTION_PROPERTY, description);
617            
618            try
619            {
620                Node authorNode = _getOrCreateNode(queryNode, QUERY_AUTHOR_PROPERTY, "ametys:user");
621                authorNode.setProperty("ametys:login", author.getLogin());
622                authorNode.setProperty("ametys:population", author.getPopulationId());
623            }
624            catch (RepositoryException e)
625            {
626                throw new AmetysRepositoryException("Error setting the author property.", e);
627            }
628            
629            queryNode.setProperty(QUERY_DATE_PROPERTY, Calendar.getInstance());
630        }
631        catch (RepositoryException e)
632        {
633            throw new AmetysRepositoryException("Error while adding query cart element.", e);
634        }
635    }
636    
637    private Node _getOrCreateQueriesNode () throws RepositoryException
638    {
639        if (getNode().hasNode(QUERIES_CART_ELEMENTS))
640        {
641            return getNode().getNode(QUERIES_CART_ELEMENTS);
642        }
643        
644        return getNode().addNode(QUERIES_CART_ELEMENTS);
645    }
646    
647    /**
648     * Delete an element
649     * @param elmtId The id of element to remove
650     * @param elmtType The type of element to remove
651     */
652    public void removeElement (String elmtId, CartElementType elmtType)
653    {
654        switch (elmtType)
655        {
656            case CONTENT:
657                _removeContent(elmtId);
658                break;
659                
660            case RESOURCE:
661                _removeResource(elmtId);
662                break;
663                
664            case CARTQUERY:
665                _removeQuery(elmtId);
666                break;
667                
668            default:
669                break;
670        }
671    }
672    
673    /**
674     * Remove a resource from the cart
675     * @param resourceIdToRemove The id of the resource to remove
676     */
677    protected void _removeResource(String resourceIdToRemove)
678    {
679        try
680        {
681            Set<String> resourceIds = new HashSet<>();
682            
683            if (getNode().hasProperty(RESOURCE_CART_ELEMENTS))
684            {
685                Value[] values = getNode().getProperty(RESOURCE_CART_ELEMENTS).getValues();
686                for (Value value : values)
687                {                    
688                    String resourceId = value.getString();
689                    if (!resourceId.equals(resourceIdToRemove))
690                    {
691                        resourceIds.add(value.getString());                        
692                    }                    
693                }
694            }
695            
696            getNode().setProperty(RESOURCE_CART_ELEMENTS, resourceIds.toArray(new String[resourceIds.size()]));
697        }
698        catch (RepositoryException e)
699        {
700            throw new AmetysRepositoryException("Error while removing resource cart element.", e);
701        }
702    }
703    
704    /**
705     * Remove a content from the cart
706     * @param contentIdToRemove The id of the content to remove
707     */
708    protected void _removeContent(String contentIdToRemove)
709    {
710        try
711        {
712            Set<String> contentIds = new HashSet<>();
713            
714            if (getNode().hasProperty(CONTENT_CART_ELEMENTS))
715            {
716                Value[] values = getNode().getProperty(CONTENT_CART_ELEMENTS).getValues();
717                for (Value value : values)
718                {                    
719                    String contentId = value.getString();
720                    if (!contentId.equals(contentIdToRemove))
721                    {
722                        contentIds.add(value.getString());                        
723                    }                    
724                }
725            }
726            
727            getNode().setProperty(CONTENT_CART_ELEMENTS, contentIds.toArray(new String[contentIds.size()]));
728        }
729        catch (RepositoryException e)
730        {
731            throw new AmetysRepositoryException("Error while removing content cart element.", e);
732        }
733    }
734    
735    /**
736     * Remove a query from the cart
737     * @param queryIdToRemove The id of the query to remove
738     */
739    protected void _removeQuery(String queryIdToRemove)
740    {
741        try
742        {                       
743            if (getNode().hasNode(QUERIES_CART_ELEMENTS))
744            {
745                Node queries = getNode().getNode(QUERIES_CART_ELEMENTS);                
746                for (NodeIterator it = queries.getNodes(); it.hasNext();)
747                {
748                    Node query = it.nextNode();
749                    String queryId = query.getProperty(QUERY_ID_PROPERTY).getString();
750                    if (queryId.equals(queryIdToRemove))
751                    {
752                        query.remove();                       
753                        break;
754                    }
755                }                
756            }
757        }
758        catch (RepositoryException e)
759        {
760            throw new AmetysRepositoryException("Error while removing query cart element.", e);
761        }
762    }
763    
764    
765    
766    /**
767     * Get the elements of the cart
768     * @return The elements of the cart
769     */
770    public List<CartElement> getElements ()
771    {
772        List<CartElement> elmts = new ArrayList<>();
773        
774        try
775        {
776            elmts.addAll(getContentCartElements());
777            elmts.addAll(getResourceCartElements());
778            elmts.addAll(getQueryCartElements());
779        }
780        catch (RepositoryException e)
781        {
782            throw new AmetysRepositoryException("Error while getting cart elements", e);
783        }
784        
785        return elmts;
786    }
787    
788    /**
789     * Get the contents of the cart
790     * @return The elements of the cart
791     * @throws RepositoryException if an exception occurs while exploring the repository
792     */
793    public List<ContentElement> getContentCartElements () throws RepositoryException
794    {
795        List<String> unexistingElmts = new ArrayList<>();
796        
797        List<ContentElement> elmts = new ArrayList<>();
798        
799        if (getNode().hasProperty(CONTENT_CART_ELEMENTS))
800        {
801            Value[] values = getNode().getProperty(CONTENT_CART_ELEMENTS).getValues();
802            
803            for (Value value : values)
804            {
805                String contentId = value.getString();
806                
807                try
808                {
809                    Content content = _getFactory().getResolver().resolveById(contentId);
810                    elmts.add(new ContentElement(content, _getFactory()._getContentTypesHelper(), _getFactory()._getContentTypeEP()));
811                }
812                catch (UnknownAmetysObjectException e)
813                {
814                    _logger.error("The content of id '{}' does not exist anymore. It will be deleting from cart '{}'.", contentId, getId());
815                    unexistingElmts.add(contentId);
816                }
817            }
818        }
819        
820        // Delete unexisting contents
821        for (String contentId : unexistingElmts)
822        {
823            _removeContent(contentId);
824        }
825        
826        return elmts;
827    }
828    
829    /**
830     * Get the resources of the cart
831     * @return The elements of the cart
832     * @throws RepositoryException if an exception occurs while exploring the repository
833     */
834    public List<ResourceElement> getResourceCartElements () throws RepositoryException
835    {
836        List<String> unexistingElmts = new ArrayList<>();
837        List<ResourceElement> elmts = new ArrayList<>();
838        
839        if (getNode().hasProperty(RESOURCE_CART_ELEMENTS))
840        {
841            Value[] values = getNode().getProperty(RESOURCE_CART_ELEMENTS).getValues();
842            
843            for (Value value : values)
844            {
845                String resourceId = value.getString();
846                
847                try
848                {
849                    Resource resource = _getFactory().getResolver().resolveById(resourceId);
850                    elmts.add(new ResourceElement(resource));
851                }
852                catch (UnknownAmetysObjectException e)
853                {
854                    _logger.error("The resource of id '{}' does not exist anymore. It will be deleting from cart '{}'.", resourceId, getId());
855                    unexistingElmts.add(resourceId);
856                }
857            }
858        }
859        
860        // Delete unexisting resources
861        for (String resourceId : unexistingElmts)
862        {
863            _removeResource(resourceId);
864        }
865        
866        return elmts;
867    }
868    
869    /**
870     * Get the queries of the cart
871     * @return The elements of the cart
872     * @throws RepositoryException if an exception occurs while exploring the repository
873     */
874    public List<QueryElement> getQueryCartElements () throws RepositoryException
875    {
876        List<QueryElement> elmts = new ArrayList<>();
877        
878        if (getNode().hasNode(QUERIES_CART_ELEMENTS))
879        {
880            Node queries = getNode().getNode(QUERIES_CART_ELEMENTS);            
881            
882            for (NodeIterator it = queries.getNodes(); it.hasNext();)
883            {
884                Node queryNode = it.nextNode();
885                String id = queryNode.getProperty(QUERY_ID_PROPERTY).getString();
886                String authorLogin = queryNode.getNode(QUERY_AUTHOR_PROPERTY).getProperty("ametys:login").getString();
887                String authorPopulation = queryNode.getNode(QUERY_AUTHOR_PROPERTY).getProperty("ametys:population").getString();
888                UserIdentity author = new UserIdentity(authorLogin, authorPopulation);
889                String query = queryNode.getProperty(QUERY_DESCRIPTION_PROPERTY).getString();
890                String title = queryNode.getProperty(QUERY_TITLE_PROPERTY).getString();
891                Calendar creationDate = queryNode.getProperty(QUERY_DATE_PROPERTY).getDate();
892                       
893                QueryElement q = new QueryElement(id, query, author, creationDate, title);
894                elmts.add(q); 
895            }
896        }
897        
898        return elmts;
899    }
900
901    private Node _getOrCreateNode(Node parent, String name, String type) throws RepositoryException
902    {
903        Node node = null;
904        
905        if (parent.hasNode(name))
906        {
907            node = parent.getNode(name);
908        }
909        else if (type != null)
910        {
911            node = parent.addNode(name, type);
912        }
913        else
914        {
915            node = parent.addNode(name);
916        }
917        
918        return node;
919    }
920}