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; 017 018import java.util.LinkedHashMap; 019import java.util.Map; 020 021import org.apache.avalon.framework.component.Component; 022import org.apache.avalon.framework.configuration.Configuration; 023import org.apache.avalon.framework.configuration.ConfigurationException; 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.avalon.framework.service.Serviceable; 027import org.apache.commons.lang3.StringUtils; 028 029import org.ametys.cms.data.holder.group.DataHolderRepeaterDefinitionParser; 030import org.ametys.cms.model.AbstractElementDefinitionParser; 031import org.ametys.plugins.repository.model.RepeaterDefinition; 032import org.ametys.plugins.repository.model.RepeaterViewItem; 033import org.ametys.runtime.i18n.I18nizableText; 034import org.ametys.runtime.model.ElementDefinition; 035import org.ametys.runtime.model.Model; 036import org.ametys.runtime.model.ModelItem; 037import org.ametys.runtime.model.ModelItemGroup; 038import org.ametys.runtime.model.ModelViewItem; 039import org.ametys.runtime.model.ModelViewItemGroup; 040import org.ametys.runtime.model.SimpleViewItemGroup; 041import org.ametys.runtime.model.View; 042import org.ametys.runtime.model.ViewElement; 043import org.ametys.runtime.model.ViewItem; 044import org.ametys.runtime.model.ViewItemContainer; 045import org.ametys.runtime.model.ViewItemGroup; 046import org.ametys.runtime.model.disableconditions.DisableConditions; 047import org.ametys.runtime.plugin.component.AbstractLogEnabled; 048 049/** 050 * Helper to parse parameters from configuration 051 */ 052public class ViewAndParametersParser extends AbstractLogEnabled implements Component, Serviceable 053{ 054 /** Avalon Role */ 055 public static final String ROLE = ViewAndParametersParser.class.getName(); 056 057 /** The service manager */ 058 protected ServiceManager _manager; 059 060 @Override 061 public void service(ServiceManager smanager) throws ServiceException 062 { 063 _manager = smanager; 064 } 065 066 /** 067 * Parse the configuration to get parameters. 068 * @param parametersConfiguration the parameters configuration. 069 * @param pluginName the plugin name 070 * @param catalog the catalog 071 * @param model the model 072 * @param elementDefinitionParser the element definition parser 073 * @param repeaterDefinitionParser the repeater definition parser 074 * @return the parameters 075 * @throws ConfigurationException if an error occurs. 076 */ 077 public ViewAndParameters parseParameters(Configuration parametersConfiguration, String pluginName, String catalog, Model model, AbstractElementDefinitionParser<? extends DisableConditions> elementDefinitionParser, DataHolderRepeaterDefinitionParser repeaterDefinitionParser) throws ConfigurationException 078 { 079 View view = new View(); 080 Map<String, ModelItem> modelItems = new LinkedHashMap<>(); 081 082 view.setName(parametersConfiguration.getAttribute("name", null)); 083 view.setLabel(_parseI18nizableText(parametersConfiguration, "label", pluginName, catalog)); 084 view.setDescription(_parseI18nizableText(parametersConfiguration, "description", pluginName, catalog)); 085 086 // Parse all groups, fielsets and parameters to build the view 087 Configuration[] groupConfigurations = parametersConfiguration.getChildren("group"); 088 if (groupConfigurations.length > 0) 089 { 090 if (parametersConfiguration.getChildren("fieldset").length > 0 091 || parametersConfiguration.getChildren("parameter").length > 0 092 || parametersConfiguration.getChildren("repeater").length > 0) 093 { 094 throw new ConfigurationException("This parameters configuration should not have parameters out of its groups.", parametersConfiguration); 095 } 096 097 // Has groups. 098 for (Configuration groupConfiguration : groupConfigurations) 099 { 100 SimpleViewItemGroup group = _parseSimpleViewItemGroup(groupConfiguration, null, pluginName, catalog, view, modelItems, model, elementDefinitionParser, repeaterDefinitionParser); 101 group.setRole(ViewItemGroup.TAB_ROLE); 102 view.addViewItem(group); 103 } 104 } 105 else 106 { 107 _parseChildren(parametersConfiguration, view, null, pluginName, catalog, view, modelItems, model, elementDefinitionParser, repeaterDefinitionParser); 108 } 109 110 return new ViewAndParameters(view, modelItems); 111 } 112 113 /** 114 * Parses a simple view item group (group or fieldset) 115 * @param groupConfiguration the item group configuration 116 * @param modelParent The last model item group to use as parent for next definitions 117 * @param pluginName the plugin name 118 * @param catalog the catalog 119 * @param view the view 120 * @param modelItems the map of model items 121 * @param model the model 122 * @param elementDefinitionParser the element definition parser 123 * @param repeaterDefinitionParser the repeater definition parser 124 * @return the parsed simple view item group 125 * @throws ConfigurationException if an error occurs 126 */ 127 protected SimpleViewItemGroup _parseSimpleViewItemGroup(Configuration groupConfiguration, ModelItemGroup modelParent, String pluginName, String catalog, View view, Map<String, ModelItem> modelItems, Model model, AbstractElementDefinitionParser<? extends DisableConditions> elementDefinitionParser, DataHolderRepeaterDefinitionParser repeaterDefinitionParser) throws ConfigurationException 128 { 129 SimpleViewItemGroup group = new SimpleViewItemGroup(); 130 group.setName(groupConfiguration.getAttribute("name", null)); 131 group.setLabel(_parseI18nizableText(groupConfiguration, "label", pluginName, catalog)); 132 group.setDescription(_parseI18nizableText(groupConfiguration, "description", pluginName, catalog)); 133 134 _parseChildren(groupConfiguration, group, modelParent, pluginName, catalog, view, modelItems, model, elementDefinitionParser, repeaterDefinitionParser); 135 136 return group; 137 } 138 139 /** 140 * Parses a service parameter 141 * @param paramConfiguration the parameter configuration 142 * @param parent the parent of the service parameter. Can be <code>null</code> if the parameter has no parent 143 * @param pluginName the plugin name 144 * @param catalog the catalog 145 * @param view the view 146 * @param modelItems the map of model item 147 * @param model the model 148 * @param elementDefinitionParser the element definition parser 149 * @param repeaterDefinitionParser the repeater definition parser 150 * @return the parsed parameter 151 * @throws ConfigurationException if an error occurs 152 */ 153 public ViewElement parseParameter(Configuration paramConfiguration, ModelItemGroup parent, String pluginName, String catalog, View view, Map<String, ModelItem> modelItems, Model model, AbstractElementDefinitionParser<? extends DisableConditions> elementDefinitionParser, DataHolderRepeaterDefinitionParser repeaterDefinitionParser) throws ConfigurationException 154 { 155 ElementDefinition elementParameter = elementDefinitionParser.parse(_manager, pluginName, catalog, paramConfiguration, model, parent); 156 157 if (elementParameter != null) 158 { 159 ViewElement viewElement = new ViewElement(); 160 viewElement.setDefinition(elementParameter); 161 162 return viewElement; 163 } 164 165 return null; 166 } 167 168 /** 169 * Parses a repeater 170 * @param repeaterConfiguration the repeater configuration 171 * @param parent the parent of the repeater. Can be <code>null</code> if the repeater has no parent 172 * @param pluginName the plugin name 173 * @param catalog the catalog 174 * @param view the view 175 * @param modelItems the map of model item 176 * @param model the model 177 * @param elementDefinitionParser the element definition parser 178 * @param repeaterDefinitionParser the repeater definition parser 179 * @return the parsed repeater 180 * @throws ConfigurationException if an error occurs 181 */ 182 public ModelViewItemGroup parseRepeater(Configuration repeaterConfiguration, ModelItemGroup parent, String pluginName, String catalog, View view, Map<String, ModelItem> modelItems, Model model, AbstractElementDefinitionParser<? extends DisableConditions> elementDefinitionParser, DataHolderRepeaterDefinitionParser repeaterDefinitionParser) throws ConfigurationException 183 { 184 RepeaterDefinition repeaterDefinition = repeaterDefinitionParser.parse(_manager, pluginName, catalog, repeaterConfiguration, model, parent); 185 186 if (repeaterDefinition != null) 187 { 188 ModelViewItemGroup<RepeaterDefinition> viewItemGroup = new RepeaterViewItem(); 189 viewItemGroup.setDefinition(repeaterDefinition); 190 191 _parseChildren(repeaterConfiguration, viewItemGroup, repeaterDefinition, pluginName, catalog, view, modelItems, model, elementDefinitionParser, repeaterDefinitionParser); 192 193 return viewItemGroup; 194 } 195 196 return null; 197 } 198 199 /** 200 * Parses children of a view item container 201 * @param containerConfiguration the item container configuration 202 * @param viewItemContainer the item container 203 * @param modelParent The last model item container to use as parent for next definitions 204 * @param pluginName the plugin name 205 * @param catalog the catalog 206 * @param view the view 207 * @param modelItems the map of model items 208 * @param model the model 209 * @param elementDefinitionParser the element definition parser 210 * @param repeaterDefinitionParser the repeater definition parser 211 * @throws ConfigurationException if an error occurs 212 */ 213 protected void _parseChildren(Configuration containerConfiguration, ViewItemContainer viewItemContainer, ModelItemGroup modelParent, String pluginName, String catalog, View view, Map<String, ModelItem> modelItems, Model model, AbstractElementDefinitionParser<? extends DisableConditions> elementDefinitionParser, DataHolderRepeaterDefinitionParser repeaterDefinitionParser) throws ConfigurationException 214 { 215 Configuration[] children = containerConfiguration.getChildren(); 216 for (Configuration child : children) 217 { 218 ViewItem viewItem = null; 219 switch (child.getName()) 220 { 221 case "fieldset": 222 viewItem = _parseSimpleViewItemGroup(child, modelParent, pluginName, catalog, view, modelItems, model, elementDefinitionParser, repeaterDefinitionParser); 223 ((ViewItemGroup) viewItem).setRole(ViewItemGroup.FIELDSET_ROLE); 224 break; 225 case "parameter": 226 viewItem = parseParameter(child, modelParent, pluginName, catalog, view, modelItems, model, elementDefinitionParser, repeaterDefinitionParser); 227 break; 228 case "repeater": 229 viewItem = parseRepeater(child, modelParent, pluginName, catalog, view, modelItems, model, elementDefinitionParser, repeaterDefinitionParser); 230 break; 231 case "group": 232 throw new ConfigurationException("This parameters configuration should not have subgroups", child); 233 default: 234 break; 235 } 236 237 if (viewItem != null) 238 { 239 viewItemContainer.addViewItem(viewItem); 240 if (viewItem instanceof ModelViewItem && modelParent == null) 241 { 242 ModelItem definition = ((ModelViewItem) viewItem).getDefinition(); 243 String name = definition.getName(); 244 if (modelItems.containsKey(name)) 245 { 246 getLogger().warn("Parameter with name '{}' is defined twice in the configuration. It will be ignored", name); 247 } 248 else 249 { 250 modelItems.put(name, definition); 251 } 252 } 253 } 254 } 255 } 256 257 /** 258 * Parse an i18n text. 259 * @param config the configuration to use. 260 * @param name the child name. 261 * @param pluginName the plugin name 262 * @param catalog the catalog 263 * @return the i18n text. 264 */ 265 protected I18nizableText _parseI18nizableText(Configuration config, String name, String pluginName, String catalog) 266 { 267 String catalogName = StringUtils.isNotBlank(catalog) ? catalog : "plugin." + pluginName; 268 return I18nizableText.parseI18nizableText(config.getChild(name), catalogName, ""); 269 } 270 271 /** 272 * The view and parameters object 273 */ 274 public static class ViewAndParameters 275 { 276 View _view; 277 Map<String, ModelItem> _modelItems; 278 279 ViewAndParameters(View view, Map<String, ModelItem> modelItems) 280 { 281 this._view = view; 282 this._modelItems = modelItems; 283 } 284 285 /** 286 * Get the view 287 * @return the view 288 */ 289 public View getView() 290 { 291 return this._view; 292 } 293 294 /** 295 * Get the map of model items 296 * @return the map of model items 297 */ 298 public Map<String, ModelItem> getParameters() 299 { 300 return this._modelItems; 301 } 302 } 303}