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