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.io.IOException; 019import java.util.Collection; 020import java.util.Locale; 021 022import org.apache.commons.lang3.StringUtils; 023import org.xml.sax.ContentHandler; 024import org.xml.sax.SAXException; 025 026import org.ametys.plugins.repository.data.external.ExternalizableDataProvider.ExternalizableDataStatus; 027import org.ametys.plugins.repository.data.holder.group.impl.ModelAwareComposite; 028import org.ametys.plugins.repository.data.holder.group.impl.ModelAwareRepeater; 029import org.ametys.plugins.repository.data.holder.impl.DataHolderHelper; 030import org.ametys.plugins.repository.data.type.RepositoryModelItemType; 031import org.ametys.plugins.repository.metadata.MultilingualString; 032import org.ametys.plugins.repository.model.RepeaterDefinition; 033import org.ametys.runtime.model.ElementDefinition; 034import org.ametys.runtime.model.ModelItem; 035import org.ametys.runtime.model.ModelItemContainer; 036import org.ametys.runtime.model.ViewItemContainer; 037import org.ametys.runtime.model.exception.BadDataPathCardinalityException; 038import org.ametys.runtime.model.exception.BadItemTypeException; 039import org.ametys.runtime.model.exception.UndefinedItemPathException; 040 041/** 042 * Interface for data containers with models 043 */ 044public interface ModelAwareDataHolder extends DataHolder 045{ 046 /** Suffix used for the alternative value */ 047 public static final String ALTERNATIVE_SUFFIX = "__alt"; 048 /** Suffix used for the status value */ 049 public static final String STATUS_SUFFIX = "__status"; 050 051 /** 052 * {@inheritDoc} 053 * @throws UndefinedItemPathException if the given composite path is not defined by the model 054 * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple 055 */ 056 @Override 057 public ModelAwareComposite getComposite(String compositePath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException; 058 059 /** 060 * Retrieves the local composite at the given path 061 * @param compositePath path of the externalizable composite to retrieve 062 * @return the composite or <code>null</code> if not exists or is empty 063 * @throws IllegalArgumentException if the given composite path is null or empty 064 * @throws BadItemTypeException if the stored value at the given path is not a composite 065 * @throws UndefinedItemPathException if the given composite path is not defined by the model 066 * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple 067 */ 068 public ModelAwareComposite getLocalComposite(String compositePath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException; 069 070 /** 071 * Retrieves the external composite at the given path 072 * @param compositePath path of the externalizable composite to retrieve 073 * @return the composite or <code>null</code> if not exists or is empty 074 * @throws IllegalArgumentException if the given composite path is null or empty 075 * @throws BadItemTypeException if the stored value at the given path is not a composite 076 * @throws UndefinedItemPathException if the given composite path is not defined by the model 077 * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple 078 */ 079 public ModelAwareComposite getExternalComposite(String compositePath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException; 080 081 /** 082 * Retrieves the repeater at the given path 083 * @param repeaterPath path of the repeater to retrieve 084 * @return the repeater or <code>null</code> if not exists or is empty 085 * @throws IllegalArgumentException if the given repeater path is null or empty 086 * @throws BadItemTypeException if the stored value at the given path is not a repeater 087 * @throws UndefinedItemPathException if the given repeater path is not defined by the model 088 * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple 089 */ 090 public ModelAwareRepeater getRepeater(String repeaterPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException; 091 092 /** 093 * Retrieves the local repeater at the given path 094 * @param repeaterPath path of the externalizable repeater to retrieve 095 * @return the repeater or <code>null</code> if not exists or is empty 096 * @throws IllegalArgumentException if the given repeater path is null or empty 097 * @throws BadItemTypeException if the stored value at the given path is not a repeater 098 * @throws UndefinedItemPathException if the given repeater path is not defined by the model 099 * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple 100 */ 101 public ModelAwareRepeater getLocalRepeater(String repeaterPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException; 102 103 /** 104 * Retrieves the external repeater at the given path 105 * @param repeaterPath path of the externalizable repeater to retrieve 106 * @return the repeater or <code>null</code> if not exists or is empty 107 * @throws IllegalArgumentException if the given repeater path is null or empty 108 * @throws BadItemTypeException if the stored value at the given path is not a repeater 109 * @throws UndefinedItemPathException if the given repeater path is not defined by the model 110 * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple 111 */ 112 public ModelAwareRepeater getExternalRepeater(String repeaterPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException; 113 114 /** 115 * {@inheritDoc} 116 * @return <code>true</code> if the data at the given path is defined by the model, if there is a value for the data (even empty) and if the type of this value matches the type of the definition. <code>false</code> otherwise 117 * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple 118 */ 119 @Override 120 public boolean hasValue(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException; 121 122 /** 123 * Checks if there is a local value for the data at the given path 124 * @param dataPath path of the externalizable data 125 * @return <code>true</code> if the data at the given path is defined by the model, if there is a local value for the data (even empty) and if the type of this value matches the type of the definition. <code>false</code> otherwise 126 * @throws IllegalArgumentException if the given data path is null or empty 127 * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple 128 */ 129 public boolean hasLocalValue(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException; 130 131 /** 132 * Checks if there is an external value for the data at the given path 133 * @param dataPath path of the externalizable data 134 * @return <code>true</code> if the data at the given path is defined by the model, if there is an external value for the data (even empty) and if the type of this value matches the type of the definition. <code>false</code> otherwise 135 * @throws IllegalArgumentException if the given data path is null or empty 136 * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple 137 */ 138 public boolean hasExternalValue(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException; 139 140 /** 141 * {@inheritDoc} 142 * @return the names of the data contained by this data holder and that are defined by the model 143 */ 144 @Override 145 public Collection<String> getDataNames(); 146 147 /** 148 * Retrieves the value of the data at the given path 149 * @param <T> type of the value to retrieve 150 * @param dataPath path of the data 151 * @return the value of the data or <code>null</code> if not exists or is empty. The object returned may be of a generic class defined by the storage (if the model is unknown). For example, an url may be returned as a String. 152 * @throws IllegalArgumentException if the given data path is null or empty 153 * @throws UndefinedItemPathException if the given data path is not defined by the model 154 * @throws BadItemTypeException if the type defined by the model doesn't match the type of the stored value 155 * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple 156 */ 157 public default <T extends Object> T getValue(String dataPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException 158 { 159 return getValue(dataPath, false); 160 } 161 162 /** 163 * Retrieves the value of the data at the given path 164 * @param <T> type of the value to retrieve 165 * @param dataPath path of the data 166 * @param allowMultiValuedPathSegments <code>true</code> to allow multi-valued segments in the path (not necessarily at the last segment), <code>false</code> otherwise. 167 * If <code>true</code>, if there is no indicated entry for a repeater, the values of all the entries are retrieved 168 * If <code>true</code> and if there are multiple values, all data are retrieved in one array 169 * @return the value of the data or <code>null</code> if managesMutiples is <code>false</code> and there is no non empty value. The object returned may be of a generic class defined by the storage (if the model is unknown). For example, an url may be returned as a String. 170 * @throws IllegalArgumentException if the given data path is null or empty 171 * @throws UndefinedItemPathException if the given data path is not defined by the model 172 * @throws BadItemTypeException if the type defined by the model doesn't match the type of the stored value 173 * @throws BadDataPathCardinalityException if the managesMultiples boolean is <code>false</code> and the definition of a part of the data path is multiple. Only the last part can be multiple 174 */ 175 public <T extends Object> T getValue(String dataPath, boolean allowMultiValuedPathSegments) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException; 176 177 /** 178 * Retrieves the value of the data at the given path, or the default value 179 * The returned value is one of those ones, in the order: 180 * <ol> 181 * <li>The value of the data if exists and is not empty</li> 182 * <li>The default value from the model if useDefaultFromModel is <code>true</code> and there is a default value defined by the model</li> 183 * <li>The given default value</li> 184 * </ol> 185 * @param <T> type of the value to retrieve 186 * @param dataPath path of the data 187 * @param useDefaultFromModel true to use the default value from the model, false to use the given default value 188 * @param defaultValue default value used if value is null and useDefaultFromModel is false, or if there is no default value on model 189 * @return the value of the data at the given path 190 * @throws IllegalArgumentException if the given data path is null or empty 191 * @throws UndefinedItemPathException if the given data path is not defined by the model 192 * @throws BadItemTypeException if the type defined by the model doesn't match the type of the stored value 193 * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple 194 */ 195 public <T extends Object> T getValue(String dataPath, boolean useDefaultFromModel, T defaultValue) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException; 196 197 /** 198 * Retrieves the local value of the data at the given path 199 * @param <T> type of the value to retrieve 200 * @param dataPath path of the externalizable data 201 * @return the local value of the data or <code>null</code> if not exists or is empty. The object returned may be of a generic class defined by the storage (if the model is unknown). For example, an url may be returned as a String. 202 * @throws IllegalArgumentException if the given data path is null or empty 203 * @throws UndefinedItemPathException if the given data path is not defined by the model 204 * @throws BadItemTypeException if the type defined by the model doesn't match the type of the stored value 205 * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple 206 */ 207 public <T extends Object> T getLocalValue(String dataPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException; 208 209 /** 210 * Retrieves the external value of the data at the given path 211 * @param <T> type of the value to retrieve 212 * @param dataPath path of the externalizable data 213 * @return the external value of the data or <code>null</code> if not exists or is empty. The object returned may be of a generic class defined by the storage (if the model is unknown). For example, an url may be returned as a String. 214 * @throws IllegalArgumentException if the given data path is null or empty 215 * @throws UndefinedItemPathException if the given data path is not defined by the model 216 * @throws BadItemTypeException if the type defined by the model doesn't match the type of the stored value 217 * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple 218 */ 219 public <T extends Object> T getExternalValue(String dataPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException; 220 221 /** 222 * Retrieves the status of the externalizable data at the given path 223 * @param dataPath path of the externalizable data 224 * @return the status of the externalizable data at the given path 225 * @throws IllegalArgumentException if the given data path is null or empty 226 * @throws UndefinedItemPathException if the given data path is not defined by the model 227 * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple 228 */ 229 public ExternalizableDataStatus getStatus(String dataPath) throws IllegalArgumentException, UndefinedItemPathException, BadDataPathCardinalityException; 230 231 /** 232 * Checks if the definition of the element at the given path is multiple 233 * @param path path of the element. No matter if it is a definition or data path (with repeater entry positions) 234 * @return <code>true</code> if the element is multiple, <code>false</code> otherwise 235 * @throws IllegalArgumentException if the given path is null or empty 236 * @throws UndefinedItemPathException if the given path is not defined by the model 237 */ 238 public default boolean isMultiple(String path) throws IllegalArgumentException, UndefinedItemPathException 239 { 240 ModelItem item = getDefinition(path); 241 if (item instanceof ElementDefinition) 242 { 243 return ((ElementDefinition) item).isMultiple(); 244 } 245 else if (item instanceof RepeaterDefinition) 246 { 247 // If the given path represents a repeater , but with no specified entry, consider the data as multiple 248 return !DataHolderHelper.isRepeaterEntryPath(path); 249 } 250 else 251 { 252 // Composites are not multiples 253 return false; 254 } 255 } 256 257 /** 258 * Retrieves the type of the data at the given path 259 * @param path path of the data. No matter if it is a definition or data path (with repeater entry positions) 260 * @return the type of the data 261 * @throws IllegalArgumentException if the given data path is null or empty 262 * @throws UndefinedItemPathException if the given data path is not defined by the model 263 */ 264 public default RepositoryModelItemType getType(String path) throws IllegalArgumentException, UndefinedItemPathException 265 { 266 return (RepositoryModelItemType) getDefinition(path).getType(); 267 } 268 269 /** 270 * Retrieves the data holder's model 271 * @return the data holder's model 272 */ 273 public Collection<? extends ModelItemContainer> getModel(); 274 275 /** 276 * Retrieves the definition of the data at the given path 277 * @param path path of the data. No matter if it is a definition or data path (with repeater entry positions) 278 * @return the definition of the data 279 * @throws IllegalArgumentException if the given path is null or empty 280 * @throws UndefinedItemPathException if the given path is not defined by the model 281 */ 282 public ModelItem getDefinition(String path) throws IllegalArgumentException, UndefinedItemPathException; 283 284 /** 285 * Checks if there is a definition at the given path 286 * @param path path of the data. No matter if it is a definition or data path (with repeater entry positions) 287 * @return <code>true</code> if there is definition at the given path, <code>false</code> otherwise 288 * @throws IllegalArgumentException if the given path is null or empty 289 */ 290 public boolean hasDefinition(String path) throws IllegalArgumentException; 291 292 /** 293 * Generates SAX events for the data in the model of the current {@link DataHolder} 294 * @param contentHandler the {@link ContentHandler} that will receive the SAX events 295 * @throws SAXException if an error occurs during the SAX events generation 296 * @throws IOException if an error occurs while reading a value using the I/O API 297 * @throws BadItemTypeException if the saxed value's type does not matches the stored data 298 */ 299 public default void dataToSAX(ContentHandler contentHandler) throws SAXException, IOException, BadItemTypeException 300 { 301 dataToSAX(contentHandler, (Locale) null); 302 } 303 304 /** 305 * Generates SAX events for the data in the model of the current {@link DataHolder} 306 * @param contentHandler the {@link ContentHandler} that will receive the SAX events 307 * @param locale The locale to use for localized data, such as {@link MultilingualString}. Can be <code>null</code> to generate SAX events for all existing {@link Locale}s. 308 * @throws SAXException if an error occurs during the SAX events generation 309 * @throws IOException if an error occurs while reading a value using the I/O API 310 * @throws BadItemTypeException if the saxed value's type does not matches the stored data 311 */ 312 public void dataToSAX(ContentHandler contentHandler, Locale locale) throws SAXException, IOException, BadItemTypeException; 313 314 /** 315 * Generates SAX events for the data in the given view in the current {@link DataHolder} 316 * @param contentHandler the {@link ContentHandler} that will receive the SAX events 317 * @param viewItemContainer the {@link ViewItemContainer} containing referencing the model item for which generate SAX events 318 * @throws SAXException if an error occurs during the SAX events generation 319 * @throws IOException if an error occurs while reading a value using the I/O API 320 * @throws BadItemTypeException if the saxed value's type does not matches the stored data 321 */ 322 public default void dataToSAX(ContentHandler contentHandler, ViewItemContainer viewItemContainer) throws SAXException, IOException, BadItemTypeException 323 { 324 dataToSAX(contentHandler, viewItemContainer, null); 325 } 326 327 /** 328 * Generates SAX events for the data in the given view in the current {@link DataHolder} 329 * @param contentHandler the {@link ContentHandler} that will receive the SAX events 330 * @param viewItemContainer the {@link ViewItemContainer} containing referencing the model item for which generate SAX events 331 * @param locale The locale to use for localized data, such as {@link MultilingualString}. Can be <code>null</code> to generate SAX events for all existing {@link Locale}s. 332 * @throws SAXException if an error occurs during the SAX events generation 333 * @throws IOException if an error occurs while reading a value using the I/O API 334 * @throws BadItemTypeException if the saxed value's type does not matches the stored data 335 */ 336 public default void dataToSAX(ContentHandler contentHandler, ViewItemContainer viewItemContainer, Locale locale) throws SAXException, IOException, BadItemTypeException 337 { 338 DataHolderHelper.dataToSAX(this, contentHandler, viewItemContainer, StringUtils.EMPTY, locale); 339 } 340}