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