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