001/* 002 * Copyright 2023 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.Collection; 019import java.util.List; 020import java.util.regex.Matcher; 021import java.util.regex.Pattern; 022 023import org.apache.avalon.framework.configuration.Configuration; 024import org.apache.avalon.framework.configuration.ConfigurationException; 025import org.apache.avalon.framework.logger.AbstractLogEnabled; 026import org.apache.commons.lang3.StringUtils; 027 028import org.ametys.runtime.i18n.I18nizableText; 029import org.ametys.runtime.model.ModelHelper.ConfigurationAndPluginName; 030import org.ametys.runtime.model.ViewHelper.InsertMode; 031import org.ametys.runtime.model.exception.UndefinedItemPathException; 032 033/** 034 * Abstract component that parses view's configuration 035 */ 036public abstract class AbstractViewParser extends AbstractLogEnabled implements ViewParser 037{ 038 /** The regex to remove view references in model item references */ 039 protected static final String __VIEW_REFERENCE_REGEX = "\\[(.+)\\]"; 040 /** The pattern to find view references in model item references */ 041 protected static final Pattern __VIEW_REFERENCE_PATTERN = Pattern.compile("^[^\\[]+" + __VIEW_REFERENCE_REGEX + "$"); 042 043 public View parseView(ConfigurationAndPluginName viewConfiguration) throws ConfigurationException 044 { 045 View view = new View(); 046 view.setName(_parseViewName(viewConfiguration)); 047 048 // Get the model 049 Collection<? extends Model> model = _getModel(); 050 051 // Parse general information of the view Configuration 052 _fillViewGeneralInformation(viewConfiguration, view, view, model); 053 054 // Parse the view items of the view Configuration 055 for (Configuration itemConfiguration : viewConfiguration.configuration().getChildren()) 056 { 057 _parseViewChild(new ConfigurationAndPluginName(itemConfiguration, viewConfiguration.pluginName()), view, model, false); 058 } 059 060 return view; 061 } 062 063 /** 064 * Parses the name of the view 065 * @param viewConfiguration the view's configuration 066 * @return the view's name 067 * @throws ConfigurationException if an error occurs while parsing the view's name 068 */ 069 protected String _parseViewName(ConfigurationAndPluginName viewConfiguration) throws ConfigurationException 070 { 071 return viewConfiguration.configuration().getAttribute("name"); 072 } 073 074 public View overrideView(ConfigurationAndPluginName viewConfiguration, View existingView) throws ConfigurationException 075 { 076 View view = new View(); 077 view.setName(existingView.getName()); 078 079 // Get the model 080 Collection<? extends Model> model = _getModel(); 081 082 // Parse general information of the view Configuration 083 _fillViewGeneralInformation(viewConfiguration, view, existingView, model); 084 085 // Parse the view items of the view Configuration 086 view.addViewItems(existingView.getViewItems()); 087 for (Configuration itemConfiguration : viewConfiguration.configuration().getChildren()) 088 { 089 _parseViewChild(new ConfigurationAndPluginName(itemConfiguration, viewConfiguration.pluginName()), view, model, true); 090 } 091 092 return view; 093 } 094 095 /** 096 * Retrieves the model corresponding to the view to parse 097 * @return the model 098 */ 099 protected abstract Collection<? extends Model> _getModel(); 100 101 /** 102 * Fill the general information of the given view (label, description, ...) 103 * @param viewConfiguration the configuration of the view to fill 104 * @param view the view to fill 105 * @param existingView the existing view, that may already contain general information 106 * @param model The model of the view 107 * @throws ConfigurationException if the configuration is not valid. 108 */ 109 protected void _fillViewGeneralInformation(ConfigurationAndPluginName viewConfiguration, View view, View existingView, Collection<? extends Model> model) throws ConfigurationException 110 { 111 // Internal 112 view.setInternal(viewConfiguration.configuration().getAttributeAsBoolean("internal", existingView.isInternal())); 113 114 // Label 115 I18nizableText label = existingView.getLabel() == null 116 ? ModelHelper.parseI18nizableText(viewConfiguration, "label", existingView.getName()) 117 : ModelHelper.parseI18nizableText(viewConfiguration, "label", existingView.getLabel()); // Case of override, use the existing view as default value 118 view.setLabel(label); 119 120 // Description 121 I18nizableText description = existingView.getDescription() == null 122 ? ModelHelper.parseI18nizableText(viewConfiguration, "description") // default value is an empty string 123 : ModelHelper.parseI18nizableText(viewConfiguration, "description", existingView.getDescription()); // Case of override, use the existing view as default value 124 view.setDescription(description); 125 } 126 127 /** 128 * Parses the item with the given configuration and add the item to the given view 129 * @param itemConfiguration the configuration of the item to parse 130 * @param view the view 131 * @param model The model containing the parsed item 132 * @param override <code>true</code> if the configuration is an override, <code>false</code> otherwise 133 * @throws ConfigurationException if the configuration is not valid. 134 */ 135 protected void _parseViewChild(ConfigurationAndPluginName itemConfiguration, View view, Collection<? extends Model> model, boolean override) throws ConfigurationException 136 { 137 if (_isAddingItemConfiguration(itemConfiguration.configuration())) 138 { 139 _parseModelViewItem(itemConfiguration, view, model, view, override); 140 } 141 else if (_isRemovingItemConfiguration(itemConfiguration.configuration())) 142 { 143 _removeViewItemFromView(view, itemConfiguration.configuration()); 144 } 145 else if (_isAddingGroupConfiguration(itemConfiguration.configuration())) 146 { 147 _parseSimpleViewItemGroup(itemConfiguration, ViewItemGroup.TAB_ROLE, view, model, view, override); 148 } 149 } 150 151 /** 152 * Checks if the given item configuration is an adding item configuration 153 * @param itemConfiguration the item configuration 154 * @return <code>true</code> if the given item configuration is an adding item configuration, <code>false</code> otherwise 155 */ 156 protected boolean _isAddingItemConfiguration(Configuration itemConfiguration) 157 { 158 String itemConfigurationName = itemConfiguration.getName(); 159 return ADD_ITEM_TAG_NAME.equals(itemConfigurationName); 160 } 161 162 /** 163 * Checks if the given item configuration is a removing item configuration 164 * @param itemConfiguration the item configuration 165 * @return <code>true</code> if the given item configuration is a removing item configuration, <code>false</code> otherwise 166 */ 167 protected boolean _isRemovingItemConfiguration(Configuration itemConfiguration) 168 { 169 String itemConfigurationName = itemConfiguration.getName(); 170 return REMOVE_ITEM_TAG_NAME.equals(itemConfigurationName); 171 } 172 173 /** 174 * Checks if the given item configuration is an adding group configuration 175 * @param itemConfiguration the item configuration 176 * @return <code>true</code> if the given item configuration is an adding group configuration, <code>false</code> otherwise 177 */ 178 protected boolean _isAddingGroupConfiguration(Configuration itemConfiguration) 179 { 180 String itemConfigurationName = itemConfiguration.getName(); 181 return ADD_GROUP_TAG_NAME.equals(itemConfigurationName); 182 } 183 184 /** 185 * Parses a model view item and add it to its parent view item accessor 186 * @param itemConfiguration configuration of the model view item 187 * @param parentViewItemAccessor the parent view item accessor of the model view item to parse 188 * @param parentModelItemAccessors the parents model item accessors of the model item corresponding to the model view item to parse 189 * @param referenceView view that references the item 190 * @param override <code>true</code> if the configuration is an override, <code>false</code> otherwise 191 * @throws ConfigurationException if the configuration is not valid. 192 */ 193 protected void _parseModelViewItem(ConfigurationAndPluginName itemConfiguration, ViewItemAccessor parentViewItemAccessor, Collection<? extends ModelItemAccessor> parentModelItemAccessors, View referenceView, boolean override) throws ConfigurationException 194 { 195 String modelItemReference = _getModelItemReference(itemConfiguration.configuration()); 196 197 Matcher viewReferenceMatcher = __VIEW_REFERENCE_PATTERN.matcher(modelItemReference); 198 boolean hasViewReference = viewReferenceMatcher.matches(); 199 200 String modelItemPath = hasViewReference ? modelItemReference.replaceAll(__VIEW_REFERENCE_REGEX, StringUtils.EMPTY) : modelItemReference; // Remove potential view reference 201 202 int lastIndexOfItemPathSeparator = !hasViewReference 203 // Resolve model item reference and initialize parents if the reference is a path 204 ? modelItemPath.lastIndexOf(ModelItem.ITEM_PATH_SEPARATOR) 205 // For view references, the model item is created as a parent view item accessor 206 : modelItemPath.length(); 207 208 209 ViewItemAccessor finalParentViewItemAccessor = parentViewItemAccessor; 210 Collection<? extends ModelItemAccessor> finalParentModelItemAccessors = parentModelItemAccessors; 211 212 String modelItemName = modelItemPath; 213 214 if (lastIndexOfItemPathSeparator > -1) 215 { 216 // Get or create the view item accessors associated to the model item path prefix 217 String parentRelativePath = modelItemPath.substring(0, lastIndexOfItemPathSeparator); 218 finalParentViewItemAccessor = _createViewItemAccessor(itemConfiguration.configuration(), parentRelativePath, parentViewItemAccessor, parentModelItemAccessors, referenceView, override); 219 finalParentModelItemAccessors = List.of((ModelItemAccessor) ((ModelViewItem) finalParentViewItemAccessor).getDefinition()); 220 221 modelItemName = !hasViewReference ? modelItemPath.substring(lastIndexOfItemPathSeparator + ModelItem.ITEM_PATH_SEPARATOR.length()) : StringUtils.EMPTY; 222 } 223 224 if (hasViewReference) 225 { 226 String viewName = viewReferenceMatcher.group(1); 227 _parseViewReference(viewName, finalParentViewItemAccessor, finalParentModelItemAccessors.iterator().next()); 228 } 229 else if (ALL_ITEMS_REFERENCE.equals(modelItemName)) 230 { 231 parseAllModelViewItems(itemConfiguration, finalParentViewItemAccessor, finalParentModelItemAccessors, referenceView, override); 232 } 233 else 234 { 235 // Get the model item 236 ModelItem modelItem = _getModelItem(itemConfiguration, modelItemName, finalParentModelItemAccessors); 237 238 // Create the view item corresponding to the model item 239 ModelViewItem viewItem = createModelViewItem(itemConfiguration, modelItem, referenceView, override); 240 241 // Add the view item to its parent 242 _addItemToViewItemAccessor(finalParentViewItemAccessor, viewItem, itemConfiguration.configuration(), referenceView, override); 243 } 244 } 245 246 /** 247 * Parses the view reference to add items of the view to the given item accessor 248 * @param viewName the name of the referenced view 249 * @param viewItemAccessor the view item accessor referencing the view 250 * @param definition the definition of the model item containing the referenced view 251 * @throws ConfigurationException if the configuration is not valid 252 */ 253 protected abstract void _parseViewReference(String viewName, ViewItemAccessor viewItemAccessor, ModelItemAccessor definition) throws ConfigurationException; 254 255 /** 256 * Parses all the model view items of the given parents 257 * @param itemConfiguration the item configuration 258 * @param parentViewItemAccessor the parent view item accessor 259 * @param parentModelItemAccessors the parent model item accorssors 260 * @param referenceView view that references the item 261 * @param override <code>true</code> if the configuration is an override, <code>false</code> otherwise 262 * @throws ConfigurationException if the configuration is not valid. 263 */ 264 protected void parseAllModelViewItems(ConfigurationAndPluginName itemConfiguration, ViewItemAccessor parentViewItemAccessor, Collection<? extends ModelItemAccessor> parentModelItemAccessors, View referenceView, boolean override) throws ConfigurationException 265 { 266 // For all accessors' items 267 for (ModelItem modelItem : ModelHelper.getModelItems(parentModelItemAccessors)) 268 { 269 // Create the view item corresponding to the model item 270 ModelViewItem viewItem = createModelViewItemForAllItemsReference(itemConfiguration, modelItem, referenceView, override); 271 272 // Add the view item to its parent 273 _addItemToViewItemAccessor(parentViewItemAccessor, viewItem, itemConfiguration.configuration(), referenceView, override); 274 275 // Recursively add all item's children 276 if (modelItem instanceof ModelItemContainer modelItemContainer && viewItem instanceof ViewItemContainer viewItemContainer) 277 { 278 parseAllModelViewItems(itemConfiguration, viewItemContainer, List.of(modelItemContainer), referenceView, override); 279 } 280 } 281 } 282 283 /** 284 * Creates the model view item corresponding to the given configuration, in cas of all items references 285 * @param itemConfiguration configuration of the model view item 286 * @param modelItem the model item 287 * @param referenceView view that references the item 288 * @param override <code>true</code> if the configuration is an override, <code>false</code> otherwise 289 * @return the created model view item 290 * @throws ConfigurationException if the configuration is not valid. 291 */ 292 protected ModelViewItem createModelViewItemForAllItemsReference(ConfigurationAndPluginName itemConfiguration, ModelItem modelItem, View referenceView, boolean override) throws ConfigurationException 293 { 294 return createModelViewItem(itemConfiguration, modelItem, referenceView, override); 295 } 296 297 /** 298 * Creates the model view item corresponding to the given configuration 299 * @param itemConfiguration configuration of the model view item 300 * @param modelItem the model item 301 * @param referenceView view that references the item 302 * @param override <code>true</code> if the configuration is an override, <code>false</code> otherwise 303 * @return the created model view item 304 * @throws ConfigurationException if the configuration is not valid. 305 */ 306 protected ModelViewItem createModelViewItem(ConfigurationAndPluginName itemConfiguration, ModelItem modelItem, View referenceView, boolean override) throws ConfigurationException 307 { 308 ModelViewItem viewItem; 309 if (modelItem instanceof ModelItemGroup modelItemGroup) 310 { 311 viewItem = _createModelViewItemInstance(modelItemGroup); 312 for (Configuration childConfiguration : itemConfiguration.configuration().getChildren()) 313 { 314 _parseViewItemAccessorChild(new ConfigurationAndPluginName(childConfiguration, itemConfiguration.pluginName()), (ViewItemAccessor) viewItem, modelItemGroup, referenceView, override); 315 } 316 } 317 else 318 { 319 viewItem = _parseViewElement(itemConfiguration, (ElementDefinition) modelItem, referenceView, override); 320 } 321 322 // Parse label and description 323 if (itemConfiguration.configuration().getChild("label", false) != null) 324 { 325 viewItem.setLabel(ModelHelper.parseI18nizableText(itemConfiguration, "label")); 326 } 327 if (itemConfiguration.configuration().getChild("description", false) != null) 328 { 329 viewItem.setDescription(ModelHelper.parseI18nizableText(itemConfiguration, "description")); 330 } 331 332 return viewItem; 333 } 334 335 /** 336 * Creates view items corresponding to the given path. 337 * @param itemConfiguration the configuration containing the model item reference 338 * @param modelItemAccessorPath The path of the model item accessor to retrieve 339 * @param viewItemAccessor the view item accessor relative to the given path 340 * @param modelItemAccessors the model item accessor relative to the given path 341 * @param referenceView the reference view for includes 342 * @param override <code>true</code> if the configuration is an override, <code>false</code> otherwise 343 * @return the found or created view item accessor 344 * @throws ConfigurationException if the given path does not correspond to a model item accessor 345 */ 346 @SuppressWarnings("unchecked") 347 protected ViewItemAccessor _createViewItemAccessor(Configuration itemConfiguration, String modelItemAccessorPath, ViewItemAccessor viewItemAccessor, Collection<? extends ModelItemAccessor> modelItemAccessors, View referenceView, boolean override) throws ConfigurationException 348 { 349 int firstIndexOfItemPathSeparator = modelItemAccessorPath.indexOf(ModelItem.ITEM_PATH_SEPARATOR); 350 String firstPathSegment = firstIndexOfItemPathSeparator > -1 ? modelItemAccessorPath.substring(0, modelItemAccessorPath.indexOf(ModelItem.ITEM_PATH_SEPARATOR)) : modelItemAccessorPath; 351 352 ModelItem modelItem = ModelHelper.getModelItem(firstPathSegment, modelItemAccessors); 353 354 if (modelItem instanceof ModelItemAccessor) 355 { 356 // Create the view item and add it to the current view item accessor 357 ModelViewItem viewItem = ViewHelper.createModelViewItemInstance(modelItem); 358 viewItem.setDefinition(modelItem); 359 360 // Add the view item to its parent 361 _addItemToViewItemAccessor(viewItemAccessor, viewItem, itemConfiguration, referenceView, override); 362 363 if (firstIndexOfItemPathSeparator > -1) 364 { 365 // Only the first segment of the path has been processed, now recursively process the next ones 366 String subPath = modelItemAccessorPath.substring(firstIndexOfItemPathSeparator + 1); 367 return _createViewItemAccessor(itemConfiguration, subPath, (ViewItemAccessor) viewItem, List.of((ModelItemAccessor) modelItem), referenceView, override); 368 } 369 else 370 { 371 return (ViewItemAccessor) viewItem; 372 } 373 } 374 else 375 { 376 throw new ConfigurationException("Unable to get or create a view item accessor, the given path '" + modelItemAccessorPath + "' refers to a model item that is not an accessor"); 377 } 378 } 379 380 /** 381 * Retrieves the model item with the given name 382 * @param itemConfiguration configuration of the model view item 383 * @param modelItemName the model item name 384 * @param parents the accessors containing the model item 385 * @return the model item 386 * @throws ConfigurationException if the configuration is not valid. 387 */ 388 protected ModelItem _getModelItem(ConfigurationAndPluginName itemConfiguration, String modelItemName, Collection<? extends ModelItemAccessor> parents) throws ConfigurationException 389 { 390 try 391 { 392 return ModelHelper.getModelItem(modelItemName, parents); 393 } 394 catch (IllegalArgumentException | UndefinedItemPathException e) 395 { 396 throw new ConfigurationException("The item '" + modelItemName + "' is not defined in model.", itemConfiguration.configuration(), e); 397 } 398 } 399 400 /** 401 * Retrieves the model item reference from the given item configuration 402 * @param itemConfiguration the item configuration 403 * @return the model item reference 404 * @throws ConfigurationException if an error occurs while parsing the model item reference 405 */ 406 protected String _getModelItemReference(Configuration itemConfiguration) throws ConfigurationException 407 { 408 return itemConfiguration.getAttribute(ITEM_REFERENCE_ATTRIBUTE_NAME); 409 } 410 411 /** 412 * Retrieves the child configuration to add items to the current accessor 413 * @param accessorConfiguration the accessor configuration 414 * @return the child configuration to add items to the current accessor 415 */ 416 protected Configuration _getAddItemChildConfiguration(Configuration accessorConfiguration) 417 { 418 return accessorConfiguration.getChild(ADD_ITEM_TAG_NAME, false); 419 } 420 421 /** 422 * Parses the view element 423 * @param itemConfiguration configuration of the view item 424 * @param definition definition of the element 425 * @param referenceView view that references the item 426 * @param override <code>true</code> if the configuration is an override, <code>false</code> otherwise 427 * @return the view item 428 * @throws ConfigurationException if the configuration is not valid 429 */ 430 protected ViewElement _parseViewElement(ConfigurationAndPluginName itemConfiguration, ElementDefinition definition, View referenceView, boolean override) throws ConfigurationException 431 { 432 return (ViewElement) _createModelViewItemInstance(definition); 433 } 434 435 /** 436 * Creates an instance of {@link ModelViewItem} due to the given {@link ModelItem} 437 * @param modelItem the model item corresponding to the view item to create 438 * @return the created view item 439 */ 440 @SuppressWarnings("unchecked") 441 protected ModelViewItem _createModelViewItemInstance(ModelItem modelItem) 442 { 443 ModelViewItem modelViewItem = ViewHelper.createModelViewItemInstance(modelItem); 444 modelViewItem.setDefinition(modelItem); 445 446 return modelViewItem; 447 } 448 449 /** 450 * Parses the item with the given configuration and add the item to the given view item accessor 451 * @param itemConfiguration the configuration of the item to parse 452 * @param viewItemAccessor the {@link ViewItemAccessor} that will access to the parsed items 453 * @param modelItemAccessor the {@link ModelItemAccessor} corresponding to the given view item accessor 454 * @param referenceView The view that references the item 455 * @param override <code>true</code> if the configuration is an override, <code>false</code> otherwise 456 * @throws ConfigurationException if the configuration is not valid 457 */ 458 protected void _parseViewItemAccessorChild(ConfigurationAndPluginName itemConfiguration, ViewItemAccessor viewItemAccessor, ModelItemAccessor modelItemAccessor, View referenceView, boolean override) throws ConfigurationException 459 { 460 if (_isAddingItemConfiguration(itemConfiguration.configuration())) 461 { 462 _parseModelViewItem(itemConfiguration, viewItemAccessor, List.of(modelItemAccessor), referenceView, override); 463 } 464 else if (_isAddingGroupConfiguration(itemConfiguration.configuration())) 465 { 466 _parseSimpleViewItemGroup(itemConfiguration, ViewItemGroup.FIELDSET_ROLE, viewItemAccessor, List.of(modelItemAccessor), referenceView, override); 467 } 468 } 469 470 /** 471 * Parses a simple view item group and add it to its parent 472 * @param itemConfiguration configuration of the simple view item group 473 * @param role the role of the view group 474 * @param parent the parent view item accessor 475 * @param modelItemAccessors the current parent model item accessors 476 * @param referenceView the reference view for includes 477 * @param override <code>true</code> if the configuration is an override, <code>false</code> otherwise 478 * @throws ConfigurationException if the configuration is not valid. 479 */ 480 protected void _parseSimpleViewItemGroup(ConfigurationAndPluginName itemConfiguration, String role, ViewItemAccessor parent, Collection<? extends ModelItemAccessor> modelItemAccessors, View referenceView, boolean override) throws ConfigurationException 481 { 482 SimpleViewItemGroup group = new SimpleViewItemGroup(); 483 group.setRole(itemConfiguration.configuration().getAttribute("role", role)); 484 group.setName(itemConfiguration.configuration().getAttribute("name", null)); 485 486 group.setLabel(ModelHelper.parseI18nizableText(itemConfiguration, "label")); 487 group.setDescription(ModelHelper.parseI18nizableText(itemConfiguration, "description")); 488 489 for (Configuration childConfiguration : itemConfiguration.configuration().getChildren()) 490 { 491 _parseSimpleViewItemGroupChild(new ConfigurationAndPluginName(childConfiguration, itemConfiguration.pluginName()), group, modelItemAccessors, referenceView, override); 492 } 493 494 // Add the group to its parent 495 _addItemToViewItemAccessor(parent, group, itemConfiguration.configuration(), referenceView, override); 496 } 497 498 /** 499 * Parses the item with the given configuration and add the item to the given group 500 * @param itemConfiguration configuration of the group's child 501 * @param group the simple view item group 502 * @param modelItemAccessors the current parent model item accessors 503 * @param referenceView the reference view for includes 504 * @param override <code>true</code> if the configuration is an override, <code>false</code> otherwise 505 * @throws ConfigurationException if the configuration is not valid. 506 */ 507 protected void _parseSimpleViewItemGroupChild(ConfigurationAndPluginName itemConfiguration, SimpleViewItemGroup group, Collection<? extends ModelItemAccessor> modelItemAccessors, View referenceView, boolean override) throws ConfigurationException 508 { 509 if (_isAddingItemConfiguration(itemConfiguration.configuration())) 510 { 511 _parseModelViewItem(itemConfiguration, group, modelItemAccessors, referenceView, override); 512 } 513 else if (_isAddingGroupConfiguration(itemConfiguration.configuration())) 514 { 515 _parseSimpleViewItemGroup(itemConfiguration, ViewItemGroup.FIELDSET_ROLE, group, modelItemAccessors, referenceView, override); 516 } 517 } 518 519 /** 520 * Add an item to a view or to an overridden view 521 * @param viewItemAccessor The view 522 * @param viewItem The view item to add 523 * @param itemConfiguration The item's configurations 524 * @param referenceView the reference view for includes 525 * @param override <code>true</code> if the view is an override, <code>false</code> otherwise 526 * @throws ConfigurationException If an error occurs 527 */ 528 protected void _addItemToViewItemAccessor(ViewItemAccessor viewItemAccessor, ViewItem viewItem, Configuration itemConfiguration, View referenceView, boolean override) throws ConfigurationException 529 { 530 // Check already existing view items 531 if (getLogger().isWarnEnabled() && viewItem instanceof ModelViewItem modelViewItem && (viewItemAccessor.hasModelViewItem(modelViewItem) || referenceView.hasModelViewItem(modelViewItem))) 532 { 533 String itemPath = modelViewItem.getDefinition().getPath(); 534 getLogger().warn("The item '" + itemPath + "' is already referenced by the view '" + referenceView.getName() + "'."); 535 } 536 537 if (viewItemAccessor instanceof View view && override) 538 { 539 _addItemToOverriddenView(view, viewItem, itemConfiguration); 540 } 541 else 542 { 543 viewItemAccessor.addViewItem(viewItem); 544 } 545 } 546 547 /** 548 * Add the viewItem to the view or in a location inside the view (in a group or before/after another view item) 549 * @param view The view in which to insert the new Item 550 * @param viewItem The viewItem to insert 551 * @param itemConfiguration The configuration of the viewItem 552 * @throws ConfigurationException If an error occurs 553 */ 554 protected void _addItemToOverriddenView(View view, ViewItem viewItem, Configuration itemConfiguration) throws ConfigurationException 555 { 556 String group = itemConfiguration.getAttribute("group", null); 557 ViewItemAccessor viewItemAccessor = view; 558 559 if (group != null) 560 { 561 try 562 { 563 viewItemAccessor = ViewHelper.getSimpleViewItemGroup(view, group); 564 } 565 catch (IllegalArgumentException e) 566 { 567 throw new ConfigurationException("The path to the requested group where to add the view item " + viewItem.getName() + " in the initial view " + view.getName() + " is empty.", itemConfiguration, e); 568 } 569 catch (UndefinedItemPathException e) 570 { 571 getLogger().warn("The group requested " + group + " does not exist in the initial view " + view.getName() + ". The item '" + viewItem.getName() + "' will be inserted at the end of the view", e); 572 } 573 } 574 575 _insertItemInViewItemAccessor(viewItemAccessor, viewItem, itemConfiguration); 576 } 577 578 /** 579 * Insert an item in the given {@link ViewItemAccessor} 580 * @param viewItemAccessor The view item accessor in which to insert the new Item 581 * @param viewItem The viewItem to insert 582 * @param itemConfiguration The configuration of the viewItem 583 * @throws ConfigurationException If an error occurs 584 */ 585 protected void _insertItemInViewItemAccessor(ViewItemAccessor viewItemAccessor, ViewItem viewItem, Configuration itemConfiguration) throws ConfigurationException 586 { 587 String before = itemConfiguration.getAttribute("order-before", null); 588 String after = itemConfiguration.getAttribute("order-after", null); 589 590 // An attribute cannot be before an attribute and after at the same time 591 if (after != null && before != null) 592 { 593 throw new ConfigurationException("The item " + viewItem.getName() + " cannot be added both after and before attributes", itemConfiguration); 594 } 595 596 if (after != null || before != null) 597 { 598 InsertMode insertMode = after != null ? InsertMode.AFTER : InsertMode.BEFORE; 599 String insertAfterOrBefore = after != null ? after : before; 600 601 try 602 { 603 ViewHelper.insertItemAfterOrBefore(viewItemAccessor, viewItem, insertAfterOrBefore, insertMode); 604 } 605 catch (IllegalArgumentException e) 606 { 607 throw new ConfigurationException("Unable to insert view item " + viewItem.getName() + " " + insertMode + " the specified view item. The name is empty or is a path.", itemConfiguration, e); 608 } 609 catch (UndefinedItemPathException e) 610 { 611 if (getLogger().isWarnEnabled()) 612 { 613 String viewItemAccessorName = viewItemAccessor instanceof View view 614 ? view.getName() 615 : viewItemAccessor instanceof ViewItem vI 616 ? vI.getName() 617 : viewItemAccessor.toString(); 618 getLogger().warn("Unable to insert view item " + viewItem.getName() + " " + insertMode + " the view item named " + insertAfterOrBefore + ". No view item has been found with this name. This item will be inserted at the end of the view item accessor '" + viewItemAccessorName + "'.", e); 619 } 620 621 // Add the item at the end of the view item accessor 622 viewItemAccessor.addViewItem(viewItem); 623 } 624 } 625 else 626 { 627 viewItemAccessor.addViewItem(viewItem); 628 } 629 } 630 631 /** 632 * Removes a view item from the view 633 * @param view The view from which we want to remove an item 634 * @param itemConfiguration The configuration of the view item to remove 635 * @throws ConfigurationException If there is an error whil parsing the item configuration 636 */ 637 protected void _removeViewItemFromView(View view, Configuration itemConfiguration) throws ConfigurationException 638 { 639 String viewItemPath = itemConfiguration.getAttribute(ITEM_REFERENCE_ATTRIBUTE_NAME); 640 641 try 642 { 643 ViewItem viewItem = ViewHelper.getViewItem(view, viewItemPath); 644 ViewItemAccessor parent = viewItem.getParent(); 645 parent.removeViewItem(viewItem); 646 } 647 catch (Exception e) 648 { 649 // Just log the warning, do not throw exceptions 650 getLogger().warn("[View Item removal] Unable to remove " + viewItemPath + " from " + view.getName(), e); 651 } 652 } 653}