001/*
002 *  Copyright 2012 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.cms.tag.jcr;
017
018import java.util.Collections;
019import java.util.HashSet;
020import java.util.Set;
021
022import javax.jcr.Node;
023import javax.jcr.PathNotFoundException;
024import javax.jcr.RepositoryException;
025import javax.jcr.Value;
026import javax.jcr.ValueFactory;
027
028import org.ametys.plugins.repository.AmetysRepositoryException;
029import org.ametys.plugins.repository.RepositoryConstants;
030import org.ametys.plugins.repository.jcr.DefaultAmetysObject;
031import org.ametys.plugins.repository.jcr.JCRAmetysObject;
032
033/**
034 * Helper class which provides methods to manage tags on {@link JCRAmetysObject}s.
035 */
036public final class TaggableAmetysObjectHelper
037{
038    /** Constant for tags metadata. */
039    public static final String DEFAULT_METADATA_TAGS = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":tags";
040    
041    private TaggableAmetysObjectHelper()
042    {
043        // Hide the default constructor.
044    }
045    
046    /**
047     * Retrieve the tags of a {@link JCRAmetysObject}.
048     * @param object the {@link JCRAmetysObject} to tag.
049     * @return the object tags.
050     * @throws AmetysRepositoryException if failed to tag Ametys object
051     */
052    public static Set<String> getTags(JCRAmetysObject object) throws AmetysRepositoryException
053    {
054        return getTags(object, DEFAULT_METADATA_TAGS);
055    }
056    
057    /**
058     * Retrieve the tags of a {@link JCRAmetysObject}.
059     * @param object the {@link JCRAmetysObject} to tag.
060     * @param metadataName The name of the metadata holding the tags
061     * @return the object tags.
062     * @throws AmetysRepositoryException if failed to tag Ametys object
063     */
064    public static Set<String> getTags(JCRAmetysObject object, String metadataName) throws AmetysRepositoryException
065    {        
066        try
067        {
068            Node node = getNode(object);
069            Value[] values = node.getProperty(metadataName).getValues();
070            Set<String> tags = new HashSet<>(values.length);
071            
072            for (Value value : values)
073            {
074                tags.add(value.getString());
075            }
076            
077            return tags;
078        }
079        catch (PathNotFoundException e)
080        {
081            return Collections.emptySet();
082        }
083        catch (RepositoryException e)
084        {
085            throw new AmetysRepositoryException("Unable to get tags property " + metadataName, e);
086        }
087    }
088        
089    /**
090     * Tag a {@link JCRAmetysObject}.
091     * @param object the {@link JCRAmetysObject} to tag.
092     * @param tag the tag to put on the object.
093     * @throws AmetysRepositoryException if an error occurs.
094     */
095    public static void tag(JCRAmetysObject object, String tag) throws AmetysRepositoryException
096    {
097        tag(object, tag, DEFAULT_METADATA_TAGS);
098    }
099    
100    /**
101     * Tag a {@link JCRAmetysObject}.
102     * @param object the {@link JCRAmetysObject} to tag.
103     * @param tag the tag to put on the object.
104     * @param metadataName The name of the metadata holding the tags
105     * @throws AmetysRepositoryException if an error occurs.
106     */
107    public static void tag(JCRAmetysObject object, String tag, String metadataName) throws AmetysRepositoryException
108    {
109        try
110        {
111            Node node = getNode(object);
112            Value[] values = new Value[0];
113            
114            if (node.hasProperty(metadataName))
115            {
116                values = node.getProperty(metadataName).getValues();
117            }
118            
119            Set<String> tags = new HashSet<>(values.length + 1);
120            
121            for (Value value : values)
122            {
123                tags.add(value.getString());
124            }
125            
126            if (tags.add(tag))
127            {
128                ValueFactory valueFactory = node.getSession().getValueFactory();
129                Set<Value> newValues = new HashSet<>(tags.size());
130                
131                for (String currentTag : tags)
132                {
133                    newValues.add(valueFactory.createValue(currentTag));
134                }
135                
136                node.setProperty(metadataName, newValues.toArray(new Value[newValues.size()]));
137            }
138        }
139        catch (RepositoryException e)
140        {
141            throw new AmetysRepositoryException("Unable to set tags property", e);
142        }
143    }
144    
145    /**
146     * Remove a tag on a {@link JCRAmetysObject}.
147     * @param object the {@link JCRAmetysObject} to tag.
148     * @param tag the tag to remove on the object.
149     * @throws AmetysRepositoryException if an error occurs.
150     */
151    public static void untag(JCRAmetysObject object, String tag) throws AmetysRepositoryException
152    {
153        untag(object, tag, DEFAULT_METADATA_TAGS);
154    }
155    
156    /**
157     * Remove a tag on a {@link JCRAmetysObject}.
158     * @param object the {@link JCRAmetysObject} to tag.
159     * @param tag the tag to remove on the object.
160     * @param metadataName The name of the metadata holding the tags
161     * @throws AmetysRepositoryException if an error occurs.
162     */
163    public static void untag(JCRAmetysObject object, String tag, String metadataName) throws AmetysRepositoryException
164    {
165        try
166        {
167            Node node = getNode(object);
168            Value[] values = new Value[0];
169            
170            if (node.hasProperty(metadataName))
171            {
172                values = node.getProperty(metadataName).getValues();
173            }
174            
175            Set<String> tags = new HashSet<>(values.length + 1);
176            
177            for (Value value : values)
178            {
179                tags.add(value.getString());
180            }
181            
182            if (tags.remove(tag))
183            {
184                ValueFactory valueFactory = node.getSession().getValueFactory();
185                Set<Value> newValues = new HashSet<>(tags.size());
186                
187                for (String currentTag : tags)
188                {
189                    newValues.add(valueFactory.createValue(currentTag));
190                }
191                
192                node.setProperty(metadataName, newValues.toArray(new Value[newValues.size()]));
193            }
194        }
195        catch (RepositoryException e)
196        {
197            throw new AmetysRepositoryException("Unable to set tags property", e);
198        }
199    }
200    
201    /**
202     * Get an object's base node.
203     * @param object the object which node to get.
204     * @return the object's base node.
205     */
206    protected static Node getNode(JCRAmetysObject object)
207    {
208        Node node = null;
209        
210        if (object instanceof DefaultAmetysObject)
211        {
212            node = ((DefaultAmetysObject) object).getBaseNode();
213        }
214        else
215        {
216            node = object.getNode();
217        }
218        
219        return node;
220    }
221    
222}