001// -------------------------------------------------------------------------------- 002// Copyright 2002-2024 Echo Three, LLC 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// -------------------------------------------------------------------------------- 016 017package com.echothree.util.server.transfer; 018 019import com.echothree.model.control.comment.common.transfer.CommentListWrapper; 020import com.echothree.model.control.comment.server.control.CommentControl; 021import com.echothree.model.control.core.common.transfer.EntityAliasTypeTransfer; 022import com.echothree.model.control.core.common.transfer.EntityAttributeGroupTransfer; 023import com.echothree.model.control.core.server.control.CoreControl; 024import com.echothree.model.control.rating.common.transfer.RatingListWrapper; 025import com.echothree.model.control.rating.server.control.RatingControl; 026import com.echothree.model.control.tag.common.transfer.TagScopeTransfer; 027import com.echothree.model.control.tag.server.control.TagControl; 028import com.echothree.model.control.uom.server.control.UomControl; 029import com.echothree.model.control.user.server.control.UserControl; 030import com.echothree.model.control.workeffort.common.transfer.WorkEffortTransfer; 031import com.echothree.model.control.workeffort.server.control.WorkEffortControl; 032import com.echothree.model.data.accounting.server.entity.Currency; 033import com.echothree.model.data.comment.server.entity.CommentType; 034import com.echothree.model.data.core.server.entity.EntityInstance; 035import com.echothree.model.data.party.common.pk.PartyPK; 036import com.echothree.model.data.party.server.entity.DateTimeFormat; 037import com.echothree.model.data.party.server.entity.Language; 038import com.echothree.model.data.party.server.entity.Party; 039import com.echothree.model.data.party.server.entity.TimeZone; 040import com.echothree.model.data.rating.server.entity.RatingType; 041import com.echothree.model.data.tag.server.entity.TagScope; 042import com.echothree.model.data.uom.server.entity.UnitOfMeasureKind; 043import com.echothree.model.data.user.server.entity.UserVisit; 044import com.echothree.util.common.exception.TransferOptionDependencyException; 045import com.echothree.util.common.string.Inet4AddressUtils; 046import com.echothree.util.common.transfer.BaseOptions; 047import com.echothree.util.common.transfer.BaseTransfer; 048import com.echothree.util.common.transfer.ListWrapper; 049import com.echothree.util.common.transfer.MapWrapper; 050import com.echothree.util.server.persistence.BaseEntity; 051import com.echothree.util.server.persistence.Session; 052import com.echothree.util.server.persistence.ThreadSession; 053import com.echothree.util.server.string.DateUtils; 054import com.echothree.util.server.string.PercentUtils; 055import com.echothree.util.server.string.UnitOfMeasureUtils; 056import java.util.HashMap; 057import java.util.List; 058import java.util.Map; 059import org.apache.commons.logging.Log; 060import org.apache.commons.logging.LogFactory; 061 062public abstract class BaseTransferCache<K extends BaseEntity, V extends BaseTransfer> { 063 064 private Log log = null; 065 066 protected UserVisit userVisit; 067 protected Session session; 068 protected Map<K, V> transferCache; 069 070 private UomControl uomControl; 071 private UserControl userControl; 072 private Party party; 073 private Language language; 074 private Currency currency; 075 private TimeZone timeZone; 076 private DateTimeFormat dateTimeFormat; 077 078 boolean includeEntityInstance; 079 boolean includeEntityAppearance; 080 boolean includeEntityVisit; 081 boolean includeNames; 082 boolean includeKey; 083 boolean includeGuid; 084 boolean includeUlid; 085 boolean includeEntityAliasTypes; 086 boolean includeEntityAttributeGroups; 087 boolean includeTagScopes; 088 089 /** Creates a new instance of BaseTransferCache */ 090 protected BaseTransferCache(UserVisit userVisit) { 091 this.userVisit = userVisit; 092 093 session = ThreadSession.currentSession(); 094 transferCache = new HashMap<>(); 095 096 var options = session.getOptions(); 097 if(options != null) { 098 includeEntityAliasTypes = options.contains(BaseOptions.BaseIncludeEntityAliasTypes); 099 includeEntityAttributeGroups = options.contains(BaseOptions.BaseIncludeEntityAttributeGroups); 100 includeTagScopes = options.contains(BaseOptions.BaseIncludeTagScopes); 101 } 102 } 103 104 protected Log getLog() { 105 if(log == null) { 106 log = LogFactory.getLog(this.getClass()); 107 } 108 109 return log; 110 } 111 112 protected void put(final K key, final V value, final EntityInstance entityInstance) { 113 transferCache.put(key, value); 114 115 if(includeEntityInstance) { 116 setupEntityInstance(key, entityInstance, value); 117 } 118 } 119 120 protected void put(final K key, final V value) { 121 put(key, value, null); 122 } 123 124 protected V get(Object key) { 125 return transferCache.get(key); 126 } 127 128 protected UomControl getUomControl() { 129 if(uomControl == null) { 130 uomControl = Session.getModelController(UomControl.class); 131 } 132 133 return uomControl; 134 } 135 136 protected UserControl getUserControl() { 137 if(userControl == null) { 138 userControl = Session.getModelController(UserControl.class); 139 } 140 141 return userControl; 142 } 143 144 protected PartyPK getPartyPK() { 145 if(party == null) { 146 getParty(); 147 } 148 149 return party == null? null: party.getPrimaryKey(); 150 } 151 152 protected Party getParty() { 153 if(party == null) { 154 party = getUserControl().getPartyFromUserVisit(userVisit); 155 } 156 157 return party; 158 } 159 160 protected Language getLanguage() { 161 if(language == null) { 162 language = getUserControl().getPreferredLanguageFromUserVisit(userVisit); 163 } 164 165 return language; 166 } 167 168 protected Currency getCurrency() { 169 if(currency == null) { 170 currency = getUserControl().getPreferredCurrencyFromUserVisit(userVisit); 171 } 172 173 return currency; 174 } 175 176 protected TimeZone getTimeZone() { 177 if(timeZone == null) { 178 timeZone = getUserControl().getPreferredTimeZoneFromUserVisit(userVisit); 179 } 180 181 return timeZone; 182 } 183 184 protected DateTimeFormat getDateTimeFormat() { 185 if(dateTimeFormat == null) { 186 dateTimeFormat = getUserControl().getPreferredDateTimeFormatFromUserVisit(userVisit); 187 } 188 189 return dateTimeFormat; 190 } 191 192 protected String formatTypicalDateTime(Long time) { 193 return DateUtils.getInstance().formatTypicalDateTime(userVisit, time); 194 } 195 196 protected String formatFractionalPercent(Integer percent) { 197 return PercentUtils.getInstance().formatFractionalPercent(percent); 198 } 199 200 protected String formatInet4Address(Integer inet4Address) { 201 return Inet4AddressUtils.getInstance().formatInet4Address(inet4Address); 202 } 203 204 protected String formatUnitOfMeasure(UnitOfMeasureKind unitOfMeasureKind, Long measure) { 205 return UnitOfMeasureUtils.getInstance().formatUnitOfMeasure(userVisit, unitOfMeasureKind, measure); 206 } 207 208 /** 209 * Returns the includeEntityAliasTypes. 210 * @return the includeEntityAliasTypes 211 */ 212 protected boolean getIncludeEntityAliasTypes() { 213 return includeEntityAliasTypes; 214 } 215 216 /** 217 * Sets the includeEntityAliasTypes. 218 * @param includeEntityAliasTypes the includeEntityAliasTypes to set 219 */ 220 protected void setIncludeEntityAliasTypes(boolean includeEntityAliasTypes) { 221 this.includeEntityAliasTypes = includeEntityAliasTypes; 222 } 223 224 protected void setupEntityAliasTypes(CoreControl coreControl, EntityInstance entityInstance, V transfer) { 225 var entityAliasTypeTransfers = coreControl.getEntityAliasTypeTransfersByEntityType(userVisit, entityInstance.getEntityType(), entityInstance); 226 var mapWrapper = new MapWrapper<EntityAliasTypeTransfer>(entityAliasTypeTransfers.size()); 227 228 entityAliasTypeTransfers.forEach((entityAliasTypeTransfer) -> { 229 mapWrapper.put(entityAliasTypeTransfer.getEntityAliasTypeName(), entityAliasTypeTransfer); 230 }); 231 232 transfer.setEntityAliasTypes(mapWrapper); 233 } 234 235 /** 236 * Returns the includeEntityAttributeGroups. 237 * @return the includeEntityAttributeGroups 238 */ 239 protected boolean getIncludeEntityAttributeGroups() { 240 return includeEntityAttributeGroups; 241 } 242 243 /** 244 * Sets the includeEntityAttributeGroups. 245 * @param includeEntityAttributeGroups the includeEntityAttributeGroups to set 246 */ 247 protected void setIncludeEntityAttributeGroups(boolean includeEntityAttributeGroups) { 248 this.includeEntityAttributeGroups = includeEntityAttributeGroups; 249 } 250 251 protected void setupEntityAttributeGroups(CoreControl coreControl, EntityInstance entityInstance, V transfer) { 252 List<EntityAttributeGroupTransfer> entityAttributeGroupTransfers = coreControl.getEntityAttributeGroupTransfersByEntityType(userVisit, entityInstance.getEntityType(), entityInstance); 253 MapWrapper<EntityAttributeGroupTransfer> mapWrapper = new MapWrapper<>(entityAttributeGroupTransfers.size()); 254 255 entityAttributeGroupTransfers.forEach((entityAttributeGroupTransfer) -> { 256 mapWrapper.put(entityAttributeGroupTransfer.getEntityAttributeGroupName(), entityAttributeGroupTransfer); 257 }); 258 259 transfer.setEntityAttributeGroups(mapWrapper); 260 } 261 262 /** 263 * Returns the includeTagScopes. 264 * @return the includeTagScopes 265 */ 266 protected boolean getIncludeTagScopes() { 267 return includeTagScopes; 268 } 269 270 /** 271 * Sets the includeTagScopes. 272 * @param includeTagScopes the includeTagScopes to set 273 */ 274 protected void setIncludeTagScopes(boolean includeTagScopes) { 275 this.includeTagScopes = includeTagScopes; 276 } 277 278 protected void setupTagScopes(CoreControl coreControl, EntityInstance entityInstance, V transfer) { 279 TagControl tagControl = Session.getModelController(TagControl.class); 280 List<TagScope> tagScopes = tagControl.getTagScopesByEntityType(entityInstance.getEntityType()); 281 MapWrapper<TagScopeTransfer> mapWrapper = new MapWrapper<>(tagScopes.size()); 282 283 tagScopes.stream().map((tagScope) -> { 284 // We get a copy of the TagScopeTransfer since we'll be modifying a field on it. Because there may be multiple instances of the 285 // TransferObject that we're building at this point, they may each have their own List of Tags within a given TagScope, so we do 286 // not want the tags property to be shared among all of them. 287 TagScopeTransfer tagScopeTransfer = tagControl.getTagScopeTransfer(userVisit, tagScope).copy(); 288 tagScopeTransfer.setTags(new ListWrapper<>(tagControl.getTagTransfersByTagScopeAndEntityInstance(userVisit, tagScope, entityInstance))); 289 return tagScopeTransfer; 290 }).forEach((tagScopeTransfer) -> { 291 mapWrapper.put(tagScopeTransfer.getTagScopeName(), tagScopeTransfer); 292 }); 293 294 transfer.setTagScopes(mapWrapper); 295 } 296 297 298 /** 299 * Returns the includeEntityInstance. 300 * @return the includeEntityInstance 301 */ 302 protected boolean getIncludeEntityInstance() { 303 return includeEntityInstance; 304 } 305 306 /** 307 * Sets the setupBaseTransfer. 308 * @param includeEntityInstance the setupBaseTransfer to set 309 */ 310 protected void setIncludeEntityInstance(boolean includeEntityInstance) { 311 this.includeEntityInstance = includeEntityInstance; 312 } 313 314 /** 315 * Returns the includeEntityAppearance. 316 * @return the includeEntityAppearance 317 */ 318 protected boolean getIncludeEntityAppearance() { 319 return includeEntityAppearance; 320 } 321 322 /** 323 * Sets the includeEntityAppearance. 324 * @param includeEntityAppearance the includeEntityAppearance to set 325 */ 326 protected void setIncludeEntityAppearance(boolean includeEntityAppearance) { 327 this.includeEntityAppearance = includeEntityAppearance; 328 } 329 330 /** 331 * Returns the includeEntityVisit. 332 * @return the includeEntityVisit 333 */ 334 protected boolean getIncludeEntityVisit() { 335 return includeEntityVisit; 336 } 337 338 /** 339 * Sets the includeEntityVisit. 340 * @param includeEntityVisit the includeEntityVisit to set 341 */ 342 protected void setIncludeEntityVisit(boolean includeEntityVisit) { 343 this.includeEntityVisit = includeEntityVisit; 344 } 345 346 /** 347 * Returns the includeNames. 348 * @return the includeNames 349 */ 350 protected boolean getIncludeNames() { 351 return includeNames; 352 } 353 354 /** 355 * Sets the includeNames. 356 * @param includeNames the includeNames to set 357 */ 358 protected void setIncludeNames(boolean includeNames) { 359 this.includeNames = includeNames; 360 } 361 362 /** 363 * Returns the includeKey. 364 * @return the includeKey 365 */ 366 protected boolean getIncludeKey() { 367 return includeKey; 368 } 369 370 /** 371 * Sets the includeKey. 372 * @param includeKey the includeKey to set 373 */ 374 protected void setIncludeKey(boolean includeKey) { 375 this.includeKey = includeKey; 376 } 377 378 /** 379 * Returns the includeGuid. 380 * @return the includeGuid 381 */ 382 protected boolean getIncludeGuid() { 383 return includeGuid; 384 } 385 386 /** 387 * Sets the includeGuid. 388 * @param includeGuid the includeGuid to set 389 */ 390 protected void setIncludeGuid(boolean includeGuid) { 391 this.includeGuid = includeGuid; 392 } 393 394 /** 395 * Sets the includeUlid. 396 * @param includeUlid the includeUlid to set 397 */ 398 protected void setIncludeUlid(boolean includeUlid) { 399 this.includeUlid = includeUlid; 400 } 401 402 protected void setupEntityInstance(final K baseEntity, EntityInstance entityInstance, final V transfer) { 403 CoreControl coreControl = Session.getModelController(CoreControl.class); 404 405 if(entityInstance == null) { 406 entityInstance = coreControl.getEntityInstanceByBasePK(baseEntity.getPrimaryKey()); 407 } 408 409 // Check to make sure entityInstance is not null. This may happen in a case where a non-versioned entity was 410 // converted to a versioned one. 411 if(entityInstance != null) { 412 transfer.setEntityInstance(coreControl.getEntityInstanceTransfer(userVisit, entityInstance, includeEntityAppearance, 413 includeEntityVisit, includeNames, includeKey, includeGuid, includeUlid)); 414 415 if(includeEntityAliasTypes || includeEntityAttributeGroups || includeTagScopes) { 416 if(includeEntityAliasTypes) { 417 setupEntityAliasTypes(coreControl, entityInstance, transfer); 418 } 419 420 if(includeEntityAttributeGroups) { 421 setupEntityAttributeGroups(coreControl, entityInstance, transfer); 422 } 423 424 if(includeTagScopes) { 425 setupTagScopes(coreControl, entityInstance, transfer); 426 } 427 } 428 } 429 } 430 431 protected EntityInstance setupComments(final K commentedEntity, EntityInstance commentedEntityInstance, final V transfer, final String commentTypeName) { 432 CommentControl commentControl = Session.getModelController(CommentControl.class); 433 434 if(commentedEntityInstance == null) { 435 CoreControl coreControl = Session.getModelController(CoreControl.class); 436 437 commentedEntityInstance = coreControl.getEntityInstanceByBasePK(commentedEntity.getPrimaryKey()); 438 } 439 440 CommentType commentType = commentControl.getCommentTypeByName(commentedEntityInstance.getEntityType(), commentTypeName); 441 transfer.addComments(commentTypeName, new CommentListWrapper(commentControl.getCommentTypeTransfer(userVisit, commentType), 442 commentControl.getCommentTransfersByCommentedEntityInstanceAndCommentType(userVisit, commentedEntityInstance, commentType))); 443 444 return commentedEntityInstance; 445 } 446 447 protected EntityInstance setupRatings(final K ratedEntity, EntityInstance ratedEntityInstance, final V transfer, final String ratingTypeName) { 448 RatingControl ratingControl = Session.getModelController(RatingControl.class); 449 450 if(ratedEntityInstance == null) { 451 CoreControl coreControl = Session.getModelController(CoreControl.class); 452 453 ratedEntityInstance = coreControl.getEntityInstanceByBasePK(ratedEntity.getPrimaryKey()); 454 } 455 456 RatingType ratingType = ratingControl.getRatingTypeByName(ratedEntityInstance.getEntityType(), ratingTypeName); 457 transfer.addRatings(ratingTypeName, new RatingListWrapper(ratingControl.getRatingTypeTransfer(userVisit, ratingType), 458 ratingControl.getRatingTransfersByRatedEntityInstanceAndRatingType(userVisit, ratedEntityInstance, ratingType))); 459 460 return ratedEntityInstance; 461 } 462 463 protected EntityInstance setupOwnedWorkEfforts(final K baseEntity, EntityInstance owningEntityInstance, final V transfer) { 464 WorkEffortControl workEffortControl = Session.getModelController(WorkEffortControl.class); 465 466 if(owningEntityInstance == null) { 467 CoreControl coreControl = Session.getModelController(CoreControl.class); 468 469 owningEntityInstance = coreControl.getEntityInstanceByBasePK(baseEntity.getPrimaryKey()); 470 } 471 472 for(WorkEffortTransfer workEffort: workEffortControl.getWorkEffortTransfersByOwningEntityInstance(userVisit, owningEntityInstance)) { 473 transfer.addOwnedWorkEffort(workEffort.getWorkEffortScope().getWorkEffortType().getWorkEffortTypeName(), workEffort); 474 } 475 476 return owningEntityInstance; 477 } 478 479 protected void verifyOptionDependency(String dependentOption, String dependsOnOption) { 480 var options = session.getOptions(); 481 482 if(!options.contains(dependsOnOption)) { 483 // Throwing an Exception for this seems harsh, but failure to meet the requirements could result in an NPE or other Exceptions. 484 throw new TransferOptionDependencyException(dependentOption + " requires that " + dependsOnOption + " be set as well"); 485 } 486 } 487 488}