001/*
002 *  Copyright 2020 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.parameters.view;
017
018import java.io.IOException;
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024import java.util.Optional;
025import java.util.stream.Collectors;
026
027import org.apache.avalon.framework.component.Component;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.avalon.framework.service.Serviceable;
031import org.apache.cocoon.ProcessingException;
032import org.apache.commons.collections4.MapUtils;
033import org.apache.commons.lang3.StringUtils;
034
035import org.ametys.cms.repository.Content;
036import org.ametys.core.observation.Event;
037import org.ametys.core.observation.ObservationManager;
038import org.ametys.core.ui.Callable;
039import org.ametys.core.user.CurrentUserProvider;
040import org.ametys.plugins.repository.AmetysObjectResolver;
041import org.ametys.plugins.repository.UnknownAmetysObjectException;
042import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder;
043import org.ametys.runtime.i18n.I18nizableText;
044import org.ametys.runtime.i18n.I18nizableTextParameter;
045import org.ametys.runtime.model.DefinitionContext;
046import org.ametys.runtime.model.ElementDefinition;
047import org.ametys.runtime.model.ModelItem;
048import org.ametys.runtime.model.SimpleViewItemGroup;
049import org.ametys.runtime.model.View;
050import org.ametys.runtime.model.ViewElement;
051import org.ametys.runtime.model.ViewItemContainer;
052import org.ametys.runtime.model.ViewItemGroup;
053import org.ametys.runtime.plugin.component.AbstractLogEnabled;
054import org.ametys.web.ObservationConstants;
055import org.ametys.web.parameters.ParametersManager;
056import org.ametys.web.repository.page.ModifiableSitemapElement;
057import org.ametys.web.repository.page.ModifiableZone;
058import org.ametys.web.repository.page.ModifiableZoneItem;
059import org.ametys.web.repository.page.SitemapElement;
060import org.ametys.web.repository.page.ZoneItem;
061import org.ametys.web.repository.page.ZoneItem.ZoneType;
062import org.ametys.web.repository.site.Site;
063import org.ametys.web.service.Service;
064import org.ametys.web.service.ServiceExtensionPoint;
065import org.ametys.web.skin.Skin;
066import org.ametys.web.skin.SkinTemplate;
067import org.ametys.web.skin.SkinTemplateZone;
068import org.ametys.web.skin.SkinsManager;
069
070/**
071 * Manager for view parameters
072 */
073public class ViewParametersDAO extends AbstractLogEnabled implements Component, Serviceable              
074{
075    /** Avalon Role */
076    public static final String ROLE = ViewParametersDAO.class.getName();
077    
078    /** The separator for model item name */
079    public static final String MODEL_ITEM_NAME_SEPARATOR = "$";
080    
081    /** The prefix for template view parameters */
082    public static final String PREFIX_TEMPLATE = "template";
083    
084    /** The prefix for zone view parameters */
085    public static final String PREFIX_ZONE = "zone";
086    
087    /** The prefix for zoneItem view parameters */
088    public static final String PREFIX_ZONE_ITEM = "zoneitem";
089    
090    /** The prefix for content view parameters */
091    public static final String PREFIX_CONTENT = "content";
092    
093    /** The prefix for service view parameters */
094    public static final String PREFIX_SERVICE = "service" + MODEL_ITEM_NAME_SEPARATOR + ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME;
095    
096    /** The Ametys object resolver */
097    protected AmetysObjectResolver _resolver;
098    
099    /** The skins manager */
100    protected SkinsManager _skinsManager;
101    
102    /** The service view parameters manager */
103    protected ServiceViewParametersManager _serviceViewParametersManager;
104    
105    /** The content view parameters manager */
106    protected ContentViewParametersManager _contentViewParametersManager;
107    
108    /** The service extension point */
109    protected ServiceExtensionPoint _serviceEP;
110    
111    /** The parameters manager */
112    protected ParametersManager _parametersManager;
113    
114    /** The observation manager */
115    protected ObservationManager _observationManager;
116    
117    /** The current user provider */
118    protected CurrentUserProvider _currentUserProvider;
119    
120    /** The view parameter manager */
121    protected ViewParametersManager _viewParametersManager;
122    
123    public void service(ServiceManager manager) throws ServiceException
124    {
125        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
126        _skinsManager = (SkinsManager) manager.lookup(SkinsManager.ROLE);
127        _serviceViewParametersManager = (ServiceViewParametersManager) manager.lookup(ServiceViewParametersManager.ROLE);
128        _contentViewParametersManager = (ContentViewParametersManager) manager.lookup(ContentViewParametersManager.ROLE);
129        _serviceEP = (ServiceExtensionPoint) manager.lookup(ServiceExtensionPoint.ROLE);
130        _parametersManager = (ParametersManager) manager.lookup(ParametersManager.ROLE);
131        _observationManager = (ObservationManager) manager.lookup(ObservationManager.ROLE);
132        _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE);
133        _viewParametersManager = (ViewParametersManager) manager.lookup(ViewParametersManager.ROLE);
134    }
135    
136    /**
137     * Get the definition of the created view of all view parameters
138     * @param pageId the page id
139     * @param zoneName the zone name (can be null)
140     * @param zoneItemId the zone item id (can be null)
141     * @return the JSON of view parameters
142     * @throws ProcessingException if a processing error occurred
143     */
144    @Callable
145    public Map<String, Object> getViewParametersDefinitions(String pageId, String zoneName, String zoneItemId) throws ProcessingException
146    {
147        Map<String, Object> response = new HashMap<>();
148        View view = _createViewParametersDialogView(pageId, zoneName, zoneItemId);
149        response.put("parameters", view.toJSON(DefinitionContext.newInstance().withEdition(true)));
150        
151        return response;
152    }
153
154    /**
155     * Create the view of all view parameters
156     * @param pageId the page id
157     * @param zoneName the zone name (can be null)
158     * @param zoneItemId the zone item id (can be null)
159     * @return the view of all view parameters
160     */
161    protected View _createViewParametersDialogView(String pageId, String zoneName, String zoneItemId)
162    {
163        View view = new View();
164        
165        ModifiableSitemapElement page = _getModifiablePage(pageId);
166        Site site = page.getSite();
167        Skin skin = _skinsManager.getSkin(site.getSkinId());
168        
169        SkinTemplate template = skin.getTemplate(page.getTemplate());
170        if (template != null)
171        {
172            _addTemplateViewItem(page, skin, template, view);
173    
174            Optional<ModifiableZoneItem> zoneItem = _getModifiableZoneItem(zoneItemId);
175            Optional<SkinTemplateZone> templateZone = _getSkinTemplateZone(template, zoneName, zoneItem);
176            if (templateZone.isPresent())
177            {
178                SkinTemplateZone skinTemplateZone = templateZone.get();
179                _addZoneViewItem(page, skin, template, skinTemplateZone, view);
180                
181                if (zoneItem.isPresent())
182                {
183                    _addZoneItemViewItem(skin, template, skinTemplateZone, zoneItem.get(), view);
184                }
185            }
186        }
187        
188        return view;
189    }
190
191    /**
192     * Add template view item
193     * @param page the page (to determine inheritance)
194     * @param skin the skin
195     * @param template the template
196     * @param viewItemContainer the container in which add the template view
197     */
198    protected void _addTemplateViewItem(ModifiableSitemapElement page, Skin skin, SkinTemplate template, ViewItemContainer viewItemContainer)
199    {
200        String templateId = template.getId();
201        Optional<ViewParametersModel> templateViewParametersOptional = _viewParametersManager.getTemplateViewParametersModel(skin.getId(), templateId);
202        if (templateViewParametersOptional.isEmpty())
203        {
204            return;
205        }
206        
207        ViewParametersModel templateViewParameters = templateViewParametersOptional.get();
208        if (templateViewParameters.isNotEmpty())
209        {
210            SimpleViewItemGroup group = new SimpleViewItemGroup();
211            group.setName(templateId);
212            
213            Map<String, I18nizableTextParameter> parameters = new HashMap<>();
214            parameters.put("title", template.getLabel());
215            group.setLabel(new I18nizableText("plugin.web", "PLUGINS_WEB_VIEW_PARAMETERS_DIALOG_BOX_TEMPLATE_LABEL", parameters));
216            group.setRole(ViewItemGroup.FIELDSET_ROLE);
217            
218            Collection< ? extends ModelItem> inheritModelItems = templateViewParameters.getInheritedModelItems(page);
219
220            List< ? extends ModelItem> noInheritModelItems = templateViewParameters.getModelItems()
221                .stream()
222                .filter(m -> !inheritModelItems.contains(m))
223                .filter(m -> !(m.getName().equals(ViewParametersManager.TEMPLATE_INHERIT_MODEL_ITEM_NAME) && inheritModelItems.isEmpty()))
224                .collect(Collectors.toList());
225            
226            String prefix = PREFIX_TEMPLATE + MODEL_ITEM_NAME_SEPARATOR + template.getId() + MODEL_ITEM_NAME_SEPARATOR;
227            _viewParametersManager.includeModelItems(noInheritModelItems, prefix, group);
228
229            if (!inheritModelItems.isEmpty())
230            {
231                List<ModelItem> includeModelItems = _viewParametersManager.includeModelItems(inheritModelItems, prefix, group);
232                _viewParametersManager.setDisableConditions(prefix + ViewParametersManager.TEMPLATE_INHERIT_MODEL_ITEM_NAME, "false", includeModelItems);
233            }
234            
235            viewItemContainer.addViewItem(group);
236        }
237    }
238    
239    /**
240     * Add zone view item
241     * @param page the page (to determine inheritance)
242     * @param skin the skin
243     * @param template the template
244     * @param zone the zone
245     * @param viewItemContainer the container in which add the zone view
246     */
247    protected void _addZoneViewItem(SitemapElement page, Skin skin, SkinTemplate template, SkinTemplateZone zone, ViewItemContainer viewItemContainer)
248    {
249        String zoneId = zone.getId();
250        Optional<ViewParametersModel> zoneViewParametersOptional = _viewParametersManager.getZoneViewParametersModel(skin.getId(), template.getId(), zoneId);
251        if (zoneViewParametersOptional.isEmpty())
252        {
253            return;
254        }
255        
256        ViewParametersModel zoneViewParameters = zoneViewParametersOptional.get();
257        if (zoneViewParameters.isNotEmpty())
258        {
259            SimpleViewItemGroup group = new SimpleViewItemGroup();
260            group.setName(zoneId);
261            
262            Map<String, I18nizableTextParameter> parameters = new HashMap<>();
263            parameters.put("title", zone.getLabel());
264            group.setLabel(new I18nizableText("plugin.web", "PLUGINS_WEB_VIEW_PARAMETERS_DIALOG_BOX_ZONE_LABEL", parameters));
265            group.setRole(ViewItemGroup.FIELDSET_ROLE);
266            
267            Collection< ? extends ModelItem> inheritModelItems = zoneViewParameters.getInheritedModelItems(page);
268
269            List< ? extends ModelItem> noInheritModelItems = zoneViewParameters.getModelItems()
270                    .stream()
271                    .filter(m -> !inheritModelItems.contains(m))
272                    .filter(m -> !(m.getName().equals(ViewParametersManager.ZONE_INHERIT_MODEL_ITEM_NAME) && inheritModelItems.isEmpty()))
273                    .collect(Collectors.toList());
274            
275            String prefix = PREFIX_ZONE + MODEL_ITEM_NAME_SEPARATOR + zoneId + MODEL_ITEM_NAME_SEPARATOR;
276            _viewParametersManager.includeModelItems(noInheritModelItems, prefix, group);
277            
278            if (!inheritModelItems.isEmpty())
279            {
280                List<ModelItem> includeModelItems = _viewParametersManager.includeModelItems(inheritModelItems, prefix, group);
281                _viewParametersManager.setDisableConditions(prefix + ViewParametersManager.ZONE_INHERIT_MODEL_ITEM_NAME, "false", includeModelItems);
282            }
283            
284            viewItemContainer.addViewItem(group);
285        }
286    }
287    
288    /**
289     * Add zone item view item and the service or content view items
290     * @param skin the skin
291     * @param template the template
292     * @param zone the zone
293     * @param zoneItem the zone item
294     * @param viewItemContainer the container in which add the zone item view
295     */
296    protected void _addZoneItemViewItem(Skin skin, SkinTemplate template, SkinTemplateZone zone, ZoneItem zoneItem, ViewItemContainer viewItemContainer)
297    {
298        ModelItemViewsWrapper modelItemViews = new ModelItemViewsWrapper();
299        
300        String skinId = skin.getId();
301        Optional<ViewParametersModel> zoneItemViewParameters = _viewParametersManager.getZoneItemViewParametersModel(skinId, template.getId(), zone.getId());
302        modelItemViews.setZoneItemViewParameters(zoneItemViewParameters);
303        
304        ZoneType type = zoneItem.getType();
305        if (type == ZoneType.SERVICE)
306        {
307            _addServiceViewParameters(modelItemViews, zoneItem, skinId);
308        }
309        else if (type == ZoneType.CONTENT)
310        {
311            _addContentViewParameters(modelItemViews, zoneItem, skinId);
312        }
313        
314        _addZoneItemViewParameters(modelItemViews, zone, zoneItem, viewItemContainer);
315    }
316    
317    /**
318     * Add all view parameters of the zone item
319     * @param modelItemViews the model item views
320     * @param zone the zone
321     * @param zoneItem the zone item
322     * @param viewItemContainer the container in which add the zone item view
323     */
324    protected void _addZoneItemViewParameters(ModelItemViewsWrapper modelItemViews, SkinTemplateZone zone, ZoneItem zoneItem, ViewItemContainer viewItemContainer)
325    {
326        if (modelItemViews.hasViewParameters())
327        {
328            SimpleViewItemGroup group = new SimpleViewItemGroup();
329            group.setName(zoneItem.getName());
330            group.setLabel(modelItemViews.getLabel());
331            group.setRole(ViewItemGroup.FIELDSET_ROLE);
332
333            if (modelItemViews.hasZoneItemViewParameters())
334            {
335                ViewParametersModel zoneItemViewParameters = modelItemViews.getZoneItemViewParameters().get();
336                
337                SimpleViewItemGroup zoneItemGroup = new SimpleViewItemGroup();
338                zoneItemGroup.setName(zoneItem.getName() + "_zoneItem");
339                
340                String prefix = PREFIX_ZONE_ITEM + MODEL_ITEM_NAME_SEPARATOR + zone.getId() + MODEL_ITEM_NAME_SEPARATOR;
341                _viewParametersManager.includeModelItems(zoneItemViewParameters.getModelItems(), prefix, zoneItemGroup);
342                
343                group.addViewItem(zoneItemGroup);
344            }
345            
346            if (modelItemViews.hasServiceOrContentViewParameters())
347            {
348                SimpleViewItemGroup serviceOrContentGroup = new SimpleViewItemGroup();
349                serviceOrContentGroup.setName(zoneItem.getName() + "_contentOrService");
350                
351                ViewElement viewElement = new ViewElement();
352                ElementDefinition<String> enumeratorViewDefinition = modelItemViews.getEnumeratorViewDefinition();
353                viewElement.setDefinition(enumeratorViewDefinition);
354                serviceOrContentGroup.addViewItem(viewElement);
355                
356                Map<String, ViewParametersModel> serviceOrContentViewParameters = modelItemViews.getServiceOrContentViewParameters();
357                for (String viewName : serviceOrContentViewParameters.keySet())
358                {
359                    ViewParametersModel viewParameters = serviceOrContentViewParameters.get(viewName);
360                    Collection< ? extends ModelItem> modelItems = viewParameters.getModelItems();
361                    
362                    String prefix = modelItemViews.getPrefix() + MODEL_ITEM_NAME_SEPARATOR + _viewParametersManager.normalizeViewName(viewName) + MODEL_ITEM_NAME_SEPARATOR;
363                    List<ModelItem> includeModelItems = _viewParametersManager.includeModelItems(modelItems, prefix, serviceOrContentGroup);
364                    _viewParametersManager.setDisableConditions(enumeratorViewDefinition.getName(), viewName, includeModelItems);
365                }
366                
367                group.addViewItem(serviceOrContentGroup);
368            }
369            
370            viewItemContainer.addViewItem(group);
371        }
372    }
373    
374    /**
375     * Add service view parameters to the model item views wrapper
376     * @param modelItemViews the model item views wrapper
377     * @param zoneItem the zone item
378     * @param skinId the skin id
379     */
380    protected void _addServiceViewParameters(ModelItemViewsWrapper modelItemViews, ZoneItem zoneItem, String skinId)
381    {
382        // The zone item contains a service
383        String serviceId = zoneItem.getServiceId();
384        Service service = _serviceEP.getExtension(serviceId);
385        
386        Map<String, I18nizableTextParameter> parameters = new HashMap<>();
387        parameters.put("title", service.getLabel());
388        modelItemViews.setLabel(new I18nizableText("plugin.web", "PLUGINS_WEB_VIEW_PARAMETERS_DIALOG_BOX_SERVICE_LABEL", parameters));
389        modelItemViews.setPrefix(PREFIX_SERVICE);
390        
391        ElementDefinition<String> serviceViewEnumerator = _viewParametersManager.getServiceViewEnumerator(serviceId);
392        if (serviceViewEnumerator != null)
393        {
394            modelItemViews.setEnumeratorViewDefinition(serviceViewEnumerator);
395            
396            Map<String, ViewParametersModel> serviceViewParametersModels = _viewParametersManager.getServiceViewParametersModels(skinId, serviceId);
397            for (String viewName : serviceViewParametersModels.keySet())
398            {
399                ViewParametersModel serviceViewParameters = serviceViewParametersModels.get(viewName);
400                modelItemViews.addServiceOrContentViewParameters(viewName, serviceViewParameters);
401            }
402        }
403    }
404    
405    /**
406     * Add content view parameters to the model item views wrapper
407     * @param modelItemViews the model item views wrapper
408     * @param zoneItem the zone item
409     * @param skinId the skin id
410     */
411    protected void _addContentViewParameters(ModelItemViewsWrapper modelItemViews, ZoneItem zoneItem, String skinId)
412    {
413        // The zone item contains a content
414        Content content = zoneItem.getContent();
415        List<String> parameters = new ArrayList<>();
416        parameters.add(content.getTitle());
417        modelItemViews.setLabel(new I18nizableText("plugin.web", "PLUGINS_WEB_VIEW_PARAMETERS_DIALOG_BOX_CONTENT_LABEL", parameters));
418        modelItemViews.setPrefix(PREFIX_CONTENT);
419        
420        ElementDefinition<String> elementDef = _viewParametersManager.getContentViewEnumerator(content);
421        modelItemViews.setEnumeratorViewDefinition(elementDef);
422        
423        Map<String, ViewParametersModel> contentViewParametersModels = _viewParametersManager.getContentViewParametersModels(skinId, content);
424        for (String viewName : contentViewParametersModels.keySet())
425        {
426            ViewParametersModel contentViewParameters = contentViewParametersModels.get(viewName);
427            modelItemViews.addServiceOrContentViewParameters(viewName, contentViewParameters);
428        }
429    }
430
431    /**
432     * Get the view parameters values
433     * @param pageId the page id
434     * @param zoneName the zone name (Can be null)
435     * @param zoneItemId the zone item id (Can be null)
436     * @return the values
437     */
438    @Callable
439    public Map<String, Object> getViewParametersValues(String pageId, String zoneName, String zoneItemId)
440    {
441        Map<String, Object> response = new HashMap<>();
442        Map<String, Object> values = new HashMap<>();
443
444        ModifiableSitemapElement page = _getModifiablePage(pageId);
445        Site site = page.getSite();
446        Skin skin = _skinsManager.getSkin(site.getSkinId());
447        
448        SkinTemplate template = skin.getTemplate(page.getTemplate());
449        if (template != null)
450        {
451            values.putAll(_getTemplateViewParametersValues(page, template));
452            
453            Optional<ModifiableZoneItem> zoneItem = _getModifiableZoneItem(zoneItemId);
454            Optional<SkinTemplateZone> templateZone = _getSkinTemplateZone(template, zoneName, zoneItem);
455            if (templateZone.isPresent())
456            {
457                SkinTemplateZone skinTemplateZone = templateZone.get();
458                values.putAll(_getZoneViewParametersValues(page, skinTemplateZone));
459    
460                if (zoneItem.isPresent())
461                {
462                    values.putAll(_getZoneItemViewParametersValues(page, skin, skinTemplateZone, zoneItem.get()));
463                }
464            }
465        }
466        
467        response.put("values", values);
468        return response;
469    }
470    
471    /**
472     * Get the template view parameters values
473     * @param page the page
474     * @param template the template
475     * @return the values
476     */
477    protected Map<String, Object> _getTemplateViewParametersValues(ModifiableSitemapElement page, SkinTemplate template)
478    {
479        Optional<ViewParametersModel> templateViewParameters = _viewParametersManager.getTemplateViewParametersModel(template);
480        if (templateViewParameters.isEmpty())
481        {
482            return MapUtils.EMPTY_SORTED_MAP;
483        }
484        
485        ModifiableModelAwareDataHolder pageViewParametersHolder = page.getTemplateParametersHolder();
486        Map<String, Object> templateValues = _parametersManager.getParametersValues(templateViewParameters.get().getModelItems(), pageViewParametersHolder, "");
487
488        String prefix = PREFIX_TEMPLATE + MODEL_ITEM_NAME_SEPARATOR + template.getId() + MODEL_ITEM_NAME_SEPARATOR;
489        return _parametersManager.addPrefixToParameters(templateValues, prefix);
490    }
491    
492    /**
493     * Get the zone view parameters values
494     * @param page the page
495     * @param skinZone the zone
496     * @return the values
497     */
498    protected Map<String, Object> _getZoneViewParametersValues(ModifiableSitemapElement page, SkinTemplateZone skinZone)
499    {
500        Optional<ViewParametersModel> zoneViewParameters = _viewParametersManager.getZoneViewParametersModel(skinZone);
501        if (zoneViewParameters.isEmpty())
502        {
503            return MapUtils.EMPTY_SORTED_MAP;
504        }
505        
506        String zoneName = skinZone.getId();
507        if (page.hasZone(zoneName))
508        {
509            ModifiableZone zone = page.getZone(zoneName);
510    
511            ModifiableModelAwareDataHolder zoneViewParametersHolder = zone.getZoneParametersHolder();
512            Map<String, Object> zoneValues = _parametersManager.getParametersValues(zoneViewParameters.get().getModelItems(), zoneViewParametersHolder, "");
513            
514            String prefix = PREFIX_ZONE + MODEL_ITEM_NAME_SEPARATOR + zoneName + MODEL_ITEM_NAME_SEPARATOR;
515            return _parametersManager.addPrefixToParameters(zoneValues, prefix);
516        }
517        
518        return MapUtils.EMPTY_SORTED_MAP;
519    }
520    
521    /**
522     * Get the zone item view parameters values
523     * @param page the page
524     * @param skin the skin
525     * @param skinZone the zone
526     * @param zoneItem the zone item
527     * @return the values
528     */
529    protected Map<String, Object> _getZoneItemViewParametersValues(ModifiableSitemapElement page, Skin skin, SkinTemplateZone skinZone, ModifiableZoneItem zoneItem)
530    {
531        Map<String, Object> values = new HashMap<>();
532        
533        ModifiableModelAwareDataHolder zoneItemViewParametersHolder = zoneItem.getZoneItemParametersHolder();
534        Optional<ViewParametersModel> zoneItemViewParameters = skinZone.getZoneItemViewParameters();
535        if (zoneItemViewParameters.isEmpty())
536        {
537            return MapUtils.EMPTY_SORTED_MAP;
538        }
539        
540        Map<String, Object> zoneItemValues = _parametersManager.getParametersValues(zoneItemViewParameters.get().getModelItems(), zoneItemViewParametersHolder, "");
541        String prefix = PREFIX_ZONE_ITEM + MODEL_ITEM_NAME_SEPARATOR + skinZone.getId() + MODEL_ITEM_NAME_SEPARATOR;
542        values.putAll(_parametersManager.addPrefixToParameters(zoneItemValues, prefix));
543        
544        if (zoneItem.getType() == ZoneType.SERVICE)
545        {
546            values.putAll(_getServiceViewParametersValues(skin, zoneItem));
547        }
548        else if (zoneItem.getType() == ZoneType.CONTENT)
549        {
550            values.putAll(_getContentViewParametersValues(skin, zoneItem));
551        }
552        
553        return values;
554    }
555    
556    /**
557     * Get the service view parameters values
558     * @param skin the skin
559     * @param zoneItem the zone item
560     * @return the values
561     */
562    protected Map<String, Object> _getServiceViewParametersValues(Skin skin, ModifiableZoneItem zoneItem)
563    {
564        Map<String, Object> values = new HashMap<>();
565        
566        ModifiableModelAwareDataHolder serviceParameters = zoneItem.getServiceParameters();
567        if (serviceParameters.hasDefinition(ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME))
568        {
569            values.put(ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME, serviceParameters.getValue(ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME));
570        }
571        
572        Map<String, ViewParametersModel> serviceViewParametersModels = _viewParametersManager.getServiceViewParametersModels(skin.getId(), zoneItem.getServiceId());
573        for (String viewName : serviceViewParametersModels.keySet())
574        {
575            ViewParametersModel serviceViewParameters = serviceViewParametersModels.get(viewName);
576            ModifiableModelAwareDataHolder serviceViewParametersHolder = zoneItem.getServiceViewParametersHolder(viewName);
577            
578            Map<String, Object> serviceValues = _parametersManager.getParametersValues(serviceViewParameters.getModelItems(), serviceViewParametersHolder, "");
579            String prefix = PREFIX_SERVICE + MODEL_ITEM_NAME_SEPARATOR + _viewParametersManager.normalizeViewName(viewName) + MODEL_ITEM_NAME_SEPARATOR;
580            values.putAll(_parametersManager.addPrefixToParameters(serviceValues, prefix));
581        }
582        
583        return values;
584    }
585    
586    /**
587     * Get the content view parameters values
588     * @param skin the skin
589     * @param zoneItem the zone item
590     * @return the values
591     */
592    protected Map<String, Object> _getContentViewParametersValues(Skin skin, ModifiableZoneItem zoneItem)
593    {
594        Map<String, Object> values = new HashMap<>();
595        
596        values.put(ViewParametersManager.CONTENT_VIEW_MODEL_ITEM_NAME, zoneItem.getViewName());
597        
598        Map<String, ViewParametersModel> contentViewParametersModels = _viewParametersManager.getContentViewParametersModels(skin.getId(), zoneItem.getContent());
599        for (String viewName : contentViewParametersModels.keySet())
600        {
601            ViewParametersModel contentViewParameters = contentViewParametersModels.get(viewName);
602            ModifiableModelAwareDataHolder contentViewParametersHolder = zoneItem.getContentViewParametersHolder(viewName);
603                
604            Map<String, Object> serviceValues = _parametersManager.getParametersValues(contentViewParameters.getModelItems(), contentViewParametersHolder, "");
605            String prefix = PREFIX_CONTENT + MODEL_ITEM_NAME_SEPARATOR + _viewParametersManager.normalizeViewName(viewName) + MODEL_ITEM_NAME_SEPARATOR;
606            values.putAll(_parametersManager.addPrefixToParameters(serviceValues, prefix));
607        }
608        
609        return values;
610    }
611    
612    /**
613     * Set view parameters values
614     * @param pageId the page id
615     * @param zoneName the zone name (Can be null)
616     * @param zoneItemId the zone item id (Can be null)
617     * @param parameterValues the parameter values
618     * @return results map
619     * @throws IOException If an error occurred
620     */
621    @Callable
622    public Map<String, Object> setViewParametersValues(String pageId, String zoneName, String zoneItemId, Map<String, Object> parameterValues) throws IOException
623    {
624        Map<String, Object> results = new HashMap<>();
625        Map<String, List<I18nizableText>> allErrors = new HashMap<>();
626        
627        ModifiableSitemapElement sitemapElement = _getModifiablePage(pageId);
628        Site site = sitemapElement.getSite();
629        Skin skin = _skinsManager.getSkin(site.getSkinId());
630        SkinTemplate template = skin.getTemplate(sitemapElement.getTemplate());
631        
632        if (template != null)
633        {
634            allErrors.putAll(_setTemplateViewParameters(sitemapElement, template, parameterValues));
635    
636            Optional<ModifiableZoneItem> zoneItem = _getModifiableZoneItem(zoneItemId);
637            Optional<SkinTemplateZone> templateZone = _getSkinTemplateZone(template, zoneName, zoneItem);
638            if (templateZone.isPresent())
639            {
640                SkinTemplateZone skinTemplateZone = templateZone.get();
641                allErrors.putAll(_setZoneViewParameters(sitemapElement, skinTemplateZone, parameterValues));
642                
643                if (zoneItem.isPresent())
644                {
645                    allErrors.putAll(_setZoneItemViewParameters(sitemapElement, skin, skinTemplateZone, zoneItem.get(), parameterValues));
646                }
647            }
648        }
649        
650        if (!allErrors.isEmpty())
651        {
652            results.put("errors", allErrors);
653            return results;
654        }
655        
656        sitemapElement.saveChanges();
657        
658        Map<String, Object> eventParams = new HashMap<>();
659        eventParams.put(ObservationConstants.ARGS_SITEMAP_ELEMENT, sitemapElement);
660        _observationManager.notify(new Event(ObservationConstants.EVENT_VIEW_PARAMETERS_MODIFIED, _currentUserProvider.getUser(), eventParams));
661        
662        return results;
663    }
664    
665    /**
666     * Set template view parameters values
667     * @param page the page
668     * @param template the template
669     * @param parameterValues the parameter values
670     * @return the errors
671     */
672    protected Map<String, List<I18nizableText>> _setTemplateViewParameters(ModifiableSitemapElement page, SkinTemplate template, Map<String, Object> parameterValues)
673    {
674        Optional<ViewParametersModel> templateViewParameters = _viewParametersManager.getTemplateViewParametersModel(template);
675        if (templateViewParameters.isEmpty())
676        {
677            return MapUtils.EMPTY_SORTED_MAP;
678        }
679        
680        String templatePrefix = PREFIX_TEMPLATE + MODEL_ITEM_NAME_SEPARATOR + template.getId() + MODEL_ITEM_NAME_SEPARATOR;
681        Map<String, Object> templateParameters = _parametersManager.getParametersStartWithPrefix(parameterValues, templatePrefix);
682        
683        // Do this because can't set null value to boolean model item. FIXME CMS-10275
684        if (!templateParameters.containsKey(ViewParametersManager.TEMPLATE_INHERIT_MODEL_ITEM_NAME))
685        {
686            templateParameters.put(ViewParametersManager.TEMPLATE_INHERIT_MODEL_ITEM_NAME, true);
687        }
688        
689        ModifiableModelAwareDataHolder pageViewParametersHolder = page.getTemplateParametersHolder();
690        return _parametersManager.setParameterValues(pageViewParametersHolder, templateViewParameters.get().getModelItems(), templateParameters);
691    }
692    
693    /**
694     * Set zone view parameters values
695     * @param page the page
696     * @param skinZone the zone
697     * @param parameterValues the parameter values
698     * @return the errors
699     */
700    protected Map<String, List<I18nizableText>> _setZoneViewParameters(ModifiableSitemapElement page, SkinTemplateZone skinZone, Map<String, Object> parameterValues)
701    {
702        Optional<ViewParametersModel> zoneViewParameters = _viewParametersManager.getZoneViewParametersModel(skinZone);
703        if (zoneViewParameters.isEmpty())
704        {
705            return MapUtils.EMPTY_SORTED_MAP;
706        }
707
708        String zoneName = skinZone.getId();
709        ModifiableZone zone = page.hasZone(zoneName) ? page.getZone(zoneName) : page.createZone(zoneName);
710        
711        String zonePrefix = PREFIX_ZONE + MODEL_ITEM_NAME_SEPARATOR + zoneName + MODEL_ITEM_NAME_SEPARATOR;
712        Map<String, Object> zoneParameters = _parametersManager.getParametersStartWithPrefix(parameterValues, zonePrefix);
713        
714        // Do this because can't set null value to boolean model item. FIXME CMS-10275
715        if (!zoneParameters.containsKey(ViewParametersManager.ZONE_INHERIT_MODEL_ITEM_NAME))
716        {
717            zoneParameters.put(ViewParametersManager.ZONE_INHERIT_MODEL_ITEM_NAME, true);
718        }
719        
720        ModifiableModelAwareDataHolder zoneViewParametersHolder = zone.getZoneParametersHolder();
721        return _parametersManager.setParameterValues(zoneViewParametersHolder, zoneViewParameters.get().getModelItems(), zoneParameters);
722    }
723    
724    /**
725     * Set zone item view parameters values
726     * @param page the page
727     * @param skin the skin
728     * @param skinZone the zone
729     * @param zoneItem the zone item
730     * @param parameterValues the parameter values
731     * @return the errors
732     */
733    protected Map<String, List<I18nizableText>> _setZoneItemViewParameters(ModifiableSitemapElement page, Skin skin, SkinTemplateZone skinZone, ModifiableZoneItem zoneItem, Map<String, Object> parameterValues)
734    {
735        Map<String, List<I18nizableText>> allErrors = new HashMap<>();
736        
737        Optional<ViewParametersModel> zoneItemViewParameters = skinZone.getZoneItemViewParameters();
738        if (zoneItemViewParameters.isEmpty())
739        {
740            return allErrors;
741        }
742        
743        ModifiableModelAwareDataHolder zoneItemViewParametersHolder = zoneItem.getZoneItemParametersHolder();
744        
745        String zoneItemPrefix = PREFIX_ZONE_ITEM + MODEL_ITEM_NAME_SEPARATOR + skinZone.getId() + MODEL_ITEM_NAME_SEPARATOR;
746        Map<String, Object> zoneItemParameters = _parametersManager.getParametersStartWithPrefix(parameterValues, zoneItemPrefix);
747        
748        allErrors.putAll(_parametersManager.setParameterValues(zoneItemViewParametersHolder, zoneItemViewParameters.get().getModelItems(), zoneItemParameters));
749        
750        if (zoneItem.getType() == ZoneType.SERVICE)
751        {
752            allErrors.putAll(_setServiceViewParameters(skin, zoneItem, parameterValues));
753        }
754        else if (zoneItem.getType() == ZoneType.CONTENT)
755        {
756            allErrors.putAll(_setContentViewParameters(skin, zoneItem, parameterValues));
757        }
758        
759        return allErrors;
760    }
761    
762    /**
763     * Set service view parameters values
764     * @param skin the skin
765     * @param zoneItem the zone item
766     * @param parameterValues the parameter values
767     * @return the errors
768     */
769    protected Map<String, List<I18nizableText>> _setServiceViewParameters(Skin skin, ModifiableZoneItem zoneItem, Map<String, Object> parameterValues)
770    {
771        String viewName = (String) parameterValues.get(ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME);
772        if (StringUtils.isEmpty(viewName))
773        {
774            // We have a service with no view parameters
775            return MapUtils.EMPTY_SORTED_MAP;
776        }
777        
778        String serviceId = zoneItem.getServiceId();
779        ModifiableModelAwareDataHolder serviceParameters = zoneItem.getServiceParameters();
780        serviceParameters.setValue(ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME, viewName);
781        
782        Optional<ViewParametersModel> serviceViewParameters = _viewParametersManager.getServiceViewParametersModel(skin.getId(), serviceId, viewName);
783        if (serviceViewParameters.isEmpty())
784        {
785            return MapUtils.EMPTY_SORTED_MAP;
786        }
787        
788        ModifiableModelAwareDataHolder serviceViewParametersHolder = zoneItem.getServiceViewParametersHolder(viewName);
789        
790        String servicePrefix = PREFIX_SERVICE + MODEL_ITEM_NAME_SEPARATOR + _viewParametersManager.normalizeViewName(viewName) + MODEL_ITEM_NAME_SEPARATOR;
791        Map<String, Object> parameters = _parametersManager.getParametersStartWithPrefix(parameterValues, servicePrefix);
792        
793        return _parametersManager.setParameterValues(serviceViewParametersHolder, serviceViewParameters.get().getModelItems(), parameters);
794    }
795    
796    /**
797     * Set content view parameters values
798     * @param skin the skin
799     * @param zoneItem the zone item
800     * @param parameterValues the parameter values
801     * @return the errors
802     */
803    protected Map<String, List<I18nizableText>> _setContentViewParameters(Skin skin, ModifiableZoneItem zoneItem, Map<String, Object> parameterValues)
804    {
805        String viewName = (String) parameterValues.get(ViewParametersManager.CONTENT_VIEW_MODEL_ITEM_NAME);
806        if (StringUtils.isEmpty(viewName))
807        {
808            // We have a content with no view parameters
809            return MapUtils.EMPTY_SORTED_MAP;
810        }
811
812        Content content = zoneItem.getContent();
813        zoneItem.setViewName(viewName);
814        Optional<ViewParametersModel> contentViewParameters = _viewParametersManager.getContentViewParametersModel(skin.getId(), content, viewName);
815        if (contentViewParameters.isEmpty())
816        {
817            return MapUtils.EMPTY_SORTED_MAP;
818        }
819        
820        ModifiableModelAwareDataHolder contentViewParametersHolder = zoneItem.getContentViewParametersHolder(viewName);
821        
822        String contentPrefix = PREFIX_CONTENT + MODEL_ITEM_NAME_SEPARATOR + _viewParametersManager.normalizeViewName(viewName) + MODEL_ITEM_NAME_SEPARATOR;
823        Map<String, Object> contentParameters = _parametersManager.getParametersStartWithPrefix(parameterValues, contentPrefix);
824        
825        return _parametersManager.setParameterValues(contentViewParametersHolder, contentViewParameters.get().getModelItems(), contentParameters);
826    }
827    
828    /**
829     * Get the modifiable page from id
830     * @param pageId the page id
831     * @return the modifiable page
832     */
833    protected ModifiableSitemapElement _getModifiablePage(String pageId)
834    {
835        try
836        {
837            SitemapElement page = _resolver.resolveById(pageId);
838            if (!(page instanceof ModifiableSitemapElement))
839            {
840                throw new IllegalArgumentException("The non-modifiable page (" + pageId + ") can't have view parameters");
841            }
842            
843            return (ModifiableSitemapElement) page;
844            
845        }
846        catch (UnknownAmetysObjectException e)
847        {
848            throw new IllegalArgumentException("An error occured getting the modifiable page from id " + pageId, e);
849        }
850    }
851    
852    /**
853     * Get the modifiable zone item from id
854     * @param zoneItemId the zone item id
855     * @return the modifiable zone item
856     */
857    protected Optional<ModifiableZoneItem> _getModifiableZoneItem(String zoneItemId)
858    {
859        if (StringUtils.isNotBlank(zoneItemId))
860        {
861            try
862            {
863                ZoneItem zoneItem = _resolver.resolveById(zoneItemId);
864                if (!(zoneItem instanceof ModifiableZoneItem))
865                {
866                    throw new IllegalArgumentException("The non-modifiable zone item (" + zoneItemId + ") can't have view parameters");
867                }
868                
869                return Optional.of((ModifiableZoneItem) zoneItem);
870                
871            }
872            catch (UnknownAmetysObjectException e)
873            {
874                throw new IllegalArgumentException("An error occured getting the modifiable zone item from id " + zoneItemId, e);
875            }
876        }
877        
878        return Optional.empty();
879    }
880    
881    /**
882     * Get the skin template zone
883     * @param template the template
884     * @param zoneName the zone name
885     * @param zoneItem the zone item
886     * @return the skin template zone
887     */
888    protected Optional<SkinTemplateZone> _getSkinTemplateZone(SkinTemplate template, String zoneName, Optional<ModifiableZoneItem> zoneItem)
889    {
890        if (StringUtils.isNotBlank(zoneName))
891        {
892            return Optional.ofNullable(template.getZone(zoneName));
893        }
894        else if (zoneItem.isPresent())
895        {
896            String name = zoneItem.get().getZone().getName();
897            return Optional.ofNullable(template.getZone(name));
898        }
899        
900        return Optional.empty();
901    }
902    
903    /**
904     * Class representing a model item and its view parameters
905     */
906    static class ModelItemViewsWrapper
907    {
908        I18nizableText _label;
909        Optional<ViewParametersModel> _zoneItemViewParameters;
910        Map<String, ViewParametersModel> _contentOrServiceViewParameters;
911        ElementDefinition<String> _enumeratorViewDefinition;
912        String _prefix;
913        
914        ModelItemViewsWrapper()
915        {
916            this._label = null;
917            this._zoneItemViewParameters = null;
918            this._contentOrServiceViewParameters = new HashMap<>();
919            this._enumeratorViewDefinition = null;
920            this._prefix = StringUtils.EMPTY;
921        }
922        
923        I18nizableText getLabel()
924        {
925            return this._label;
926        }
927
928        void setLabel(I18nizableText label)
929        {
930            this._label = label;
931        }
932        
933        Optional<ViewParametersModel> getZoneItemViewParameters()
934        {
935            return this._zoneItemViewParameters;
936        }
937        
938        void setZoneItemViewParameters(Optional<ViewParametersModel> viewParameters)
939        {
940            this._zoneItemViewParameters = viewParameters;
941        }
942        
943        Map<String, ViewParametersModel> getServiceOrContentViewParameters()
944        {
945            return this._contentOrServiceViewParameters;
946        }
947        
948        void addServiceOrContentViewParameters(String viewName, ViewParametersModel serviceViewParameters)
949        {
950            this._contentOrServiceViewParameters.put(viewName, serviceViewParameters);
951        }
952
953        ElementDefinition<String> getEnumeratorViewDefinition()
954        {
955            return this._enumeratorViewDefinition;
956        }
957        
958        void setEnumeratorViewDefinition(ElementDefinition<String> elementDefinition)
959        {
960            this._enumeratorViewDefinition = elementDefinition;
961        }
962        
963        String getPrefix()
964        {
965            return this._prefix;
966        }
967        
968        void setPrefix(String prefix)
969        {
970            this._prefix = prefix;
971        }
972        
973        boolean hasZoneItemViewParameters()
974        {
975            return _zoneItemViewParameters.isPresent() && _zoneItemViewParameters.get().isNotEmpty();
976        }
977        
978        boolean hasServiceOrContentViewParameters()
979        {
980            boolean hasViewParameters = false;
981            for (ViewParametersModel viewParameters : _contentOrServiceViewParameters.values())
982            {
983                hasViewParameters = viewParameters.isNotEmpty() || hasViewParameters;
984            }
985            
986            return hasViewParameters;
987        }
988        
989        boolean hasViewParameters()
990        {
991            return hasZoneItemViewParameters() || hasServiceOrContentViewParameters();
992        }
993    }
994}