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.List;
020import java.util.Map;
021import java.util.Optional;
022
023import org.apache.commons.lang3.StringUtils;
024import org.xml.sax.ContentHandler;
025import org.xml.sax.SAXException;
026
027import org.ametys.plugins.repository.data.DataComment;
028import org.ametys.plugins.repository.data.external.ExternalizableDataProvider.ExternalizableDataStatus;
029import org.ametys.plugins.repository.data.holder.group.ModelAwareComposite;
030import org.ametys.plugins.repository.data.holder.group.ModelAwareRepeater;
031import org.ametys.plugins.repository.data.holder.impl.DataHolderHelper;
032import org.ametys.plugins.repository.data.holder.values.SynchronizationContext;
033import org.ametys.plugins.repository.model.RepeaterDefinition;
034import org.ametys.runtime.model.ElementDefinition;
035import org.ametys.runtime.model.ModelHelper;
036import org.ametys.runtime.model.ModelItem;
037import org.ametys.runtime.model.ModelItemContainer;
038import org.ametys.runtime.model.ViewHelper;
039import org.ametys.runtime.model.ViewItemAccessor;
040import org.ametys.runtime.model.exception.BadDataPathCardinalityException;
041import org.ametys.runtime.model.exception.BadItemTypeException;
042import org.ametys.runtime.model.exception.UndefinedItemPathException;
043import org.ametys.runtime.model.type.DataContext;
044import org.ametys.runtime.model.type.ModelItemType;
045
046/**
047 * Interface for data containers with models
048 */
049public interface ModelAwareDataHolder extends DataHolder
050{
051    /** Suffix used for the alternative value */
052    public static final String ALTERNATIVE_SUFFIX = "__alt";
053    /** Suffix used for the status value */
054    public static final String STATUS_SUFFIX = "__status";
055    /** Suffix used for the comments */
056    public static final String COMMENTS_SUFFIX = "_comments";
057    
058    /**
059     * {@inheritDoc}
060     * @throws UndefinedItemPathException if the given composite path is not defined by the model
061     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
062     */
063    public ModelAwareComposite getComposite(String compositePath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException;
064    
065    /**
066     * Retrieves the local composite at the given path
067     * @param compositePath path of the externalizable composite to retrieve
068     * @return the composite or <code>null</code> if not exists or is empty
069     * @throws IllegalArgumentException if the given composite path is null or empty
070     * @throws BadItemTypeException if the stored value at the given path is not a composite
071     * @throws UndefinedItemPathException if the given composite path is not defined by the model
072     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
073     */
074    public ModelAwareComposite getLocalComposite(String compositePath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException;
075    
076    /**
077     * Retrieves the external composite at the given path
078     * @param compositePath path of the externalizable composite to retrieve
079     * @return the composite or <code>null</code> if not exists or is empty
080     * @throws IllegalArgumentException if the given composite path is null or empty
081     * @throws BadItemTypeException if the stored value at the given path is not a composite
082     * @throws UndefinedItemPathException if the given composite path is not defined by the model
083     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
084     */
085    public ModelAwareComposite getExternalComposite(String compositePath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException;
086    
087    /**
088     * Retrieves the repeater at the given path
089     * @param repeaterPath path of the repeater to retrieve
090     * @return the repeater or <code>null</code> if not exists or is empty
091     * @throws IllegalArgumentException if the given repeater path is null or empty
092     * @throws BadItemTypeException if the stored value at the given path is not a repeater
093     * @throws UndefinedItemPathException if the given repeater path is not defined by the model
094     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
095     */
096    public ModelAwareRepeater getRepeater(String repeaterPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException;
097    
098    /**
099     * Retrieves the local repeater at the given path
100     * @param repeaterPath path of the externalizable repeater to retrieve
101     * @return the repeater or <code>null</code> if not exists or is empty
102     * @throws IllegalArgumentException if the given repeater path is null or empty
103     * @throws BadItemTypeException if the stored value at the given path is not a repeater
104     * @throws UndefinedItemPathException if the given repeater path is not defined by the model
105     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
106     */
107    public ModelAwareRepeater getLocalRepeater(String repeaterPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException;
108    
109    /**
110     * Retrieves the external repeater at the given path
111     * @param repeaterPath path of the externalizable repeater to retrieve
112     * @return the repeater or <code>null</code> if not exists or is empty
113     * @throws IllegalArgumentException if the given repeater path is null or empty
114     * @throws BadItemTypeException if the stored value at the given path is not a repeater
115     * @throws UndefinedItemPathException if the given repeater path is not defined by the model
116     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
117     */
118    public ModelAwareRepeater getExternalRepeater(String repeaterPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException;
119    
120    /**
121     * {@inheritDoc}
122     * @return <code>true</code> if the data at the given path is defined by the model, if there is a non empty value for the data and if the type of this value matches the type of the definition. <code>false</code> otherwise
123     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
124     */
125    @Override
126    public boolean hasValue(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException;
127    
128    /**
129     * Checks if there is a non empty local value for the data at the given path
130     * @param dataPath path of the externalizable data
131     * @return <code>true</code> if the data at the given path is defined by the model, if there is a non empty local value for the data and if the type of this value matches the type of the definition. <code>false</code> otherwise
132     * @throws IllegalArgumentException if the given data path is null or empty
133     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
134     */
135    public boolean hasLocalValue(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException;
136    
137    /**
138     * Checks if there is a non empty external value for the data at the given path
139     * @param dataPath path of the externalizable data
140     * @return <code>true</code> if the data at the given path is defined by the model, if there is a non empty external value for the data and if the type of this value matches the type of the definition. <code>false</code> otherwise
141     * @throws IllegalArgumentException if the given data path is null or empty
142     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
143     */
144    public boolean hasExternalValue(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException;
145    
146    /**
147     * {@inheritDoc}
148     * @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
149     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
150     */
151    @Override
152    public boolean hasValueOrEmpty(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException;
153    
154    /**
155     * Checks if there is a local value for the data at the given path
156     * @param dataPath path of the externalizable data
157     * @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
158     * @throws IllegalArgumentException if the given data path is null or empty
159     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
160     */
161    public boolean hasLocalValueOrEmpty(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException;
162    
163    /**
164     * Checks if there is an external value for the data at the given path
165     * @param dataPath path of the externalizable data
166     * @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
167     * @throws IllegalArgumentException if the given data path is null or empty
168     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
169     */
170    public boolean hasExternalValueOrEmpty(String dataPath) throws IllegalArgumentException, BadDataPathCardinalityException;
171    
172    /**
173     * Checks if there is are comments on the data with the given name
174     * @param dataName name of the data
175     * @return <code>true</code> if there are comments on the data, <code>false</code> otherwise
176     * @throws IllegalArgumentException if the given data name is null or empty
177     * @throws UndefinedItemPathException if the given data name is not defined by the model
178     */
179    public boolean hasComments(String dataName) throws IllegalArgumentException, UndefinedItemPathException;
180    
181    /**
182     * {@inheritDoc}
183     * @return the names of the data contained by this data holder and that are defined by the model
184     */
185    @Override
186    public Collection<String> getDataNames();
187    
188    /**
189     * Retrieves the value of the data at the given path
190     * @param <T> type of the value to retrieve
191     * @param dataPath path of the data
192     * @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.
193     * @throws IllegalArgumentException if the given data path is null or empty
194     * @throws UndefinedItemPathException if the given data path is not defined by the model
195     * @throws BadItemTypeException if the type defined by the model doesn't match the type of the stored value
196     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
197     */
198    public default <T extends Object> T getValue(String dataPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException
199    {
200        return getValue(dataPath, false);
201    }
202    
203    /**
204     * Retrieves the value of the data at the given path
205     * @param <T> type of the value to retrieve
206     * @param dataPath path of the data
207     * @param allowMultiValuedPathSegments <code>true</code> to allow multi-valued segments in the path (not necessarily at the last segment), <code>false</code> otherwise.
208     *      If <code>true</code>, if there is no indicated entry for a repeater, the values of all the entries are retrieved
209     *      If <code>true</code> and if there are multiple values, all data are retrieved in one array
210     * @return the value of the data or <code>null</code> if allowMultiValuedPathSegments 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.
211     * @throws IllegalArgumentException if the given data path is null or empty
212     * @throws UndefinedItemPathException if the given data path is not defined by the model
213     * @throws BadItemTypeException if the type defined by the model doesn't match the type of the stored value
214     * @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
215     */
216    public <T extends Object> T getValue(String dataPath, boolean allowMultiValuedPathSegments) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException;
217    
218    /**
219     * Retrieves the value of the data at the given path, or the default value
220     * The returned value is one of those ones, in the order:
221     * <ol>
222     * <li>The value of the data if exists and is not empty</li>
223     * <li>The default value from the model if useDefaultFromModel is <code>true</code> and there is a default value defined by the model</li>
224     * <li>The given default value</li>
225     * </ol>
226     * @param <T> type of the value to retrieve
227     * @param dataPath path of the data
228     * @param useDefaultFromModel true to use the default value from the model, false to use the given default value
229     * @param defaultValue default value used if value is null and useDefaultFromModel is false, or if there is no default value on model
230     * @return the value of the data at the given path
231     * @throws IllegalArgumentException if the given data path is null or empty
232     * @throws UndefinedItemPathException if the given data path is not defined by the model
233     * @throws BadItemTypeException if the type defined by the model doesn't match the type of the stored value
234     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
235     */
236    public <T extends Object> T getValue(String dataPath, boolean useDefaultFromModel, T defaultValue) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException;
237    
238    /**
239     * Retrieves the local value of the data at the given path
240     * @param <T> type of the value to retrieve
241     * @param dataPath path of the externalizable data
242     * @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.
243     * @throws IllegalArgumentException if the given data path is null or empty
244     * @throws UndefinedItemPathException if the given data path is not defined by the model
245     * @throws BadItemTypeException if the type defined by the model doesn't match the type of the stored value
246     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
247     */
248    public <T extends Object> T getLocalValue(String dataPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException;
249    
250    /**
251     * Retrieves the external value of the data at the given path
252     * @param <T> type of the value to retrieve
253     * @param dataPath path of the externalizable data
254     * @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.
255     * @throws IllegalArgumentException if the given data path is null or empty
256     * @throws UndefinedItemPathException if the given data path is not defined by the model
257     * @throws BadItemTypeException if the type defined by the model doesn't match the type of the stored value
258     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
259     */
260    public <T extends Object> T getExternalValue(String dataPath) throws IllegalArgumentException, UndefinedItemPathException, BadItemTypeException, BadDataPathCardinalityException;
261    
262    /**
263     * Retrieves the status of the externalizable data at the given path
264     * Warning: This method won't check that your data is externalizable. But there is no sense to call it with a non externalizable data
265     * @param dataPath path of the externalizable data
266     * @return the status of the externalizable data at the given path
267     * @throws IllegalArgumentException if the given data path is null or empty
268     * @throws UndefinedItemPathException if the given data path is not defined by the model
269     * @throws BadDataPathCardinalityException if the definition of a part of the data path is multiple. Only the last part can be multiple
270     */
271    public ExternalizableDataStatus getStatus(String dataPath) throws IllegalArgumentException, UndefinedItemPathException, BadDataPathCardinalityException;
272    
273    /**
274     * Retrieve the comments of the data with the given name
275     * @param dataName name of the data
276     * @return the comments of the data
277     * @throws IllegalArgumentException if the given data name is null or empty
278     * @throws UndefinedItemPathException if the given data name is not defined by the model
279     */
280    public List<DataComment> getComments(String dataName) throws IllegalArgumentException, UndefinedItemPathException;
281    
282    /**
283     * Checks if the definition of the element at the given path is multiple
284     * @param path path of the element. No matter if it is a definition or data path (with repeater entry positions)
285     * @return <code>true</code> if the element is multiple, <code>false</code> otherwise
286     * @throws IllegalArgumentException if the given path is null or empty
287     * @throws UndefinedItemPathException if the given path is not defined by the model
288     */
289    public default boolean isMultiple(String path) throws IllegalArgumentException, UndefinedItemPathException
290    {
291        ModelItem item = getDefinition(path);
292        if (item instanceof ElementDefinition)
293        {
294            return ((ElementDefinition) item).isMultiple();
295        }
296        else if (item instanceof RepeaterDefinition)
297        {
298            // If the given path represents a repeater , but with no specified entry, consider the data as multiple
299            return !DataHolderHelper.isRepeaterEntryPath(path);
300        }
301        else
302        {
303            // Composites are not multiples
304            return false;
305        }
306    }
307    
308    /**
309     * Retrieves the type of the data at the given path
310     * @param <X> type of the item type
311     * @param path path of the data. No matter if it is a definition or data path (with repeater entry positions)
312     * @return the type of the data
313     * @throws IllegalArgumentException if the given data path is null or empty
314     * @throws UndefinedItemPathException if the given data path is not defined by the model
315     */
316    @SuppressWarnings("unchecked")
317    public default <X extends ModelItemType> X getType(String path) throws IllegalArgumentException, UndefinedItemPathException
318    {
319        return (X) getDefinition(path).getType();
320    }
321    
322    /**
323     * Retrieves the data holder's model
324     * @return the data holder's model
325     */
326    public Collection<? extends ModelItemContainer> getModel();
327    
328    /**
329     * Retrieves the definition of the data at the given path
330     * @param path path of the data. No matter if it is a definition or data path (with repeater entry positions)
331     * @return the definition of the data
332     * @throws IllegalArgumentException if the given path is null or empty
333     * @throws UndefinedItemPathException if the given path is not defined by the model
334     */
335    public default ModelItem getDefinition(String path) throws IllegalArgumentException, UndefinedItemPathException
336    {
337        return ModelHelper.getModelItem(path, getModel());
338    }
339    
340    /**
341     * Checks if there is a definition at the given path
342     * @param path path of the data. No matter if it is a definition or data path (with repeater entry positions)
343     * @return <code>true</code> if there is definition at the given path, <code>false</code> otherwise
344     * @throws IllegalArgumentException if the given path is null or empty
345     */
346    public default boolean hasDefinition(String path) throws IllegalArgumentException
347    {
348        try
349        {
350            getDefinition(path);
351            return true;
352        }
353        catch (UndefinedItemPathException e)
354        {
355            return false;
356        }
357    }
358    
359    /**
360     * Generates SAX events for the data in the model of the current {@link DataHolder}
361     * @param contentHandler the {@link ContentHandler} that will receive the SAX events
362     * @throws SAXException if an error occurs during the SAX events generation
363     * @throws BadItemTypeException if the saxed value's type does not matches the stored data
364     */
365    public default void dataToSAX(ContentHandler contentHandler) throws SAXException, BadItemTypeException
366    {
367        dataToSAX(contentHandler, DataContext.newInstance());
368    }
369    
370    /**
371     * Generates SAX events for the data in the model of the current {@link DataHolder}
372     * @param contentHandler the {@link ContentHandler} that will receive the SAX events
373     * @param context The context of the data to SAX
374     * @throws SAXException if an error occurs during the SAX events generation
375     * @throws BadItemTypeException if the saxed value's type does not matches the stored data
376     */
377    public default void dataToSAX(ContentHandler contentHandler, DataContext context) throws SAXException, BadItemTypeException
378    {
379        ViewItemAccessor viewItemAccessor = ViewHelper.createViewItemAccessor(getModel());
380        dataToSAX(contentHandler, viewItemAccessor, context);
381    }
382    
383    /**
384     * Generates SAX events for the data in the given view in the current {@link DataHolder}
385     * @param contentHandler the {@link ContentHandler} that will receive the SAX events
386     * @param viewItemAccessor the {@link ViewItemAccessor} referencing the items for which generate SAX events
387     * @throws SAXException if an error occurs during the SAX events generation
388     * @throws BadItemTypeException if the saxed value's type does not matches the stored data
389     */
390    public default void dataToSAX(ContentHandler contentHandler, ViewItemAccessor viewItemAccessor) throws SAXException, BadItemTypeException
391    {
392        dataToSAX(contentHandler, viewItemAccessor, DataContext.newInstance());
393    }
394    
395    /**
396     * Generates SAX events for the data in the given view in the current {@link DataHolder}
397     * @param contentHandler the {@link ContentHandler} that will receive the SAX events
398     * @param viewItemAccessor the {@link ViewItemAccessor} referencing the items for which generate SAX events
399     * @param context The context of the data to SAX
400     * @throws SAXException if an error occurs during the SAX events generation
401     * @throws BadItemTypeException if the saxed value's type does not matches the stored data
402     */
403    public void dataToSAX(ContentHandler contentHandler, ViewItemAccessor viewItemAccessor, DataContext context) throws SAXException, BadItemTypeException;
404    
405    /**
406     * Generates SAX events for the data in the given view in edition mode in the current {@link DataHolder}
407     * @param contentHandler the {@link ContentHandler} that will receive the SAX events
408     * @param viewItemAccessor the {@link ViewItemAccessor} referencing the items for which generate SAX events
409     * @param context The context of the data to SAX
410     * @throws SAXException if an error occurs during the SAX events generation
411     * @throws BadItemTypeException if the saxed value's type does not matches the stored data
412     */
413    public void dataToSAXForEdition(ContentHandler contentHandler, ViewItemAccessor viewItemAccessor, DataContext context) throws SAXException, BadItemTypeException;
414    
415    /**
416     * Convert the data in the model of the current {@link DataHolder}
417     * @return The data of the current {@link DataHolder} as JSON
418     * @throws BadItemTypeException if the value's type does not matches the stored data
419     */
420    public default Map<String, Object> dataToJSON() throws BadItemTypeException
421    {
422        return dataToJSON(DataContext.newInstance());
423    }
424    
425    /**
426     * Convert the data in the model of the current {@link DataHolder}
427     * @param context The context of the data to convert
428     * @return The data of the current {@link DataHolder} as JSON
429     * @throws BadItemTypeException if the value's type does not matches the stored data
430     */
431    public default Map<String, Object> dataToJSON(DataContext context) throws BadItemTypeException
432    {
433        ViewItemAccessor viewItemAccessor = ViewHelper.createViewItemAccessor(getModel());
434        return dataToJSON(viewItemAccessor, context);
435    }
436    
437    /**
438     * Convert the data in the given view of the current {@link DataHolder}
439     * @param viewItemAccessor the {@link ViewItemAccessor} referencing the items to convert
440     * @return The data of the given view as JSON
441     * @throws BadItemTypeException if the value's type does not matches the stored data
442     */
443    public default Map<String, Object> dataToJSON(ViewItemAccessor viewItemAccessor) throws BadItemTypeException
444    {
445        return dataToJSON(viewItemAccessor, DataContext.newInstance());
446    }
447    
448    /**
449     * Convert the data in the given view of the current {@link DataHolder}
450     * @param viewItemAccessor the {@link ViewItemAccessor} referencing the items to convert
451     * @param context The context of the data to convert
452     * @return The data of the given view as JSON
453     * @throws BadItemTypeException if the value's type does not matches the stored data
454     */
455    public Map<String, Object> dataToJSON(ViewItemAccessor viewItemAccessor, DataContext context) throws BadItemTypeException;
456    
457    /**
458     * Convert the data in the given view in edition mode in the current {@link DataHolder}
459     * @param viewItemAccessor the {@link ViewItemAccessor} referencing the items to convert
460     * @param context The context of the data to convert
461     * @return The data of the given view as JSON
462     * @throws BadItemTypeException if the value's type does not matches the stored data
463     */
464    public Map<String, Object> dataToJSONForEdition(ViewItemAccessor viewItemAccessor, DataContext context) throws BadItemTypeException;
465    
466    /**
467     * Generates SAX events for the comments of the data in the given view in the current {@link DataHolder}
468     * @param contentHandler the {@link ContentHandler} that will receive the SAX events
469     * @param viewItemAccessor the {@link ViewItemAccessor} referencing the items for which generate SAX events
470     * @throws SAXException if an error occurs during the SAX events generation
471     */
472    public default void commentsToSAX(ContentHandler contentHandler, ViewItemAccessor viewItemAccessor) throws SAXException
473    {
474        DataHolderHelper.commentsToSAX(this, contentHandler, viewItemAccessor, StringUtils.EMPTY);
475    }
476    
477    /**
478     * Retrieves all data of this DataHolder as a typed-values Map.
479     * @return a Map containing all data.
480     */
481    public default Map<String, Object> dataToMap()
482    {
483        return dataToMap(DataContext.newInstance());
484    }
485    
486    /**
487     * Retrieves all data of this DataHolder as a typed-values Map.
488     * @param context The context of the data
489     * @return  a Map containing all data.
490     */
491    public default Map<String, Object> dataToMap(DataContext context)
492    {
493        ViewItemAccessor viewItemAccessor = ViewHelper.createViewItemAccessor(getModel());
494        return dataToMap(viewItemAccessor, context);
495    }
496    
497    /**
498     * Retrieves data of this DataHolder as a typed-values Map.
499     * @param viewItemAccessor the {@link ViewItemAccessor} referencing the items to include in the resulting Map
500     * @return a Map containing all data.
501     */
502    public default Map<String, Object> dataToMap(ViewItemAccessor viewItemAccessor)
503    {
504        return dataToMap(viewItemAccessor, DataContext.newInstance());
505    }
506    
507    /**
508     * Retrieves data of this DataHolder as a typed-values Map.
509     * @param viewItemAccessor the {@link ViewItemAccessor} referencing the items to include in the resulting Map
510     * @param context The context of the data
511     * @return a Map containing all data.
512     */
513    public Map<String, Object> dataToMap(ViewItemAccessor viewItemAccessor, DataContext context);
514    
515    /**
516     * Check if there are differences between the given values and the current ones
517     * @param viewItemAccessor The {@link ViewItemAccessor} for all items to check
518     * @param values the values to check
519     * @return <code>true</code> if there are differences, <code>false</code> otherwise
520     * @throws UndefinedItemPathException if a key in the given Map refers to a data that is not defined by the model
521     * @throws BadItemTypeException if the type defined by the model of one of the Map's key doesn't match the corresponding value
522     */
523    public boolean hasDifferences(ViewItemAccessor viewItemAccessor, Map<String, Object> values) throws UndefinedItemPathException, BadItemTypeException;
524    
525    /**
526     * Check if there are differences between the given values and the current ones
527     * @param viewItemAccessor The {@link ViewItemAccessor} for all items to check
528     * @param values the values to check
529     * @param context the context of the synchronization
530     * @return <code>true</code> if there are differences, <code>false</code> otherwise
531     * @throws UndefinedItemPathException if a key in the given Map refers to a data that is not defined by the model
532     * @throws BadItemTypeException if the type defined by the model of one of the Map's key doesn't match the corresponding value
533     */
534    public boolean hasDifferences(ViewItemAccessor viewItemAccessor, Map<String, Object> values, SynchronizationContext context) throws UndefinedItemPathException, BadItemTypeException;
535
536    /**
537     * Get the collection of model items where there are differences between the given values and the current ones
538     * @param viewItemAccessor The {@link ViewItemAccessor} for all items to check
539     * @param values the values to check
540     * @return a collection of model items with differences
541     * @throws UndefinedItemPathException if a key in the given Map refers to a data that is not defined by the model
542     * @throws BadItemTypeException if the type defined by the model of one of the Map's key doesn't match the corresponding value
543     */
544    public Collection<ModelItem> getDifferences(ViewItemAccessor viewItemAccessor, Map<String, Object> values) throws UndefinedItemPathException, BadItemTypeException;
545
546    /**
547     * Get the collection of model items where there are differences between the given values and the current ones
548     * @param viewItemAccessor The {@link ViewItemAccessor} for all items to check
549     * @param values the values to check
550     * @param context the context of the synchronization
551     * @return a collection of model items with differences
552     * @throws UndefinedItemPathException if a key in the given Map refers to a data that is not defined by the model
553     * @throws BadItemTypeException if the type defined by the model of one of the Map's key doesn't match the corresponding value
554     */
555    public Collection<ModelItem> getDifferences(ViewItemAccessor viewItemAccessor, Map<String, Object> values, SynchronizationContext context) throws UndefinedItemPathException, BadItemTypeException;
556    
557    @Override
558    public Optional<? extends ModelAwareDataHolder> getParentDataHolder();
559    
560    @Override
561    public ModelAwareDataHolder getRootDataHolder();
562}