001/* 002 * Copyright 2019 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.cms.data; 017 018import java.util.Collection; 019import java.util.List; 020import java.util.Map; 021import java.util.Objects; 022import java.util.Optional; 023 024import javax.jcr.RepositoryException; 025import javax.jcr.Session; 026 027import org.apache.commons.collections4.CollectionUtils; 028import org.xml.sax.ContentHandler; 029import org.xml.sax.SAXException; 030 031import org.ametys.cms.data.type.AbstractContentElementType; 032import org.ametys.cms.repository.ModifiableContent; 033import org.ametys.plugins.repository.AmetysObjectResolver; 034import org.ametys.plugins.repository.AmetysRepositoryException; 035import org.ametys.plugins.repository.UnknownAmetysObjectException; 036import org.ametys.plugins.repository.data.DataComment; 037import org.ametys.plugins.repository.data.UnknownDataException; 038import org.ametys.plugins.repository.data.external.ExternalizableDataProvider.ExternalizableDataStatus; 039import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder; 040import org.ametys.plugins.repository.data.holder.group.impl.ModifiableModelAwareComposite; 041import org.ametys.plugins.repository.data.holder.group.impl.ModifiableModelAwareRepeater; 042import org.ametys.plugins.repository.data.holder.values.SynchronizationContext; 043import org.ametys.plugins.repository.data.holder.values.SynchronizationResult; 044import org.ametys.plugins.repository.data.repositorydata.ModifiableRepositoryData; 045import org.ametys.runtime.model.ModelItem; 046import org.ametys.runtime.model.ModelItemContainer; 047import org.ametys.runtime.model.ViewItemContainer; 048import org.ametys.runtime.model.exception.BadDataPathCardinalityException; 049import org.ametys.runtime.model.exception.BadItemTypeException; 050import org.ametys.runtime.model.exception.UndefinedItemPathException; 051import org.ametys.runtime.model.type.DataContext; 052 053/** 054 * Content wrapper used by attributes of type content 055 * @see AbstractContentElementType 056 */ 057public class ContentValue implements ModifiableModelAwareDataHolder 058{ 059 private AmetysObjectResolver _resolver; 060 private String _contentId; 061 private ModifiableContent _content; 062 private Session _session; 063 064 /** 065 * Constructor of the content wrapper 066 * @param content the existing content 067 */ 068 public ContentValue(ModifiableContent content) 069 { 070 _content = content; 071 _contentId = content.getId(); 072 } 073 074 /** 075 * Constructor of the content wrapper 076 * @param resolver resolver used to get the content from its identifier 077 * @param contentId content identifier 078 */ 079 public ContentValue(AmetysObjectResolver resolver, String contentId) 080 { 081 this(resolver, contentId, null); 082 } 083 084 /** 085 * Constructor of the content wrapper 086 * @param resolver resolver used to get the content from its identifier 087 * @param contentId content identifier 088 * @param session the current session. If <code>null</code>, a new session will be used to retrieve the content 089 */ 090 public ContentValue(AmetysObjectResolver resolver, String contentId, Session session) 091 { 092 _resolver = resolver; 093 _contentId = contentId; 094 _session = session; 095 } 096 097 /** 098 * Retrieves the content's identifier 099 * @return the content's identifier 100 */ 101 public String getContentId() 102 { 103 return _contentId; 104 } 105 106 /** 107 * Retrieves the content 108 * @return the content 109 * @throws AmetysRepositoryException if an error occurs. 110 * @throws UnknownAmetysObjectException if no content exists for the identifier 111 */ 112 public ModifiableContent getContent() throws AmetysRepositoryException, UnknownAmetysObjectException 113 { 114 if (_content == null) 115 { 116 if (_session != null) 117 { 118 try 119 { 120 _content = _resolver.resolveById(_contentId, _session); 121 } 122 catch (RepositoryException e) 123 { 124 throw new AmetysRepositoryException("Unable to retrieve the content with the id '" + _contentId + "'.", e); 125 } 126 } 127 else 128 { 129 _content = _resolver.resolveById(_contentId); 130 } 131 } 132 133 return _content; 134 } 135 136 /** 137 * Retrieves an {@link Optional} describing the content, or an empty {@link Optional} if the content does not exist 138 * @return an {@link Optional} describing the content 139 */ 140 public Optional<ModifiableContent> getContentIfExists() 141 { 142 try 143 { 144 return Optional.ofNullable(getContent()); 145 } 146 catch (AmetysRepositoryException e) 147 { 148 return Optional.empty(); 149 } 150 } 151 152 @Override 153 public int hashCode() 154 { 155 return Objects.hash(_contentId); 156 } 157 158 @Override 159 public boolean equals(Object obj) 160 { 161 if (!(obj instanceof ContentValue)) 162 { 163 return false; 164 } 165 166 return Objects.equals(_contentId, ((ContentValue) obj)._contentId); 167 } 168 169 public boolean hasValue(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException 170 { 171 return getContentIfExists() 172 .map(c -> c.hasValue(dataPath)) 173 .orElse(false); 174 } 175 176 public boolean hasLocalValue(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException 177 { 178 return getContentIfExists() 179 .map(c -> c.hasLocalValue(dataPath)) 180 .orElse(false); 181 } 182 183 public boolean hasExternalValue(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException 184 { 185 return getContentIfExists() 186 .map(c -> c.hasExternalValue(dataPath)) 187 .orElse(false); 188 } 189 190 public boolean hasValueOrEmpty(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException 191 { 192 return getContentIfExists() 193 .map(c -> c.hasValueOrEmpty(dataPath)) 194 .orElse(false); 195 } 196 197 public boolean hasLocalValueOrEmpty(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException 198 { 199 return getContentIfExists() 200 .map(c -> c.hasLocalValueOrEmpty(dataPath)) 201 .orElse(false); 202 } 203 204 public boolean hasExternalValueOrEmpty(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException 205 { 206 return getContentIfExists() 207 .map(c -> c.hasExternalValueOrEmpty(dataPath)) 208 .orElse(false); 209 } 210 211 public boolean hasComments(String dataName) throws IllegalArgumentException, UndefinedItemPathException 212 { 213 return getContentIfExists() 214 .map(c -> c.hasComments(dataName)) 215 .orElse(false); 216 } 217 218 public Collection<String> getDataNames() 219 { 220 return getContentIfExists() 221 .map(c -> c.getDataNames()) 222 .orElse(CollectionUtils.EMPTY_COLLECTION); 223 } 224 225 public <T> T getValue(String dataPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 226 { 227 return getContentIfExists() 228 .map(c -> c.<T>getValue(dataPath)) 229 .orElse(null); 230 } 231 232 public <T> T getValue(String dataPath, boolean allowMultiValuedPathSegments) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 233 { 234 return getContentIfExists() 235 .map(c -> c.<T>getValue(dataPath, allowMultiValuedPathSegments)) 236 .orElse(null); 237 } 238 239 public <T> T getValue(String dataPath, boolean useDefaultFromModel, T defaultValue) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 240 { 241 return getContentIfExists() 242 .map(c -> c.<T>getValue(dataPath, useDefaultFromModel, defaultValue)) 243 .orElse(null); 244 } 245 246 public <T> T getLocalValue(String dataPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 247 { 248 return getContentIfExists() 249 .map(c -> c.<T>getLocalValue(dataPath)) 250 .orElse(null); 251 } 252 253 public <T> T getExternalValue(String dataPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 254 { 255 return getContentIfExists() 256 .map(c -> c.<T>getExternalValue(dataPath)) 257 .orElse(null); 258 } 259 260 public ExternalizableDataStatus getStatus(String dataPath) throws IllegalArgumentException, UndefinedItemPathException, BadDataPathCardinalityException 261 { 262 return getContentIfExists() 263 .map(c -> c.getStatus(dataPath)) 264 .orElse(ExternalizableDataStatus.LOCAL); 265 } 266 267 public List<DataComment> getComments(String dataName) throws IllegalArgumentException, UndefinedItemPathException 268 { 269 return getContentIfExists() 270 .map(c -> c.getComments(dataName)) 271 .orElse(null); 272 } 273 274 public Collection< ? extends ModelItemContainer> getModel() 275 { 276 return getContentIfExists() 277 .map(c -> c.getModel()) 278 .orElse(null); 279 } 280 281 public ModelItem getDefinition(String path) throws IllegalArgumentException, UndefinedItemPathException 282 { 283 return getContentIfExists() 284 .map(c -> c.getDefinition(path)) 285 .orElse(null); 286 } 287 288 public boolean hasDefinition(String path) throws IllegalArgumentException 289 { 290 return getContentIfExists() 291 .map(c -> c.hasDefinition(path)) 292 .orElse(null); 293 } 294 295 public ModifiableModelAwareComposite getComposite(String compositePath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 296 { 297 return getContentIfExists() 298 .map(c -> c.getComposite(compositePath)) 299 .orElse(null); 300 } 301 302 public ModifiableModelAwareComposite getLocalComposite(String compositePath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 303 { 304 return getContentIfExists() 305 .map(c -> c.getLocalComposite(compositePath)) 306 .orElse(null); 307 } 308 309 public ModifiableModelAwareComposite getExternalComposite(String compositePath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 310 { 311 return getContentIfExists() 312 .map(c -> c.getExternalComposite(compositePath)) 313 .orElse(null); 314 } 315 316 public ModifiableModelAwareRepeater getRepeater(String repeaterPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 317 { 318 return getContentIfExists() 319 .map(c -> c.getRepeater(repeaterPath)) 320 .orElse(null); 321 } 322 323 public ModifiableModelAwareRepeater getLocalRepeater(String repeaterPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 324 { 325 return getContentIfExists() 326 .map(c -> c.getLocalRepeater(repeaterPath)) 327 .orElse(null); 328 } 329 330 public ModifiableModelAwareRepeater getExternalRepeater(String repeaterPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 331 { 332 return getContentIfExists() 333 .map(c -> c.getExternalRepeater(repeaterPath)) 334 .orElse(null); 335 } 336 337 public void dataToSAX(ContentHandler contentHandler, String dataPath, DataContext context) throws SAXException 338 { 339 getContent().dataToSAX(contentHandler, dataPath, context); 340 } 341 342 public ModifiableModelAwareComposite getComposite(String compositePath, boolean createNew) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 343 { 344 return getContentIfExists() 345 .map(c -> c.getComposite(compositePath, createNew)) 346 .orElse(null); 347 } 348 349 public ModifiableModelAwareComposite getLocalComposite(String compositePath, boolean createNew) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 350 { 351 return getContentIfExists() 352 .map(c -> c.getLocalComposite(compositePath, createNew)) 353 .orElse(null); 354 } 355 356 public ModifiableModelAwareComposite getExternalComposite(String compositePath, boolean createNew) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 357 { 358 return getContentIfExists() 359 .map(c -> c.getExternalComposite(compositePath, createNew)) 360 .orElse(null); 361 } 362 363 public ModifiableModelAwareRepeater getRepeater(String repeaterPath, boolean createNew) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 364 { 365 return getContentIfExists() 366 .map(c -> c.getRepeater(repeaterPath, createNew)) 367 .orElse(null); 368 } 369 370 public ModifiableModelAwareRepeater getLocalRepeater(String repeaterPath, boolean createNew) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 371 { 372 return getContentIfExists() 373 .map(c -> c.getLocalRepeater(repeaterPath, createNew)) 374 .orElse(null); 375 } 376 377 public ModifiableModelAwareRepeater getExternalRepeater(String repeaterPath, boolean createNew) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 378 { 379 return getContentIfExists() 380 .map(c -> c.getExternalRepeater(repeaterPath, createNew)) 381 .orElse(null); 382 } 383 384 public <T extends SynchronizationResult> T synchronizeValues(Map<String, Object> values) throws UndefinedItemPathException, BadItemTypeException 385 { 386 return getContent().synchronizeValues(values); 387 } 388 389 public <T extends SynchronizationResult> T synchronizeValues(Map<String, Object> values, SynchronizationContext context) throws UndefinedItemPathException, BadItemTypeException 390 { 391 return getContent().synchronizeValues(values, context); 392 } 393 394 public <T extends SynchronizationResult> T synchronizeValues(ViewItemContainer viewItemContainer, Map<String, Object> values) throws UndefinedItemPathException, BadItemTypeException 395 { 396 return getContent().synchronizeValues(viewItemContainer, values); 397 } 398 399 public <T extends SynchronizationResult> T synchronizeValues(ViewItemContainer viewItemContainer, Map<String, Object> values, SynchronizationContext context) throws UndefinedItemPathException, BadItemTypeException 400 { 401 return getContent().synchronizeValues(viewItemContainer, values, context); 402 } 403 404 public void setValue(String dataPath, Object value) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 405 { 406 getContent().setValue(dataPath, value); 407 } 408 409 public void setLocalValue(String dataPath, Object localValue) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 410 { 411 getContent().setLocalValue(dataPath, localValue); 412 } 413 414 public void setExternalValue(String dataPath, Object externalValue) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 415 { 416 getContent().setExternalValue(dataPath, externalValue); 417 } 418 419 public void setStatus(String dataPath, ExternalizableDataStatus status) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 420 { 421 getContent().setStatus(dataPath, status); 422 } 423 424 public void setComments(String dataName, List<DataComment> comments) throws IllegalArgumentException, UndefinedItemPathException 425 { 426 getContent().setComments(dataName, comments); 427 } 428 429 public void removeValue(String dataPath) throws IllegalArgumentException, UndefinedItemPathException, UnknownDataException, BadDataPathCardinalityException 430 { 431 getContent().removeValue(dataPath); 432 } 433 434 public void removeLocalValue(String dataPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, UnknownDataException, BadDataPathCardinalityException 435 { 436 getContent().removeLocalValue(dataPath); 437 } 438 439 public void removeExternalValue(String dataPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, UnknownDataException, BadDataPathCardinalityException 440 { 441 getContent().removeExternalValue(dataPath); 442 } 443 444 public void removeExternalizableMetadataIfExists(String dataPath) throws IllegalArgumentException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 445 { 446 getContent().removeExternalizableMetadataIfExists(dataPath); 447 } 448 449 public ModifiableRepositoryData getRepositoryData() 450 { 451 return getContent().getRepositoryData(); 452 } 453 454 public Optional<? extends ModifiableModelAwareDataHolder> getParentDataHolder() 455 { 456 return getContent().getParentDataHolder(); 457 } 458 459 public ModifiableModelAwareDataHolder getRootDataHolder() 460 { 461 return getContent().getRootDataHolder(); 462 } 463}