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.web.repository.page.actions;
017
018import java.util.ArrayList;
019import java.util.Date;
020import java.util.Enumeration;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024
025import org.apache.avalon.framework.parameters.Parameters;
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.cocoon.environment.ObjectModelHelper;
029import org.apache.cocoon.environment.Redirector;
030import org.apache.cocoon.environment.Request;
031import org.apache.cocoon.environment.SourceResolver;
032
033import org.ametys.core.observation.AbstractNotifierAction;
034import org.ametys.core.observation.Event;
035import org.ametys.plugins.repository.AmetysObjectResolver;
036import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata;
037import org.ametys.runtime.parameter.ParameterHelper;
038import org.ametys.runtime.parameter.ParameterHelper.ParameterType;
039import org.ametys.web.ObservationConstants;
040import org.ametys.web.repository.page.ModifiablePage;
041
042/**
043 * Edit the metadata of a page
044 * The attempt request parameters are like 'page.input.[type].[single|multiple].[path].[path]'
045 *
046 */
047public class EditMetadataAction extends AbstractNotifierAction
048{
049    /** Prefix for form elements. */
050    public static final String FORM_ELEMENTS_PREFIX = "page.input.";
051    
052    private AmetysObjectResolver _resolver;
053    
054    @Override
055    public void service(ServiceManager smanager) throws ServiceException
056    {
057        super.service(smanager);
058        _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE);
059    }
060    
061    @Override
062    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
063    {
064        Request request = ObjectModelHelper.getRequest(objectModel);
065        String id = request.getParameter("id");
066        
067        ModifiablePage page = _resolver.resolveById(id);
068        
069        // FIXME API
070        ModifiableCompositeMetadata metaHolder = page.getMetadataHolder();
071        
072        Enumeration paramNames = request.getParameterNames();
073        while (paramNames.hasMoreElements())
074        {
075            String paramName = (String) paramNames.nextElement();
076            
077            if (paramName.startsWith(FORM_ELEMENTS_PREFIX))
078            {
079                String[] metadataValues = request.getParameterValues(paramName);
080                
081                // ex: page.input.string.multiple.keywords.title
082                // ex: page.input.date.single.publication.date
083                paramName = paramName.substring(FORM_ELEMENTS_PREFIX.length());
084                
085                String[] a = paramName.split("\\.");
086                String type = a[0];
087                boolean isMultiple = a[1].equals("multiple");
088                String[] metadataPath = new String[a.length - 2];
089                for (int i = 0; i < metadataPath.length; i++)
090                {
091                    metadataPath[i] = a[i + 2];
092                }
093                
094                _saveMetadata(metaHolder, metadataPath, type, metadataValues, isMultiple);
095            }
096        }
097        
098        if (page.needsSave())
099        {
100            page.saveChanges();
101        }
102        
103        // Notify observer
104        Map<String, Object> eventParams = new HashMap<>();
105        eventParams.put(ObservationConstants.ARGS_PAGE, page);
106        _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_CHANGED, _getCurrentUser(), eventParams));
107        
108        return EMPTY_MAP;
109    }
110    
111    private void _saveMetadata (ModifiableCompositeMetadata metadata, String[] metadataPath, String type, String[] values, boolean isMultiple)
112    {
113        if (metadataPath.length == 1)
114        {
115            _saveMetadata(metadata, metadataPath[0], type, values, isMultiple);
116        }
117        else
118        {
119            String[] childPath = new String[metadataPath.length - 1];
120            for (int i = 0; i < childPath.length; i++)
121            {
122                childPath[i] = metadataPath[i + 1];
123            }
124            ModifiableCompositeMetadata compMetadata = metadata.getCompositeMetadata(metadataPath[0], true);
125            _saveMetadata (compMetadata, childPath, type, values, isMultiple);
126        }
127    }
128    
129    private void _saveMetadata (ModifiableCompositeMetadata metadata, String metadataName, String type, String[] values, boolean isMultiple)
130    {
131        ParameterType paramType = ParameterHelper.stringToType(type);
132        
133        if (ParameterType.STRING.equals(paramType))
134        {
135            _saveStringMetadata (metadata, metadataName, values, isMultiple);
136        }
137        else if (ParameterType.DATE.equals(paramType))
138        {
139            _saveDateMetadata (metadata, metadataName, values, isMultiple);
140        }
141        else if (ParameterType.LONG.equals(paramType))
142        {
143            _saveLongMetadata (metadata, metadataName, values, isMultiple);
144        }
145        else if (ParameterType.DOUBLE.equals(paramType))
146        {
147            _saveDoubleMetadata (metadata, metadataName, values, isMultiple);
148        }
149        else if (ParameterType.BOOLEAN.equals(paramType))
150        {
151            _saveBooleanMetadata (metadata, metadataName, values, isMultiple);
152        }
153        else if (ParameterType.BINARY.equals(paramType))
154        {
155            // TODO
156        }
157    }
158    
159    private void _saveStringMetadata (ModifiableCompositeMetadata metadata, String metadataName, String[] values, boolean isMultiple)
160    {
161        List<String> stringValues = new ArrayList<>();
162        
163        for (int i = 0; i < values.length; i++)
164        {
165            if (!"".equals(values[i]))
166            {
167                stringValues.add(values[i]);
168            }
169        }
170        
171        String[] stringArray = stringValues.toArray(new String[stringValues.size()]);
172        if (stringArray.length == 0)
173        {
174            if (metadata.hasMetadata(metadataName))
175            {
176                metadata.removeMetadata(metadataName);
177            }
178        }
179        else
180        {
181            if (isMultiple)
182            {
183                metadata.setMetadata(metadataName, stringArray);
184            }
185            else
186            {
187                metadata.setMetadata(metadataName, stringArray[0]);
188            }
189        }
190    }
191    
192    private void _saveDateMetadata (ModifiableCompositeMetadata metadata, String metadataName, String[] values, boolean isMultiple)
193    {
194        List<Date> dateValues = new ArrayList<>();
195        
196        for (String value : values)
197        {
198            if (!"".equals(value))
199            {
200                Date date = (Date) ParameterHelper.castValue(value, ParameterType.DATE);
201                if (date == null)
202                {
203                    getLogger().error("Cannot cast value '" + value + "' into type 'date'");
204                    throw new IllegalArgumentException("Invalid format for date value '" +  value + "'");
205                }
206                dateValues.add(date);
207            }
208        }
209        
210        Date[] dateArray = dateValues.toArray(new Date[dateValues.size()]);
211        
212        if (dateArray.length == 0)
213        {
214            if (metadata.hasMetadata(metadataName))
215            {
216                metadata.removeMetadata(metadataName);
217            }
218        }
219        else
220        {
221            if (isMultiple)
222            {
223                metadata.setMetadata(metadataName, dateArray);
224            }
225            else
226            {
227                metadata.setMetadata(metadataName, dateArray[0]);
228            }
229        }
230    }
231    
232    private void _saveLongMetadata (ModifiableCompositeMetadata metadata, String metadataName, String[] values, boolean isMultiple)
233    {
234        List<Long> longValues = new ArrayList<>();
235        
236        for (String value : values)
237        {
238            if (!"".equals(value))
239            {
240                try
241                {
242                    longValues.add(Long.parseLong(value));
243                }
244                catch (NumberFormatException e)
245                {
246                    getLogger().error("Cannot cast value '" + value + "' into type 'long'", e);
247                    throw new IllegalArgumentException("Invalid format for long value '" +  value + "'", e);
248                }
249            }
250        }
251        
252        long[] longArray = new long[longValues.size()];
253        int i = 0;
254        for (Long l : longValues)
255        {
256            longArray[i] = l.longValue();
257            i++;
258        }
259        
260        if (longArray.length == 0)
261        {
262            if (metadata.hasMetadata(metadataName))
263            {
264                metadata.removeMetadata(metadataName);
265            }
266        }
267        else
268        {
269            if (isMultiple)
270            {
271                metadata.setMetadata(metadataName, longArray);
272            }
273            else
274            {
275                metadata.setMetadata(metadataName, longArray[0]);
276            }
277        }
278        
279    }
280    
281    private void _saveDoubleMetadata (ModifiableCompositeMetadata metadata, String metadataName, String[] values, boolean isMultiple)
282    {
283        List<Double> doubleValues = new ArrayList<>();
284        
285        for (String value : values)
286        {
287            if (!"".equals(value))
288            {
289                try
290                {
291                    doubleValues.add(Double.parseDouble(value));
292                }
293                catch (NumberFormatException e)
294                {
295                    getLogger().error("Cannot cast value '" + value + "' into type 'double'", e);
296                    throw new IllegalArgumentException("Invalid format for double value '" +  value + "'", e);
297                }
298            }
299        }
300        
301        double[] doubleArray = new double[doubleValues.size()];
302        int i = 0;
303        for (Double d : doubleValues)
304        {
305            doubleArray[i] = d.doubleValue();
306            i++;
307        }
308        
309        
310        if (doubleArray.length == 0)
311        {
312            if (metadata.hasMetadata(metadataName))
313            {
314                metadata.removeMetadata(metadataName);
315            }
316        }
317        else
318        {
319            if (isMultiple)
320            {
321                metadata.setMetadata(metadataName, doubleArray);
322            }
323            else
324            {
325                metadata.setMetadata(metadataName, doubleArray[0]);
326            }
327        }
328    }
329    
330    private void _saveBooleanMetadata (ModifiableCompositeMetadata metadata, String metadataName, String[] values, boolean isMultiple)
331    {
332        List<Boolean> booleanValues = new ArrayList<>();
333        
334        for (String value : values)
335        {
336            if (!"".equals(value))
337            {
338                booleanValues.add(Boolean.parseBoolean(value));
339            }
340        }
341        
342        boolean[] booleanArray = new boolean[booleanValues.size()];
343        int i = 0;
344        for (Boolean b : booleanValues)
345        {
346            booleanArray[i] = b.booleanValue();
347            i++;
348        }
349        
350        if (booleanArray.length == 0)
351        {
352            if (metadata.hasMetadata(metadataName))
353            {
354                metadata.removeMetadata(metadataName);
355            }
356        }
357        else
358        {
359            if (isMultiple)
360            {
361                metadata.setMetadata(metadataName, booleanArray);
362            }
363            else
364            {
365                metadata.setMetadata(metadataName, booleanArray[0]);
366            }
367        }
368    }
369}