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.repositoryapp.jcr;
017
018import java.io.File;
019import java.io.FileInputStream;
020import java.io.IOException;
021import java.io.InputStream;
022import java.text.DateFormat;
023import java.text.ParseException;
024import java.text.SimpleDateFormat;
025import java.time.ZonedDateTime;
026import java.util.ArrayList;
027import java.util.Arrays;
028import java.util.Calendar;
029import java.util.Collections;
030import java.util.GregorianCalendar;
031import java.util.HashMap;
032import java.util.List;
033import java.util.Map;
034
035import javax.jcr.Binary;
036import javax.jcr.Node;
037import javax.jcr.RepositoryException;
038import javax.jcr.Session;
039import javax.jcr.Value;
040import javax.jcr.ValueFactory;
041
042import org.apache.avalon.framework.parameters.Parameters;
043import org.apache.avalon.framework.service.ServiceException;
044import org.apache.avalon.framework.service.ServiceManager;
045import org.apache.cocoon.acting.ServiceableAction;
046import org.apache.cocoon.environment.ObjectModelHelper;
047import org.apache.cocoon.environment.Redirector;
048import org.apache.cocoon.environment.Request;
049import org.apache.cocoon.environment.SourceResolver;
050import org.apache.cocoon.servlet.multipart.PartOnDisk;
051import org.apache.commons.lang3.StringUtils;
052
053import org.ametys.core.cocoon.JSonReader;
054import org.ametys.core.util.DateUtils;
055import org.ametys.plugins.repositoryapp.RepositoryProvider;
056import org.ametys.runtime.i18n.I18nizableText;
057import org.ametys.workspaces.repository.jcr.RepositoryDao;
058
059/**
060 * Set value for a property (if the property does not exist, create the property)
061 */
062public class SetPropertyAction extends ServiceableAction
063{
064    
065    /** The input date format. */
066    protected static final DateFormat _DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
067    
068    /** The repository provider. */
069    protected RepositoryProvider _repositoryProvider;
070    
071    @Override
072    public void service(ServiceManager serviceManager) throws ServiceException
073    {
074        super.service(serviceManager);
075        _repositoryProvider = (RepositoryProvider) serviceManager.lookup(RepositoryProvider.ROLE);
076    }
077    
078    public Map act(Redirector redirector, SourceResolver sourceResolver, Map objectModel, String source, Parameters parameters) throws Exception
079    {
080        Map<String, Object> result = new HashMap<>();
081        
082        Request request = ObjectModelHelper.getRequest(objectModel);
083        
084        String workspaceName = request.getParameter("workspace");
085        
086        Session session = _repositoryProvider.getSession(workspaceName);
087        
088        String nodePath = request.getParameter("path");
089        String propertyName = request.getParameter("name");
090        String[] values = request.getParameterValues("value");
091        String type = request.getParameter("type");
092        boolean multiple = Boolean.valueOf(request.getParameter("multiple"));
093        
094        if (getLogger().isDebugEnabled())
095        {
096            getLogger().debug("Trying to add property: '" + propertyName + "' to the node at path: '" + nodePath + "'");
097        }
098        
099        String relPath = RepositoryDao.removeLeadingSlash(nodePath);
100        
101        // Get the parent node
102        Node node = null;
103        if (StringUtils.isEmpty(relPath))
104        {
105            node = session.getRootNode();
106        }
107        else
108        {
109            node = session.getRootNode().getNode(relPath);
110        }
111        
112        // Get the type in jcr format (e.g. javax.jcr.PropertyType.BOOLEAN)
113        int jcrType = javax.jcr.PropertyType.valueFromName(StringUtils.capitalize(type));
114        
115        try
116        {
117            // Add or update property to the node
118            if (type.equalsIgnoreCase("Date"))
119            {
120                _setDate(node, propertyName, values);
121            }
122            else if (type.equalsIgnoreCase("Binary"))
123            {
124                _setBinary(session, request, node, propertyName);
125            }
126            else if (type.equalsIgnoreCase("Reference"))
127            {
128                _setReference(session, node, propertyName, values, multiple);
129            }
130            else
131            {
132                _setValue(node, propertyName, values, multiple, jcrType);
133            }
134            
135            result.put("success", true);
136        }
137        catch (RepositoryException e)
138        {
139            getLogger().error("Unable to set value " + Arrays.toString(values) + " for property '" + propertyName + "'", e);
140            result.put("success", false);
141            result.put("message", e.toString());
142        }
143        catch (ParseException e)
144        {
145            getLogger().error("Unable to set value " + Arrays.toString(values) + " for property '" + propertyName + "'", e);
146            result.put("success", false);
147            I18nizableText message = new I18nizableText("plugin.repositoryapp", "PLUGINS_REPOSITORYAPP_CREATE_PROP_ERROR_DATE", Collections.singletonMap("error", new I18nizableText(e.getMessage())));
148            result.put("message", message);
149        }
150        catch (Exception e)
151        {
152            getLogger().error("Unable to set value " + Arrays.toString(values) + " for property '" + propertyName + "'", e);
153            result.put("success", false);
154            result.put("message", e.toString());
155        }
156        
157        request.setAttribute(JSonReader.OBJECT_TO_READ, result);
158        return EMPTY_MAP;
159    }
160    
161    private void _setDate(Node node, String propertyName, String[] value) throws RepositoryException, ParseException
162    {
163        //create calendar date from string value
164        ZonedDateTime zdt = DateUtils.parseZonedDateTime(value[0]);
165        Calendar cal = GregorianCalendar.from(zdt);
166        
167        node.setProperty(propertyName, cal);
168    }
169    
170    private void _setBinary(Session session, Request request, Node node, String propertyName) throws RepositoryException, IOException
171    {
172        // The upload was either sent as the property name (when modified) or as "fieldValue" (when added).
173        PartOnDisk uploadedFilePart = (PartOnDisk) request.get(propertyName);
174        if (uploadedFilePart == null)
175        {
176            uploadedFilePart = (PartOnDisk) request.get("fieldValue");
177        }
178        
179        File uploadedFile = (uploadedFilePart != null) ? uploadedFilePart.getFile() : null;
180        InputStream is = new FileInputStream(uploadedFile);
181        
182        Binary binary = session.getValueFactory().createBinary(is);
183        node.setProperty(propertyName, binary);
184    }
185    
186    private void _setReference(Session session, Node node, String propertyName, String[] value, boolean multiple) throws RepositoryException
187    {
188        List<Value> values = new ArrayList<>();
189        ValueFactory vf = session.getValueFactory();
190        for (String v : value)
191        {
192            values.add(vf.createValue(session.getNodeByIdentifier(v)));
193        }
194        
195        boolean isMultiple = multiple || node.hasProperty(propertyName) && node.getProperty(propertyName).getDefinition().isMultiple();
196        if (isMultiple)
197        {
198            node.setProperty(propertyName, values.toArray(new Value[values.size()]));
199        }
200        else
201        {
202            node.setProperty(propertyName, values.get(0));
203        }
204    }
205    
206    private void _setValue(Node node, String propertyName, String[] value, boolean multiple, int jcrType) throws RepositoryException
207    {
208        boolean isMultiple = multiple || node.hasProperty(propertyName) && node.getProperty(propertyName).getDefinition().isMultiple();
209        if (isMultiple)
210        {
211            node.setProperty(propertyName, value, jcrType);
212        }
213        else
214        {
215            node.setProperty(propertyName, value[0], jcrType);
216        }
217    }
218    
219}