001/* 002 * Copyright 2026 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.plugins.repository.jcr; 017 018import java.util.Collection; 019import java.util.Map; 020import java.util.Optional; 021 022import javax.jcr.Node; 023 024import org.xml.sax.ContentHandler; 025import org.xml.sax.SAXException; 026 027import org.ametys.plugins.repository.AmetysObject; 028import org.ametys.plugins.repository.data.external.ExternalizableDataProvider.ExternalizableDataStatus; 029import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder; 030import org.ametys.plugins.repository.data.holder.group.ModifiableModelAwareComposite; 031import org.ametys.plugins.repository.data.holder.group.ModifiableRepeater; 032import org.ametys.plugins.repository.data.holder.impl.DataHolderHelper; 033import org.ametys.plugins.repository.data.holder.impl.DefaultModifiableModelAwareDataHolder; 034import org.ametys.plugins.repository.data.holder.values.SynchronizationContext; 035import org.ametys.plugins.repository.data.holder.values.SynchronizationResult; 036import org.ametys.plugins.repository.data.repositorydata.ModifiableRepositoryData; 037import org.ametys.plugins.repository.data.repositorydata.impl.JCRRepositoryData; 038import org.ametys.plugins.repository.data.type.ModelItemTypeExtensionPoint; 039import org.ametys.runtime.model.Model; 040import org.ametys.runtime.model.ModelItem; 041import org.ametys.runtime.model.ViewItemAccessor; 042import org.ametys.runtime.model.exception.BadDataPathCardinalityException; 043import org.ametys.runtime.model.exception.BadItemTypeException; 044import org.ametys.runtime.model.exception.UndefinedItemPathException; 045import org.ametys.runtime.model.type.DataContext; 046import org.ametys.runtime.model.type.ModelItemType; 047 048/** 049 * Model aware implementation of an {@link AmetysObject}, backed by a JCR node.<br> 050 * @param <F> the actual type of factory. 051 */ 052public class SimpleModelAwareAmetysObject<F extends SimpleModelAwareAmetysObjectFactory> extends SimpleAmetysObject<F> implements ModelAwareJCRAmetysObject 053{ 054 /** 055 * Creates an {@link SimpleModelAwareAmetysObject}. 056 * @param node the node backing this {@link AmetysObject} 057 * @param parentPath the parentPath in the Ametys hierarchy 058 * @param factory the {@link SimpleModelAwareAmetysObjectFactory} which created the AmetysObject 059 */ 060 public SimpleModelAwareAmetysObject(Node node, String parentPath, F factory) 061 { 062 super(node, parentPath, factory); 063 } 064 065 @Override 066 protected ModifiableModelAwareDataHolder getDataHolder() 067 { 068 ModifiableRepositoryData repositoryData = new JCRRepositoryData(getNode()); 069 return new DefaultModifiableModelAwareDataHolder(repositoryData, _getFactory().getModel(this), Optional.empty(), Optional.empty(), Optional.of(this)); 070 } 071 072 @Override 073 public ModifiableModelAwareComposite getComposite(String compositePath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 074 { 075 return getDataHolder().getComposite(compositePath); 076 } 077 078 @Override 079 public ModifiableModelAwareComposite getLocalComposite(String compositePath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 080 { 081 return getDataHolder().getLocalComposite(compositePath); 082 } 083 084 @Override 085 public ModifiableModelAwareComposite getExternalComposite(String compositePath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 086 { 087 return getDataHolder().getExternalComposite(compositePath); 088 } 089 090 @Override 091 public ModifiableRepeater getRepeater(String repeaterPath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 092 { 093 return getDataHolder().getRepeater(repeaterPath); 094 } 095 096 @Override 097 public ModifiableRepeater getLocalRepeater(String repeaterPath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 098 { 099 return getDataHolder().getLocalRepeater(repeaterPath); 100 } 101 102 @Override 103 public ModifiableRepeater getExternalRepeater(String repeaterPath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 104 { 105 return getDataHolder().getExternalRepeater(repeaterPath); 106 } 107 108 @Override 109 public ModifiableModelAwareComposite getComposite(String compositePath, boolean createNew) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 110 { 111 return getDataHolder().getComposite(compositePath, createNew); 112 } 113 114 public ModifiableModelAwareComposite getLocalComposite(String compositePath, boolean createNew) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 115 { 116 return getDataHolder().getLocalComposite(compositePath, createNew); 117 } 118 119 public ModifiableModelAwareComposite getExternalComposite(String compositePath, boolean createNew) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 120 { 121 return getDataHolder().getExternalComposite(compositePath, createNew); 122 } 123 124 public ModifiableRepeater getRepeater(String repeaterPath, boolean createNew) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 125 { 126 return getDataHolder().getRepeater(repeaterPath, createNew); 127 } 128 129 public ModifiableRepeater getLocalRepeater(String repeaterPath, boolean createNew) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 130 { 131 return getDataHolder().getLocalRepeater(repeaterPath, createNew); 132 } 133 134 public ModifiableRepeater getExternalRepeater(String repeaterPath, boolean createNew) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 135 { 136 return getDataHolder().getExternalRepeater(repeaterPath, createNew); 137 } 138 139 @Override 140 public boolean hasValue(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException 141 { 142 return getDataHolder().hasValue(dataPath); 143 } 144 145 @Override 146 public boolean hasValue(String dataPath, String dataTypeId) throws IllegalArgumentException, BadDataPathCardinalityException 147 { 148 return ModelAwareJCRAmetysObject.super.hasValue(dataPath, dataTypeId); 149 } 150 151 public boolean hasLocalValue(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException 152 { 153 return getDataHolder().hasLocalValue(dataPath); 154 } 155 156 public boolean hasExternalValue(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException 157 { 158 return getDataHolder().hasExternalValue(dataPath); 159 } 160 161 @Override 162 public boolean hasValueOrEmpty(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException 163 { 164 return getDataHolder().hasValueOrEmpty(dataPath); 165 } 166 167 public boolean hasLocalValueOrEmpty(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException 168 { 169 return getDataHolder().hasLocalValueOrEmpty(dataPath); 170 } 171 172 public boolean hasExternalValueOrEmpty(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException 173 { 174 return getDataHolder().hasExternalValueOrEmpty(dataPath); 175 } 176 177 public <T> T getLocalValue(String dataPath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 178 { 179 return getDataHolder().getLocalValue(dataPath); 180 } 181 182 public <T> T getExternalValue(String dataPath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 183 { 184 return getDataHolder().getExternalValue(dataPath); 185 } 186 187 public <T> T getValueOrDefault(String dataPath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 188 { 189 return getDataHolder().getValueOrDefault(dataPath); 190 } 191 192 @Override 193 public <T> T getValueOfType(String dataPath, String dataTypeId) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 194 { 195 return ModelAwareJCRAmetysObject.super.getValueOfType(dataPath, dataTypeId); 196 } 197 198 @Override 199 public <T> T getValueOfTypeOrDefault(String dataPath, String dataTypeId, T defaultValue) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 200 { 201 return ModelAwareJCRAmetysObject.super.getValueOfTypeOrDefault(dataPath, dataTypeId, defaultValue); 202 } 203 204 public <T> T getValueWithMultiValuedPathSegments(String dataPath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 205 { 206 return getDataHolder().getValueWithMultiValuedPathSegments(dataPath); 207 } 208 209 public ExternalizableDataStatus getStatus(String dataPath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 210 { 211 return getDataHolder().getStatus(dataPath); 212 } 213 214 @Override 215 public boolean isMultiple(String dataPath) throws IllegalArgumentException, UndefinedItemPathException 216 { 217 return ModelAwareJCRAmetysObject.super.isMultiple(dataPath); 218 } 219 220 @Override 221 public boolean isMultiple(String dataPath, String dataTypeId) throws IllegalArgumentException, UndefinedItemPathException 222 { 223 return ModelAwareJCRAmetysObject.super.isMultiple(dataPath, dataTypeId); 224 } 225 226 @Override 227 public <X extends ModelItemType> X getType(String path) throws IllegalArgumentException, UndefinedItemPathException 228 { 229 return ModelAwareJCRAmetysObject.super.getType(path); 230 } 231 232 @Override 233 public ModelItemTypeExtensionPoint getModelItemTypeExtensionPoint() 234 { 235 return ModelAwareJCRAmetysObject.super.getModelItemTypeExtensionPoint(); 236 } 237 238 @SuppressWarnings("unchecked") 239 public Collection<? extends Model> getModel() 240 { 241 return (Collection<? extends Model>) getDataHolder().getModel(); 242 } 243 244 @Override 245 public ModelItem getDefinition(String path) throws IllegalArgumentException, UndefinedItemPathException 246 { 247 return getDataHolder().getDefinition(path); 248 } 249 250 @Override 251 public boolean hasDefinition(String path) throws IllegalArgumentException 252 { 253 return getDataHolder().hasDefinition(path); 254 } 255 256 @Override 257 public void dataToSAX(ContentHandler contentHandler, DataContext context) throws SAXException, BadItemTypeException 258 { 259 ModelAwareJCRAmetysObject.super.dataToSAX(contentHandler, context); 260 } 261 262 public void dataToSAX(ContentHandler contentHandler, ViewItemAccessor viewItemAccessor, DataContext context) throws SAXException, BadItemTypeException 263 { 264 getDataHolder().dataToSAX(contentHandler, viewItemAccessor, context); 265 } 266 267 public void dataToSAXForEdition(ContentHandler contentHandler, ViewItemAccessor viewItemAccessor, DataContext context) throws SAXException, BadItemTypeException 268 { 269 getDataHolder().dataToSAXForEdition(contentHandler, viewItemAccessor, context); 270 } 271 272 @Override 273 public Map<String, Object> dataToJSON(DataContext context) throws BadItemTypeException 274 { 275 return ModelAwareJCRAmetysObject.super.dataToJSON(context); 276 } 277 278 public Map<String, Object> dataToJSON(ViewItemAccessor viewItemAccessor, DataContext context) throws BadItemTypeException 279 { 280 return getDataHolder().dataToJSON(viewItemAccessor, context); 281 } 282 283 public Map<String, Object> dataToJSONForEdition(ViewItemAccessor viewItemAccessor, DataContext context) throws BadItemTypeException 284 { 285 return getDataHolder().dataToJSONForEdition(viewItemAccessor, context); 286 } 287 288 public Map<String, Object> dataToMap(ViewItemAccessor viewItemAccessor, DataContext context) throws BadItemTypeException 289 { 290 return getDataHolder().dataToMap(viewItemAccessor, context); 291 } 292 293 @Override 294 public boolean hasDifferences(Map<String, Object> values) throws BadItemTypeException 295 { 296 ViewItemAccessor viewItemAccessor = DataHolderHelper.createViewItemAccessorFromValues(getModel(), values); 297 Map<String, Object> convertedValues = DataHolderHelper.convertValues(viewItemAccessor, values, DataHolderHelper::convertValue); 298 return getDataHolder().hasDifferences(viewItemAccessor, convertedValues); 299 } 300 301 @Override 302 public boolean hasDifferences(Map<String, Object> values, SynchronizationContext context) throws BadItemTypeException 303 { 304 ViewItemAccessor viewItemAccessor = DataHolderHelper.createViewItemAccessorFromValues(getModel(), values); 305 Map<String, Object> convertedValues = DataHolderHelper.convertValues(viewItemAccessor, values, context.ignoreIncompatibleValues() 306 ? DataHolderHelper::convertValueIgnoringIncompatibleOnes 307 : DataHolderHelper::convertValue); 308 return getDataHolder().hasDifferences(viewItemAccessor, convertedValues, context); 309 } 310 311 public boolean hasDifferences(ViewItemAccessor viewItemAccessor, Map<String, Object> values) throws BadItemTypeException 312 { 313 Map<String, Object> convertedValues = DataHolderHelper.convertValues(viewItemAccessor, values, DataHolderHelper::convertValue); 314 return getDataHolder().hasDifferences(viewItemAccessor, convertedValues); 315 } 316 317 public boolean hasDifferences(ViewItemAccessor viewItemAccessor, Map<String, Object> values, SynchronizationContext context) throws BadItemTypeException 318 { 319 Map<String, Object> convertedValues = DataHolderHelper.convertValues(viewItemAccessor, values, context.ignoreIncompatibleValues() 320 ? DataHolderHelper::convertValueIgnoringIncompatibleOnes 321 : DataHolderHelper::convertValue); 322 return getDataHolder().hasDifferences(viewItemAccessor, convertedValues, context); 323 } 324 325 @Override 326 public Collection<ModelItem> getDifferences(Map<String, Object> values) throws BadItemTypeException 327 { 328 ViewItemAccessor viewItemAccessor = DataHolderHelper.createViewItemAccessorFromValues(getModel(), values); 329 Map<String, Object> convertedValues = DataHolderHelper.convertValues(viewItemAccessor, values, DataHolderHelper::convertValue); 330 return getDataHolder().getDifferences(viewItemAccessor, convertedValues); 331 } 332 333 @Override 334 public Collection<ModelItem> getDifferences(Map<String, Object> values, SynchronizationContext context) throws BadItemTypeException 335 { 336 ViewItemAccessor viewItemAccessor = DataHolderHelper.createViewItemAccessorFromValues(getModel(), values); 337 Map<String, Object> convertedValues = DataHolderHelper.convertValues(viewItemAccessor, values, context.ignoreIncompatibleValues() 338 ? DataHolderHelper::convertValueIgnoringIncompatibleOnes 339 : DataHolderHelper::convertValue); 340 return getDataHolder().getDifferences(viewItemAccessor, convertedValues, context); 341 } 342 343 public Collection<ModelItem> getDifferences(ViewItemAccessor viewItemAccessor, Map<String, Object> values) throws BadItemTypeException 344 { 345 Map<String, Object> convertedValues = DataHolderHelper.convertValues(viewItemAccessor, values, DataHolderHelper::convertValue); 346 return getDataHolder().getDifferences(viewItemAccessor, convertedValues); 347 } 348 349 public Collection<ModelItem> getDifferences(ViewItemAccessor viewItemAccessor, Map<String, Object> values, SynchronizationContext context) throws BadItemTypeException 350 { 351 Map<String, Object> convertedValues = DataHolderHelper.convertValues(viewItemAccessor, values, context.ignoreIncompatibleValues() 352 ? DataHolderHelper::convertValueIgnoringIncompatibleOnes 353 : DataHolderHelper::convertValue); 354 return getDataHolder().getDifferences(viewItemAccessor, convertedValues, context); 355 } 356 357 @Override 358 public <T extends SynchronizationResult> T synchronizeValues(Map<String, Object> values) throws BadItemTypeException, UndefinedItemPathException 359 { 360 return getDataHolder().synchronizeValues(values); 361 } 362 363 public <T extends SynchronizationResult> T synchronizeValues(Map<String, Object> values, SynchronizationContext context) throws BadItemTypeException, UndefinedItemPathException 364 { 365 return getDataHolder().synchronizeValues(values, context); 366 } 367 368 public <T extends SynchronizationResult> T synchronizeValues(ViewItemAccessor viewItemAccessor, Map<String, Object> values) throws BadItemTypeException, UndefinedItemPathException 369 { 370 return getDataHolder().synchronizeValues(viewItemAccessor, values); 371 } 372 373 public <T extends SynchronizationResult> T synchronizeValues(ViewItemAccessor viewItemAccessor, Map<String, Object> values, SynchronizationContext context) throws BadItemTypeException, UndefinedItemPathException 374 { 375 return getDataHolder().synchronizeValues(viewItemAccessor, values, context); 376 } 377 378 @Override 379 public void setValue(String dataPath, Object value) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 380 { 381 getDataHolder().setValue(dataPath, value); 382 } 383 384 public void setLocalValue(String dataPath, Object localValue) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 385 { 386 getDataHolder().setLocalValue(dataPath, localValue); 387 } 388 389 public void setExternalValue(String dataPath, Object externalValue) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 390 { 391 getDataHolder().setExternalValue(dataPath, externalValue); 392 } 393 394 public void setStatus(String dataPath, ExternalizableDataStatus status) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 395 { 396 getDataHolder().setStatus(dataPath, status); 397 } 398 399 @Override 400 public void setValue(String dataPath, Object value, String dataTypeId) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 401 { 402 ModelAwareJCRAmetysObject.super.setValue(dataPath, value, dataTypeId); 403 } 404 405 @Override 406 public void removeValue(String dataPath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 407 { 408 getDataHolder().removeValue(dataPath); 409 } 410 411 public void removeLocalValue(String dataPath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 412 { 413 getDataHolder().removeLocalValue(dataPath); 414 } 415 416 public void removeExternalValue(String dataPath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 417 { 418 getDataHolder().removeExternalValue(dataPath); 419 } 420 421 public void removeExternalizableMetadataIfExists(String dataPath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 422 { 423 getDataHolder().removeExternalizableMetadataIfExists(dataPath); 424 } 425 426 @Override 427 public ModifiableRepositoryData getRepositoryData() 428 { 429 return getDataHolder().getRepositoryData(); 430 } 431 432 @Override 433 public Optional<? extends ModifiableModelAwareDataHolder> getParentDataHolder() 434 { 435 return getDataHolder().getParentDataHolder(); 436 } 437 438 @Override 439 public ModifiableModelAwareDataHolder getRootDataHolder() 440 { 441 return getDataHolder().getRootDataHolder(); 442 } 443}