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