001/*
002 *  Copyright 2020 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.model;
017
018import java.util.HashSet;
019import java.util.Optional;
020import java.util.Set;
021
022import org.ametys.plugins.repository.AmetysObject;
023import org.ametys.plugins.repository.data.ametysobject.DataAwareAmetysObject;
024import org.ametys.runtime.model.ModelHelper;
025import org.ametys.runtime.model.type.DataContext;
026
027/**
028 * Object that gives some context for repository data manipulation
029 */
030public class RepositoryDataContext extends DataContext
031{
032    private Optional<? extends DataAwareAmetysObject> _object = Optional.empty();
033    private Optional<? extends DataAwareAmetysObject> _rootObject = Optional.empty();
034    
035    private Set<String> _externalizableData = new HashSet<>();
036    private boolean _copyExternalMetadata;
037    
038    /**
039     * Creates a new instance of a {@link RepositoryDataContext}
040     */
041    protected RepositoryDataContext()
042    {
043        // Empty constructor
044    }
045
046    /**
047     * Creates a new instance of a {@link RepositoryDataContext} from another {@link DataContext}
048     * @param context the data context to copy
049     */
050    protected RepositoryDataContext(DataContext context)
051    {
052        super(context);
053        if (context instanceof RepositoryDataContext repositoryContext)
054        {
055            withObject(repositoryContext.getObject().orElse(null));
056            _withRootObject(repositoryContext._getRootObject().orElse(null));
057            
058            withExternalizableData(repositoryContext.getExternalizableData());
059            withExternalMetadataInCopy(repositoryContext.copyExternalMetadata());
060        }
061    }
062    
063    /**
064     * Creates a new instance of a {@link RepositoryDataContext}
065     * @return the created instance
066     */
067    public static RepositoryDataContext newInstance()
068    {
069        return new RepositoryDataContext();
070    }
071    
072    /**
073     * Creates a new instance of a {@link RepositoryDataContext} from another {@link DataContext}.
074     * It can be the same implementation or another one, but it will be casted to the current implementation.
075     * @param context the data context to copy
076     * @return the created instance
077     */
078    public static RepositoryDataContext newInstance(DataContext context)
079    {
080        return new RepositoryDataContext(context);
081    }
082    
083    /**
084     * Creates a new instance of a {@link RepositoryDataContext}, with the current context values
085     * @return the created instance
086     */
087    @Override
088    public RepositoryDataContext cloneContext()
089    {
090        return newInstance(this);
091    }
092    
093    /**
094     * Retrieves the object from which the data path is computed
095     * @param <T> Type of the object
096     * @return the object
097     */
098    @SuppressWarnings("unchecked")
099    public <T extends DataAwareAmetysObject> Optional<T> getObject()
100    {
101        return (Optional<T>) _object;
102    }
103    
104    /**
105     * Retrieves the identifier of the object
106     * @return the object's identifier
107     */
108    public Optional<String> getObjectId()
109    {
110        return _object.map(AmetysObject::getId);
111    }
112    
113    /**
114     * Set the object from which the data path is computed
115     * @param <T> the type of the retrieved {@link DataContext}
116     * @param object the object to set
117     * @return the current {@link DataContext}
118     */
119    @SuppressWarnings("unchecked")
120    public <T extends RepositoryDataContext> T withObject(DataAwareAmetysObject object)
121    {
122        _object = Optional.ofNullable(object);
123        
124        if (_rootObject.isEmpty())
125        {
126            _withRootObject(object);
127        }
128
129        return (T) this;
130    }
131    
132    /**
133     * Retrieves the object from which the full data path is computed
134     * @param <T> Type of the root object
135     * @return the root object
136     */
137    @SuppressWarnings("unchecked")
138    protected <T extends DataAwareAmetysObject> Optional<T> _getRootObject()
139    {
140        return (Optional<T>) _rootObject;
141    }
142    
143    /**
144     * Retrieves the identifier of the root object
145     * @return the root object's identifier
146     */
147    public Optional<String> getRootObjectId()
148    {
149        return _rootObject.map(AmetysObject::getId);
150    }
151    
152    /**
153     * Set the object from which the full data path is computed
154     * @param <T> the type of the retrieved {@link DataContext}
155     * @param rootObject the root object to set
156     * @return the current {@link DataContext}
157     */
158    @SuppressWarnings("unchecked")
159    protected <T extends RepositoryDataContext> T _withRootObject(DataAwareAmetysObject rootObject)
160    {
161        _rootObject = Optional.ofNullable(rootObject);
162        return (T) this;
163    }
164    
165    /**
166     * Retrieves the externalizable data
167     * @return the externalizable data
168     */
169    public Set<String> getExternalizableData()
170    {
171        return _externalizableData;
172    }
173    
174    /**
175     * Check if the current data is externalizable
176     * @return <code>true</code> if the data is externalizable, <code>false</code> otherwise
177     */
178    public boolean isDataExternalizable()
179    {
180        String dataPath = getDataPath();
181        String definitionPath = ModelHelper.getDefinitionPathFromDataPath(dataPath);
182        return _externalizableData.contains(definitionPath);
183    }
184    
185    /**
186     * Sets the externalizable data
187     * @param <T> the type of the retrieved {@link DataContext}
188     * @param externalizableData the externalizable data to set
189     * @return the current {@link RepositoryDataContext}
190     */
191    @SuppressWarnings("unchecked")
192    public <T extends RepositoryDataContext> T withExternalizableData(Set<String> externalizableData)
193    {
194        _externalizableData = externalizableData;
195        return (T) this;
196    }
197    
198    /**
199     * Check if the external metadata (alternative and status) should be copied
200     * @return <code>true</code> if the external metadata should be copied, <code>false</code> otherwise
201     */
202    public boolean copyExternalMetadata()
203    {
204        return _copyExternalMetadata;
205    }
206    
207    /**
208     * Set to <code>true</code> to copy the external metadata (alternative and status) (default to <code>false</code>)
209     * @param <T> the type of the retrieved {@link DataContext}
210     * @param copyExternalMetadata <code>true</code> to copy the external metadata, <code>false</code> otherwise
211     * @return the current {@link RepositoryDataContext}
212     */
213    @SuppressWarnings("unchecked")
214    public <T extends RepositoryDataContext> T withExternalMetadataInCopy(boolean copyExternalMetadata)
215    {
216        _copyExternalMetadata = copyExternalMetadata;
217        return (T) this;
218    }
219}