001/* 002 * Copyright 2018 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.runtime.model; 017 018import java.util.ArrayList; 019import java.util.Arrays; 020import java.util.Collection; 021import java.util.Collections; 022import java.util.HashMap; 023import java.util.LinkedHashMap; 024import java.util.List; 025import java.util.Map; 026 027import org.apache.cocoon.ProcessingException; 028 029import org.ametys.runtime.model.type.DataContext; 030import org.ametys.runtime.model.type.ElementType; 031import org.ametys.runtime.model.type.ModelItemType; 032import org.ametys.runtime.model.type.ModelItemTypeConstants; 033 034/** 035 * Class for group of model items 036 */ 037public class ModelItemGroup extends AbstractModelItem implements ModelItemContainer 038{ 039 /** Id for model item group types */ 040 private static final String __DEFAULT_TYPE_ID = "composite"; 041 042 private List<ModelItem> _children = new ArrayList<>(); 043 private ElementDefinition<Boolean> _switcher; 044 private ModelItemType _type; 045 046 /** 047 * Default constructor. 048 */ 049 public ModelItemGroup() 050 { 051 super(); 052 } 053 054 /** 055 * Constructor used to create simple models and items 056 * @param name the name of the definition 057 * @param children the group's children 058 */ 059 public ModelItemGroup(String name, ModelItem... children) 060 { 061 super(name); 062 Arrays.stream(children) 063 .forEach(item -> addChild(item)); 064 } 065 066 public Collection<ModelItem> getModelItems() 067 { 068 return getChildren(); 069 } 070 071 /** 072 * Retrieves the list of children model items 073 * @return the children 074 */ 075 public List<ModelItem> getChildren() 076 { 077 return getChildren(true); 078 } 079 080 /** 081 * Retrieves the list of children model items, with or without the switcher 082 * @param withSwitch true to retrieve the switcher with the other children 083 * @return the children with or without the switcher 084 */ 085 public List<ModelItem> getChildren(boolean withSwitch) 086 { 087 if (withSwitch || _switcher == null) 088 { 089 return Collections.unmodifiableList(_children); 090 } 091 092 List<ModelItem> childrenWithoutSwitcher = new ArrayList<>(_children); 093 childrenWithoutSwitcher.remove(_switcher); 094 return childrenWithoutSwitcher; 095 } 096 097 /** 098 * Add a child in the group 099 * @param child the item to add 100 */ 101 public void addChild(ModelItem child) 102 { 103 addChild(child, false); 104 } 105 106 /** 107 * Add a child in the group 108 * @param child the child to add 109 * @param isGroupSwitch true if the child to add is the group switch, false otherwise 110 */ 111 @SuppressWarnings("unchecked") 112 public void addChild(ModelItem child, boolean isGroupSwitch) 113 { 114 _children.add(child); 115 child.setParent(this); 116 117 if (isGroupSwitch) 118 { 119 if (_switcher == null) 120 { 121 if (child instanceof ElementDefinition) 122 { 123 ElementType type = ((ElementDefinition) child).getType(); 124 if (ModelItemTypeConstants.BOOLEAN_TYPE_ID.equals(type.getId())) 125 { 126 _switcher = (ElementDefinition<Boolean>) child; 127 } 128 } 129 130 if (_switcher == null) 131 { 132 // If switcher is still null, the type of child is not compatible 133 throw new RuntimeException("The group '" + getLabel() + "' has a switch '" + child + "' that is not valid because it is not a boolean."); 134 } 135 } 136 else 137 { 138 throw new RuntimeException("At least two group-switches have been defined for the configuration group '" + getLabel() + "'. These parameters are '" + _switcher + "' and '" + child + "'."); 139 } 140 } 141 } 142 143 /** 144 * Retrieves the switcher element definition 145 * @return the switcher 146 */ 147 public ElementDefinition<Boolean> getSwitcher() 148 { 149 return _switcher; 150 } 151 152 @Override 153 public void setModel(Model model) 154 { 155 super.setModel(model); 156 for (ModelItem modelItem : _children) 157 { 158 modelItem.setModel(model); 159 } 160 } 161 162 @Override 163 public ModelItemType getType() 164 { 165 return _type; 166 } 167 168 public void setType(ModelItemType type) 169 { 170 _type = type; 171 } 172 173 @Override 174 protected Map<String, Object> _toJSON(DefinitionContext context) throws ProcessingException 175 { 176 return _toJSON(context, true); 177 } 178 179 /** 180 * Converts the model item group in a JSON map 181 * @param context the context of the definition 182 * @param includeChildren true to iterate and add children as elements in the returned JSON map, false otherwise 183 * @return The model item as a JSON map 184 * @throws ProcessingException If an error occurs when converting the model item group 185 */ 186 public Map<String, Object> toJSON(DefinitionContext context, boolean includeChildren) throws ProcessingException 187 { 188 if (_shouldJSONBeEmpty(context)) 189 { 190 return Map.of(); 191 } 192 else 193 { 194 return _toJSON(context, includeChildren); 195 } 196 } 197 198 /** 199 * Converts the model item group in a JSON map 200 * @param context the context of the definition 201 * @param includeChildren true to iterate and add children as elements in the returned JSON map, false otherwise 202 * @return The model item as a JSON map 203 * @throws ProcessingException If an error occurs when converting the model item group 204 */ 205 protected Map<String, Object> _toJSON(DefinitionContext context, boolean includeChildren) throws ProcessingException 206 { 207 Map<String, Object> result = super._toJSON(context); 208 209 ModelItemType type = getType(); 210 result.put("type", type != null ? type.getId() : __DEFAULT_TYPE_ID); 211 212 ElementDefinition<Boolean> switcher = getSwitcher(); 213 if (switcher != null) 214 { 215 Map<String, Object> switcherToJSON = new HashMap<>(); 216 217 switcherToJSON.put("id", switcher.getName()); 218 switcherToJSON.put("label", switcher.getLabel()); 219 220 if (switcher.getType() != null) 221 { 222 switcherToJSON.put("default-value", switcher.getType().valueToJSONForClient(switcher.getDefaultValue(), DataContext.newInstance())); 223 } 224 225 result.put("switcher", switcherToJSON); 226 } 227 228 // Do not include switcher in children because it is already included above 229 List<ModelItem> children = getChildren(false); 230 if (includeChildren && !children.isEmpty()) 231 { 232 Map<String, Object> elements = new LinkedHashMap<>(); 233 for (ModelItem child : children) 234 { 235 String name = child.getName(); 236 if (name != null) 237 { 238 elements.put(name, child.toJSON(context)); 239 } 240 } 241 242 result.put("elements", elements); 243 } 244 245 return result; 246 } 247 248 /** 249 * Creates a {@link ModelItemGroup} 250 * @param name the group's name 251 * @param children the group's children 252 * @return the created {@link ModelItemGroup} 253 */ 254 public static ModelItemGroup of(String name, ModelItem... children) 255 { 256 return new ModelItemGroup(name, children); 257 } 258}