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