001/*
002 *  Copyright 2010 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.repository.metadata.jcr;
017
018import javax.jcr.Node;
019import javax.jcr.RepositoryException;
020import javax.jcr.lock.Lock;
021import javax.jcr.lock.LockManager;
022
023import org.apache.commons.lang3.ArrayUtils;
024
025import org.ametys.plugins.repository.AmetysObjectResolver;
026import org.ametys.plugins.repository.AmetysRepositoryException;
027import org.ametys.plugins.repository.RepositoryConstants;
028import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata;
029import org.ametys.plugins.repository.metadata.ModifiableFolder;
030import org.ametys.plugins.repository.metadata.ModifiableRichText;
031import org.ametys.plugins.repository.metadata.RichText;
032import org.ametys.plugins.repository.metadata.UnknownMetadataException;
033
034/**
035 * JCR implementation of a {@link RichText}, based on the ametys:richText nodetype.<br>
036 */
037public class JCRRichText extends JCRResource implements ModifiableRichText
038{
039    
040    /** The annotations node name. */
041    private static final String _ANNOTATIONS_NODE_NAME = "annotations";
042    
043    private Node _rootDataNode;
044    private AmetysObjectResolver _resolver;
045    private boolean _lockAlreadyChecked;
046    
047    /**
048     * Constructor
049     * @param node the JCR Node backing this {@link JCRRichText}
050     * @param resolver The resolver, used to resolve object collections.
051     * @throws AmetysRepositoryException if an error occurs
052     */
053    public JCRRichText(Node node, AmetysObjectResolver resolver) throws AmetysRepositoryException
054    {
055        super(node);
056        
057        _resolver = resolver;
058        
059        try
060        {
061            _rootDataNode = node.getNode("data");
062        }
063        catch (RepositoryException e)
064        {
065            throw new AmetysRepositoryException(e);
066        }
067    }
068    
069    public ModifiableFolder getAdditionalDataFolder()
070    {
071        return new JCRFolder(_rootDataNode);
072    }
073    
074    @Override
075    public String[] getAnnotationNames() throws AmetysRepositoryException
076    {
077        try
078        {
079            ModifiableCompositeMetadata annotations = getAnnotationsNode(false);
080            
081            return annotations.getMetadataNames();
082        }
083        catch (UnknownMetadataException e)
084        {
085            // Ignore, just return an empty array.
086        }
087        
088        return new String[0];
089    }
090    
091    @Override
092    public String[] getAnnotationValues(String name) throws AmetysRepositoryException
093    {
094        try
095        {
096            ModifiableCompositeMetadata annotations = getAnnotationsNode(false);
097            if (annotations.hasMetadata(name))
098            {
099                return annotations.getStringArray(name);
100            }
101        }
102        catch (UnknownMetadataException e)
103        {
104            // Ignore, just return an empty array.
105        }
106        
107        return new String[0];
108    }
109    
110    @Override
111    public void addAnnotation(String name, String value) throws AmetysRepositoryException
112    {
113        String[] currentValues = getAnnotationValues(name);
114        getAnnotationsNode(true).setMetadata(name, ArrayUtils.add(currentValues, value));
115    }
116    
117    @Override
118    public void addAnnotation(String name, String[] values) throws AmetysRepositoryException
119    {
120        String[] currentValues = getAnnotationValues(name);
121        getAnnotationsNode(true).setMetadata(name, ArrayUtils.addAll(currentValues, values));
122    }
123    
124    @Override
125    public void removeAnnotations() throws AmetysRepositoryException
126    {
127        try
128        {
129            _checkLock();
130            if (getNode().hasNode(_ANNOTATIONS_NODE_NAME))
131            {
132                getNode().getNode(_ANNOTATIONS_NODE_NAME).remove(); 
133            }
134        }
135        catch (RepositoryException e)
136        {
137            throw new AmetysRepositoryException(e);
138        }
139    }
140    
141    @Override
142    public void removeAnnotation(String name) throws AmetysRepositoryException
143    {
144        ModifiableCompositeMetadata annotations = getAnnotationsNode(true);
145        if (annotations.hasMetadata(name))
146        {
147            annotations.removeMetadata(name);
148        }
149    }
150    
151    /**
152     * Get the annotations container node.
153     * @param createNew <code>true</code> to create the node if it doesn't exist, <code>false</code> otherwise.
154     * @return The annotation container node.
155     * @throws UnknownMetadataException If the node doesn't exist and createNew is false.
156     * @throws AmetysRepositoryException If a repository error occurs.
157     */
158    protected ModifiableCompositeMetadata getAnnotationsNode(boolean createNew) throws UnknownMetadataException, AmetysRepositoryException
159    {
160        try
161        {
162            if (getNode().hasNode(_ANNOTATIONS_NODE_NAME))
163            {
164                Node node = getNode().getNode(_ANNOTATIONS_NODE_NAME);
165                return new JCRCompositeMetadata(node, _resolver);
166            }
167            else if (createNew)
168            {
169                _checkLock();
170                Node node = getNode().addNode(_ANNOTATIONS_NODE_NAME, "ametys:compositeMetadata");
171                return new JCRCompositeMetadata(node, _resolver);
172            }
173            else
174            {
175                throw new UnknownMetadataException("No annotation found");
176            }
177        }
178        catch (RepositoryException e)
179        {
180            throw new AmetysRepositoryException(e);
181        }
182    }
183    
184    private void _checkLock() throws RepositoryException
185    {
186        Node node = getNode();
187        if (!_lockAlreadyChecked && node.isLocked())
188        {
189            LockManager lockManager = node.getSession().getWorkspace().getLockManager();
190            
191            Lock lock = lockManager.getLock(node.getPath());
192            Node lockHolder = lock.getNode();
193            
194            lockManager.addLockToken(lockHolder.getProperty(RepositoryConstants.METADATA_LOCKTOKEN).getString());
195            _lockAlreadyChecked = true;
196        }
197    }
198    
199}