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