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.runtime.model.type; 017 018import java.util.ArrayList; 019import java.util.List; 020import java.util.Locale; 021import java.util.Optional; 022 023import org.apache.commons.lang3.StringUtils; 024 025import org.ametys.runtime.model.ModelItem; 026 027/** 028 * Object that gives some context for data manipulation 029 */ 030public class DataContext 031{ 032 private Locale _locale; 033 private List<String> _fullDataPath = new ArrayList<>(); 034 private List<String> _dataPath = new ArrayList<>(); 035 private Optional<String> _objectId = Optional.empty(); 036 private Optional<String> _rootObjectId = Optional.empty(); 037 private boolean _renderEmptyValues = true; 038 private Optional<ModelItem> _modelItem = Optional.empty(); 039 040 /** 041 * Creates a new instance of a {@link DataContext} 042 */ 043 protected DataContext() 044 { 045 // Empty private constructor 046 } 047 048 /** 049 * Creates a new instance of a {@link DataContext} 050 * @return the created instance 051 */ 052 public static DataContext newInstance() 053 { 054 return new DataContext(); 055 } 056 057 /** 058 * Creates a new instance of a {@link DataContext}, with the current context values 059 * @return the created instance 060 */ 061 public DataContext cloneContext() 062 { 063 DataContext clone = new DataContext(); 064 _cloneContextData(clone); 065 return clone; 066 } 067 068 /** 069 * Clone the data of the current context in the given one 070 * @param context the clone 071 */ 072 protected void _cloneContextData(DataContext context) 073 { 074 context.withLocale(getLocale()) 075 .withDataPath(getDataPath()) 076 .withFullDataPath(getFullDataPath()) 077 .withObjectId(getObjectId().orElse(null)) 078 .withRootObjectId(getRootObjectId().orElse(null)) 079 .withEmptyValues(renderEmptyValues()) 080 .withModelItem(getModelItem().orElse(null)); 081 } 082 083 /** 084 * Retrieves the locale to use for localized data 085 * @return the locale, or null if no local has been set 086 */ 087 public Locale getLocale() 088 { 089 return _locale; 090 } 091 092 /** 093 * Sets the locale to use for localized data. 094 * Do not set {@link Locale} to use all existing ones. 095 * @param locale the locale to set 096 * @return the current {@link DataContext} 097 */ 098 public DataContext withLocale(Locale locale) 099 { 100 _locale = locale; 101 return this; 102 } 103 104 /** 105 * Retrieves the data path 106 * @return the dataPath 107 */ 108 public String getDataPath() 109 { 110 return StringUtils.join(_dataPath, ModelItem.ITEM_PATH_SEPARATOR); 111 } 112 113 /** 114 * Retrieves the last segment of the data path 115 * @return the last segment of the data path 116 */ 117 public String getDataPathLastSegment() 118 { 119 return _dataPath.get(_dataPath.size() - 1); 120 } 121 122 /** 123 * Sets the data path 124 * @param dataPath the data path to set 125 * @return the current {@link DataContext} 126 */ 127 public DataContext withDataPath(String dataPath) 128 { 129 _dataPath = new ArrayList<>(); 130 if (StringUtils.isNotEmpty(dataPath)) 131 { 132 _dataPath.add(dataPath); 133 _fullDataPath.add(dataPath); 134 } 135 return this; 136 } 137 138 /** 139 * Retrieves the full data path 140 * @return the fullDataPath 141 */ 142 public String getFullDataPath() 143 { 144 return StringUtils.join(_fullDataPath, ModelItem.ITEM_PATH_SEPARATOR); 145 } 146 147 /** 148 * Sets the full data path 149 * @param fullDataPath the full data path to set 150 * @return the current {@link DataContext} 151 */ 152 public DataContext withFullDataPath(String fullDataPath) 153 { 154 _fullDataPath = new ArrayList<>(); 155 if (StringUtils.isNotEmpty(fullDataPath)) 156 { 157 _fullDataPath.add(fullDataPath); 158 } 159 return this; 160 } 161 162 /** 163 * Add a segment to the data path 164 * @param segment the segment to add to the data path 165 * @return the current {@link DataContext} 166 */ 167 public DataContext addSegmentToDataPath(String segment) 168 { 169 _dataPath.add(segment); 170 _fullDataPath.add(segment); 171 return this; 172 } 173 174 /** 175 * Add a suffix to the last segment of the data path 176 * @param suffix the suffix to add to the last segment 177 * @return the current {@link DataContext} 178 */ 179 public DataContext addSuffixToLastSegment(String suffix) 180 { 181 int segmentIndex = _dataPath.size() - 1; 182 _dataPath.set(segmentIndex, _dataPath.get(segmentIndex) + suffix); 183 184 segmentIndex = _fullDataPath.size() - 1; 185 _fullDataPath.set(segmentIndex, _fullDataPath.get(segmentIndex) + suffix); 186 187 return this; 188 } 189 190 /** 191 * Retrieves the identifier of the object from which the data path is computed 192 * @return the object identifier 193 */ 194 public Optional<String> getObjectId() 195 { 196 return _objectId; 197 } 198 199 /** 200 * Set the identifier of the object from which the data path is computed 201 * @param objectId the object identifier to set 202 * @return the current {@link DataContext} 203 */ 204 public DataContext withObjectId(String objectId) 205 { 206 _objectId = Optional.ofNullable(objectId) 207 .filter(StringUtils::isNotEmpty); 208 if (_rootObjectId.isEmpty()) 209 { 210 _rootObjectId = _objectId; 211 } 212 return this; 213 } 214 215 /** 216 * Retrieves the identifier of the object from which the full data path is computed 217 * @return the root object identifier 218 */ 219 public Optional<String> getRootObjectId() 220 { 221 return _rootObjectId; 222 } 223 224 /** 225 * Set the identifier of the object from which the full data path is computed 226 * @param rootObjectId the root object identifier to set 227 * @return the current {@link DataContext} 228 */ 229 public DataContext withRootObjectId(String rootObjectId) 230 { 231 _rootObjectId = Optional.ofNullable(rootObjectId) 232 .filter(StringUtils::isNotEmpty); 233 return this; 234 } 235 236 /** 237 * Determines if the empty values have to be rendered 238 * @return <code>true</code> if empty values must be rendered (default), <code>false</code> otherwise 239 */ 240 public boolean renderEmptyValues() 241 { 242 return _renderEmptyValues; 243 } 244 245 /** 246 * Set to <code>false</code> to not render empty values (default to <code>true</code>) 247 * @param renderEmptyValues <code>true</code> to render the empty values, <code>false</code> otherwise 248 * @return the current {@link DataContext} 249 */ 250 public DataContext withEmptyValues(boolean renderEmptyValues) 251 { 252 _renderEmptyValues = renderEmptyValues; 253 return this; 254 } 255 256 /** 257 * Retrieves the model item 258 * @return the model item 259 */ 260 public Optional<ModelItem> getModelItem() 261 { 262 return _modelItem; 263 } 264 265 /** 266 * Sets the model item 267 * @param modelItem the model item to set 268 * @return the current {@link DataContext} 269 */ 270 public DataContext withModelItem(ModelItem modelItem) 271 { 272 _modelItem = Optional.ofNullable(modelItem); 273 return this; 274 } 275}