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