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