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