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