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.plugins.repository.data.holder; 017 018import java.util.Collection; 019import java.util.Map; 020import java.util.Optional; 021 022import org.xml.sax.ContentHandler; 023import org.xml.sax.SAXException; 024 025import org.ametys.plugins.repository.data.UnknownDataException; 026import org.ametys.plugins.repository.data.holder.group.Composite; 027import org.ametys.plugins.repository.data.holder.impl.DataHolderHelper; 028import org.ametys.plugins.repository.data.repositorydata.RepositoryData; 029import org.ametys.plugins.repository.data.type.ModelItemTypeExtensionPoint; 030import org.ametys.runtime.model.exception.BadDataPathCardinalityException; 031import org.ametys.runtime.model.exception.BadItemTypeException; 032import org.ametys.runtime.model.exception.NotUniqueTypeException; 033import org.ametys.runtime.model.exception.UndefinedItemPathException; 034import org.ametys.runtime.model.exception.UnknownTypeException; 035import org.ametys.runtime.model.type.DataContext; 036import org.ametys.runtime.model.type.ModelItemType; 037 038/** 039 * Interface for data containers 040 */ 041public interface DataHolder 042{ 043 /** 044 * Retrieves the composite at the given path 045 * @param compositePath path of the composite to retrieve 046 * @return the composite or <code>null</code> if not exists or is empty 047 * @throws IllegalArgumentException if the given composite path is null or empty 048 * @throws UnknownTypeException if the type composite is not available for this data holder 049 * @throws BadItemTypeException if the stored value at the given path is not a composite 050 * @throws UndefinedItemPathException if the data holder has a model and the given composite path is not defined by this model 051 * @throws BadDataPathCardinalityException if the data holder has a model and the definition of a part of the data path is multiple. Only the last part can be multiple 052 */ 053 public Composite getComposite(String compositePath) throws IllegalArgumentException, UnknownTypeException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException; 054 055 /** 056 * Checks if there is a non empty value for the data at the given path 057 * @param dataPath path of the data 058 * @return <code>true</code> if there is a non empty value for the data. If the data holder has a model and the data at the given path is defined by the model and the type of this value matches the type of the definition. <code>false</code> otherwise 059 * @throws IllegalArgumentException if the given data path is null or empty 060 * @throws BadDataPathCardinalityException if the data holder has a model and the definition of a part of the data path is multiple. Only the last part can be multiple 061 * 062 * 063 */ 064 public boolean hasValue(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException; 065 066 /** 067 * Checks if there is a non empty value for the data at the given path 068 * @param dataPath path of the data 069 * @param dataTypeId type identifier of the data 070 * @return <code>true</code> if there is a non empty value for the data. If the data holder has a model and the data at the given path is defined by the model and the type of this value matches the type of the definition. <code>false</code> otherwise 071 * @throws IllegalArgumentException if the given data path is null or empty 072 * @throws UnknownTypeException if the given type isn't available for this data holder's type extension point 073 * @throws BadDataPathCardinalityException if the data holder has a model and the definition of a part of the data path is multiple. Only the last part can be multiple 074 * 075 */ 076 public boolean hasValue(String dataPath, String dataTypeId) throws IllegalArgumentException, UnknownTypeException, BadDataPathCardinalityException; 077 078 /** 079 * Checks if there is a value, even empty, for the data at the given path 080 * @param dataPath path of the data 081 * @return <code>true</code> if there is value, even empty, for the data. If the data holder has a model and the data at the given path is defined by the model and the type of this value matches the type of the definition. <code>false</code> otherwise 082 * @throws IllegalArgumentException if the given data path is null or empty 083 * @throws BadDataPathCardinalityException if the data holder has a model and the definition of a part of the data path is multiple. Only the last part can be multiple 084 * 085 */ 086 public boolean hasValueOrEmpty(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException; 087 088 /** 089 * Retrieves the names of data contained by this data holder 090 * Retrieves only the data at first level, does not check composite data 091 * @return the names of all data contained by this data holder 092 */ 093 public Collection<String> getDataNames(); 094 095 /** 096 * Retrieves the value of the data at the given path 097 * @param <T> type of the value to retrieve. If the data holder has a model, the type of the value is defined by this model. Otherwise, the type of the value will be deduced from the stored data. In some cases, the type can be wrong. For example, it is impossible to know if a stored date is a date or a date time 098 * @param dataPath path of the data 099 * @return the value of the data or <code>null</code> if not exists or is empty. A typed array is returned for multiple empty data, and an empty string is returned for single empty string data 100 * @throws IllegalArgumentException if the given data path is null or empty 101 * @throws UnknownTypeException if there is no compatible type with the data at the given data path 102 * @throws NotUniqueTypeException if there are many compatible types (there is no way to determine which type is the good one) 103 * @throws BadItemTypeException if the data holder has a model and the type defined by the model doesn't match the type of the stored value, or if value at the sub data path of the given one is not a composite 104 * @throws UndefinedItemPathException if the data holder has a model and the given data path is not defined by this model 105 * @throws BadDataPathCardinalityException if the data holder has a model and the definition of a part of the data path is multiple. Only the last part can be multiple 106 */ 107 public <T> T getValue(String dataPath) throws IllegalArgumentException, UnknownTypeException, NotUniqueTypeException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException; 108 109 /** 110 * Retrieves the value of the data at the given path if exists and is not empty, or the given default value 111 * @param <T> type of the value to retrieve. If the data holder has a model, the type of the value is defined by this model. Otherwise, the type of the value will be deduced from the stored data. In some cases, the type can be wrong. For example, it is impossible to know if a stored date is a date or a date time 112 * @param dataPath path of the data 113 * @param defaultValue default value 114 * @return the value of the data, or the given default value if the value does not exist or is empty 115 * @throws IllegalArgumentException if the given data path is null or empty 116 * @throws UnknownTypeException if there is no compatible type with the data at the given data path 117 * @throws NotUniqueTypeException if there are many compatible types (there is no way to determine which type is the good one) 118 * @throws BadItemTypeException if value at the sub data path of the given one is not a composite 119 * @throws UndefinedItemPathException if the data holder has a model and the given data path is not defined by this model 120 * @throws BadDataPathCardinalityException if the data holder has a model and the definition of a part of the data path is multiple. Only the last part can be multiple 121 */ 122 public <T> T getValueOrDefault(String dataPath, T defaultValue) throws IllegalArgumentException, UnknownTypeException, NotUniqueTypeException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException; 123 124 /** 125 * Retrieves the value of the data at the given path 126 * @param <T> type of the value to retrieve. Should match the given data type 127 * @param dataPath path of the data 128 * @param dataTypeId type identifier of the data 129 * @return the value of the data or <code>null</code> if not exists or is empty. A typed array is returned for multiple empty data, and an empty string is returned for single empty string data 130 * @throws IllegalArgumentException if the given data path is null or empty 131 * @throws UnknownTypeException if the given type isn't available for this data holder's type extension point 132 * @throws BadItemTypeException if the given type doesn't match the type of the stored value at the given path 133 * @throws UndefinedItemPathException if the data holder has a model and the given data path is not defined by this model 134 * @throws BadDataPathCardinalityException if the data holder has a model and the definition of a part of the data path is multiple. Only the last part can be multiple 135 */ 136 public <T> T getValueOfType(String dataPath, String dataTypeId) throws IllegalArgumentException, UnknownTypeException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException; 137 138 /** 139 * Retrieves the value of the data at the given path if exists and is not empty, or the given default value 140 * @param <T> type of the value to retrieve. Should match the given data type 141 * @param dataPath path of the data 142 * @param dataTypeId type identifier of the data 143 * @param defaultValue default value 144 * @return the value of the data, or the given default value if the value does not exist or is empty 145 * @throws IllegalArgumentException if the given data path is null or empty 146 * @throws UnknownTypeException if the given type isn't available for this data holder's type extension point 147 * @throws BadItemTypeException if the given type doesn't match the type of the stored value at the given path 148 * @throws UndefinedItemPathException if the data holder has a model and the given data path is not defined by this model 149 * @throws BadDataPathCardinalityException if the data holder has a model and the definition of a part of the data path is multiple. Only the last part can be multiple 150 */ 151 public <T> T getValueOfTypeOrDefault(String dataPath, String dataTypeId, T defaultValue) throws IllegalArgumentException, UnknownTypeException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException; 152 153 /** 154 * Checks if the value of the data at the given path is multiple 155 * @param dataPath path of the data to check 156 * @return <code>true</code> if the value of the data is multiple, <code>false</code> otherwise 157 * @throws IllegalArgumentException if the given data path is null or empty 158 * @throws UnknownDataException the data at the given path does not exist 159 * @throws UnknownTypeException if there is no compatible type with the data at the given data path 160 * @throws NotUniqueTypeException if there are many compatible types (there is no way to determine which type is the good one) 161 * @throws BadItemTypeException if value at the sub data path of the given one is not a composite 162 * @throws UndefinedItemPathException if the data holder has a model and the given data path is not defined by this model 163 */ 164 public boolean isMultiple(String dataPath) throws IllegalArgumentException, UnknownDataException, UnknownTypeException, NotUniqueTypeException, BadItemTypeException, UndefinedItemPathException; 165 166 /** 167 * Checks if the value of the data at the given path is multiple 168 * @param dataPath path of the data to check 169 * @param dataTypeId type identifier of the data 170 * @return <code>true</code> if the value of the data is multiple, <code>false</code> otherwise 171 * @throws IllegalArgumentException if the given data path is null or empty 172 * @throws UnknownDataException the data at the given path does not exist 173 * @throws UnknownTypeException if there is no compatible type with the data at the given data path 174 * @throws BadItemTypeException if value at the sub data path of the given one is not a composite 175 * @throws UndefinedItemPathException if the data holder has a model and the given data path is not defined by this model 176 */ 177 public boolean isMultiple(String dataPath, String dataTypeId) throws IllegalArgumentException, UnknownDataException, UnknownTypeException, BadItemTypeException, UndefinedItemPathException; 178 179 /** 180 * Retrieves the type of the data at the given path 181 * @param <X> type of the item type 182 * @param dataPath path of the data 183 * @return the type of the data 184 * @throws IllegalArgumentException if the given data path is null or empty 185 * @throws UnknownDataException if there is no data stored at the given path 186 * @throws UnknownTypeException if there is no compatible type with the data at the given data path or if the data is a repeater entry but the composite type is not available 187 * @throws NotUniqueTypeException if there are many compatible types (there is no way to determine which type is the good one) 188 * @throws UndefinedItemPathException if the data holder has a model and the given data path is not defined by this model 189 */ 190 public <X extends ModelItemType> X getType(String dataPath) throws IllegalArgumentException, UnknownDataException, UnknownTypeException, NotUniqueTypeException, UndefinedItemPathException; 191 192 /** 193 * Provide the ModelItemTypeExtensionPoint linked with the DataHolder 194 * @return the extension point 195 */ 196 public ModelItemTypeExtensionPoint getModelItemTypeExtensionPoint(); 197 198 /** 199 * Copies the current {@link DataHolder} to the given {@link ModifiableDataHolder}. 200 * @param dataHolder The destination dataHolder. Can not be null. 201 * @throws UnknownTypeException if there is no available type compatible with the copied value for the type extension point of the destination {@link ModifiableDataHolder} 202 * @throws NotUniqueTypeException if there is more than one available types compatibles with the copied value for the type extension point of the destination {@link ModifiableDataHolder} 203 * @throws BadItemTypeException if type of a data to copy doesn't match the data with same path in the destination {@link ModifiableDataHolder} 204 * @throws UndefinedItemPathException if the data holder has a model and the given data path is not defined by this model 205 */ 206 public default void copyTo(ModifiableDataHolder dataHolder) throws UnknownTypeException, NotUniqueTypeException, BadItemTypeException, UndefinedItemPathException 207 { 208 copyTo(dataHolder, DataContext.newInstance()); 209 } 210 211 /** 212 * Copies the current {@link DataHolder} to the given {@link ModifiableDataHolder}. 213 * @param dataHolder The destination dataHolder. Can not be null. 214 * @param context The context of the data to copy 215 * @throws UnknownTypeException if there is no available type compatible with the copied value for the type extension point of the destination {@link ModifiableDataHolder} 216 * @throws NotUniqueTypeException if there is more than one available types compatibles with the copied value for the type extension point of the destination {@link ModifiableDataHolder} 217 * @throws BadItemTypeException if type of a data to copy doesn't match the data with same path in the destination {@link ModifiableDataHolder} 218 * @throws UndefinedItemPathException if the data holder has a model and the given data path is not defined by this model 219 */ 220 public default void copyTo(ModifiableDataHolder dataHolder, DataContext context) throws UnknownTypeException, NotUniqueTypeException, BadItemTypeException, UndefinedItemPathException 221 { 222 DataHolderHelper.copyTo(this, dataHolder, context); 223 } 224 225 /** 226 * Generates SAX events for data contained in this {@link DataHolder} 227 * @param contentHandler the {@link ContentHandler} that will receive the SAX events 228 * @throws SAXException if an error occurs during the SAX events generation 229 * @throws UnknownTypeException if there is no compatible type with the saxed value 230 * @throws NotUniqueTypeException if there are many compatible types (there is no way to determine which type is the good one) with the saxed value 231 * @throws BadItemTypeException if the saxed value's type does not matches the stored data 232 */ 233 public default void dataToSAX(ContentHandler contentHandler) throws SAXException, UnknownTypeException, NotUniqueTypeException, BadItemTypeException 234 { 235 dataToSAX(contentHandler, DataContext.newInstance()); 236 } 237 238 /** 239 * Generates SAX events for data contained in this {@link DataHolder} 240 * @param contentHandler the {@link ContentHandler} that will receive the SAX events 241 * @param context The context of the data to SAX 242 * @throws SAXException if an error occurs during the SAX events generation 243 * @throws UnknownTypeException if there is no compatible type with the saxed value 244 * @throws NotUniqueTypeException if there are many compatible types (there is no way to determine which type is the good one) with the saxed value 245 * @throws BadItemTypeException if the saxed value's type does not matches the stored data 246 */ 247 public void dataToSAX(ContentHandler contentHandler, DataContext context) throws SAXException, UnknownTypeException, NotUniqueTypeException, BadItemTypeException; 248 249 /** 250 * Generates SAX events for the data at the given data path in the current {@link DataHolder} 251 * Do not generate any event if there is no values at the given path 252 * @param contentHandler the {@link ContentHandler} that will receive the SAX events 253 * @param dataPath the path of the data to SAX 254 * @throws SAXException if an error occurs during the SAX events generation 255 * @throws UnknownTypeException if there is no compatible type with the saxed value 256 * @throws NotUniqueTypeException if there are many compatible types (there is no way to determine which type is the good one) with the saxed value 257 * @throws BadItemTypeException if the saxed value's type does not matches the stored data 258 * @throws UndefinedItemPathException if the data holder has a model and the given data path is not defined by this model 259 */ 260 public default void dataToSAX(ContentHandler contentHandler, String dataPath) throws SAXException, UnknownTypeException, NotUniqueTypeException, BadItemTypeException, UndefinedItemPathException 261 { 262 dataToSAX(contentHandler, dataPath, DataContext.newInstance()); 263 } 264 265 /** 266 * Generates SAX events for the data at the given data path in the current {@link DataHolder} 267 * Do not generate any event if there is no values at the given path 268 * @param contentHandler the {@link ContentHandler} that will receive the SAX events 269 * @param dataPath the path of the data to SAX 270 * @param context The context of the data to SAX 271 * @throws SAXException if an error occurs during the SAX events generation 272 * @throws UnknownTypeException if there is no compatible type with the saxed value 273 * @throws NotUniqueTypeException if there are many compatible types (there is no way to determine which type is the good one) with the saxed value 274 * @throws BadItemTypeException if the saxed value's type does not matches the stored data 275 * @throws UndefinedItemPathException if the data holder has a model and the given data path is not defined by this model 276 */ 277 public void dataToSAX(ContentHandler contentHandler, String dataPath, DataContext context) throws SAXException, UnknownTypeException, NotUniqueTypeException, BadItemTypeException, UndefinedItemPathException; 278 279 /** 280 * Convert the data contained in this {@link DataHolder} 281 * @return The data of the current {@link DataHolder} as JSON 282 * @throws UnknownTypeException if there is no compatible type with the value to convert 283 * @throws NotUniqueTypeException if there are many compatible types (there is no way to determine which type is the good one) with the value to convert 284 * @throws BadItemTypeException if the value's type does not matches the stored data 285 */ 286 public default Map<String, Object> dataToJSON() throws UnknownTypeException, NotUniqueTypeException, BadItemTypeException 287 { 288 return dataToJSON(DataContext.newInstance()); 289 } 290 291 /** 292 * Convert the data contained in this {@link DataHolder} 293 * @param context The context of the data to convert 294 * @return The data of the current {@link DataHolder} as JSON 295 * @throws UnknownTypeException if there is no compatible type with the value to convert 296 * @throws NotUniqueTypeException if there are many compatible types (there is no way to determine which type is the good one) with the value to convert 297 * @throws BadItemTypeException if the value's type does not matches the stored data 298 */ 299 public Map<String, Object> dataToJSON(DataContext context) throws UnknownTypeException, NotUniqueTypeException, BadItemTypeException; 300 301 /** 302 * Convert the data at the given path into a JSON object 303 * @param dataPath the path of the data to convert 304 * @return The value as JSON 305 * @throws UnknownTypeException if there is no compatible type with the value to convert 306 * @throws NotUniqueTypeException if there are many compatible types (there is no way to determine which type is the good one) with the value to convert 307 * @throws BadItemTypeException if the value's type does not matches the stored data 308 * @throws UndefinedItemPathException if the data holder has a model and the given data path is not defined by this model 309 */ 310 public default Object dataToJSON(String dataPath) throws UnknownTypeException, NotUniqueTypeException, BadItemTypeException, UndefinedItemPathException 311 { 312 return dataToJSON(dataPath, DataContext.newInstance()); 313 } 314 315 /** 316 * Convert the data at the given path into a JSON object 317 * @param dataPath the path of the data to convert 318 * @param context The context of the data to convert 319 * @return The value as JSON 320 * @throws UnknownTypeException if there is no compatible type with the value to convert 321 * @throws NotUniqueTypeException if there are many compatible types (there is no way to determine which type is the good one) with the value to convert 322 * @throws BadItemTypeException if the value's type does not matches the stored data 323 * @throws UndefinedItemPathException if the data holder has a model and the given data path is not defined by this model 324 */ 325 public Object dataToJSON(String dataPath, DataContext context) throws UnknownTypeException, NotUniqueTypeException, BadItemTypeException, UndefinedItemPathException; 326 327 /** 328 * Check if there are differences between the given values and the current ones 329 * @param values the values to check 330 * @return <code>true</code> if there are differences, <code>false</code> otherwise 331 * @throws UnknownTypeException if there is no available type compatible with a given value for this data holder's type extension point 332 * @throws NotUniqueTypeException if there is more than one available types compatibles with the a value for this data holder's type extension point 333 * @throws BadItemTypeException if value doesn't match the data at corresponding path 334 */ 335 public boolean hasDifferences(Map<String, Object> values) throws UnknownTypeException, NotUniqueTypeException, BadItemTypeException; 336 337 /** 338 * Retrieves the repository data used by this {@link DataHolder} 339 * @return the repository data used by this {@link DataHolder} 340 */ 341 public RepositoryData getRepositoryData(); 342 343 /** 344 * Retrieves the optional parent of the current {@link DataHolder} 345 * There can be no parent if the current {@link DataHolder} is the root 346 * @return the parent of the current {@link DataHolder} 347 */ 348 public Optional<? extends DataHolder> getParentDataHolder(); 349 350 /** 351 * Retrieves the {@link DataHolder} that is the root of the current one 352 * @return the root {@link DataHolder} 353 */ 354 public DataHolder getRootDataHolder(); 355}