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