001// -------------------------------------------------------------------------------- 002// Copyright 2002-2025 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.common.transfer; 018 019import com.echothree.util.common.string.StringUtils; 020import com.echothree.util.common.transfer.BaseTransfer; 021import com.echothree.util.common.transfer.BaseWrapper; 022import java.lang.reflect.InvocationTargetException; 023import java.util.HashSet; 024import java.util.Set; 025import org.apache.commons.logging.Log; 026import org.apache.commons.logging.LogFactory; 027 028public class BaseTransferUtils { 029 030 private static Log log = LogFactory.getLog(BaseTransferUtils.class); 031 032 private BaseTransferUtils() { 033 super(); 034 } 035 036 private static class BaseTransferUtilsHolder { 037 static BaseTransferUtils instance = new BaseTransferUtils(); 038 } 039 040 public static BaseTransferUtils getInstance() { 041 return BaseTransferUtilsHolder.instance; 042 } 043 044 private void getEntityRefsFromBaseWrapper(EntityRefExclusions entityRefExclusions, Set<String> entityRefs, Set<Object> visitedObjects, 045 BaseWrapper<?> baseWrapper, int indentCount) { 046 var collection = baseWrapper.getCollection(); 047 048 if(!collection.isEmpty()) { 049 collection.stream().filter((nextDependsOn) -> !visitedObjects.contains(nextDependsOn)).forEach((nextDependsOn) -> { 050 getEntityRefs(entityRefExclusions, entityRefs, visitedObjects, nextDependsOn, indentCount + 1); 051 }); 052 } 053 } 054 055 private Set<String> getEntityRefs(EntityRefExclusions entityRefExclusions, Set<String> entityRefs, Set<Object> visitedObjects, Object dependsOn, 056 int indentCount) { 057 if(BaseTransferUtilsDebugFlags.LogVisits) { 058 log.info(StringUtils.getInstance().getIndent(4, indentCount) + "Visiting " + dependsOn); 059 } 060 visitedObjects.add(dependsOn); 061 062 if(dependsOn instanceof BaseTransfer) { 063 var entityInstance = ((BaseTransfer)dependsOn).getEntityInstance(); 064 var includeMethods = true; 065 066 if(entityInstance != null) { 067 var nextDependsOnEntityRef = entityInstance.getEntityRef(); 068 069 if(nextDependsOnEntityRef != null) { 070 if(entityRefExclusions != null && nextDependsOnEntityRef != null && entityRefExclusions.contains(nextDependsOnEntityRef)) { 071 if(BaseTransferUtilsDebugFlags.LogGetEntityRefs) { 072 log.info(StringUtils.getInstance().getIndent(4, indentCount) + "Excluding " + nextDependsOnEntityRef); 073 } 074 075 includeMethods = false; 076 } else { 077 if(BaseTransferUtilsDebugFlags.LogGetEntityRefs) { 078 log.info(StringUtils.getInstance().getIndent(4, indentCount) + "Including " + nextDependsOnEntityRef); 079 } 080 081 entityRefs.add(nextDependsOnEntityRef); 082 } 083 } 084 } 085 086 if(includeMethods) { 087 var methods = dependsOn.getClass().getMethods(); 088 089 for(var method : methods) { 090 var name = method.getName(); 091 092 if(name.startsWith("get")) { 093 try { 094 var returnType = method.getReturnType(); 095 096 if(BaseTransfer.class.isAssignableFrom(returnType)) { 097 // If it's a BaseTransfer... 098 var nextDependsOn = (BaseTransfer)method.invoke(dependsOn); 099 100 if(nextDependsOn != null) { 101 if(!visitedObjects.contains(nextDependsOn)) { 102 getEntityRefs(entityRefExclusions, entityRefs, visitedObjects, nextDependsOn, indentCount + 1); 103 } else { 104 if(BaseTransferUtilsDebugFlags.LogVisits) { 105 log.info(StringUtils.getInstance().getIndent(4, indentCount) + "Already visited " + nextDependsOn); 106 } 107 } 108 } 109 } else if(BaseWrapper.class.isAssignableFrom(returnType)) { 110 // If it's a BaseWrapper 111 var baseWrapper = (BaseWrapper<?>)method.invoke(dependsOn); 112 113 if(baseWrapper != null) { 114 if(BaseTransferUtilsDebugFlags.LogGetEntityRefs) { 115 log.info(StringUtils.getInstance().getIndent(4, indentCount) + "BaseWrapper found: " + name.substring(3)); 116 } 117 118 getEntityRefsFromBaseWrapper(entityRefExclusions, entityRefs, visitedObjects, baseWrapper, indentCount); 119 } 120 } 121 } catch(IllegalAccessException iea) { 122 throw new RuntimeException(iea); 123 } catch(IllegalArgumentException iea) { 124 throw new RuntimeException(iea); 125 } catch(InvocationTargetException ite) { 126 throw new RuntimeException(ite); 127 } 128 } 129 } 130 } 131 } else if(dependsOn instanceof BaseWrapper) { 132 var baseWrapper = (BaseWrapper<?>)dependsOn; 133 134 if(baseWrapper != null) { 135 if(BaseTransferUtilsDebugFlags.LogGetEntityRefs) { 136 log.info(StringUtils.getInstance().getIndent(4, indentCount) + "BaseWrapper passed in"); 137 } 138 139 getEntityRefsFromBaseWrapper(entityRefExclusions, entityRefs, visitedObjects, baseWrapper, indentCount); 140 } 141 } 142 143 return entityRefs; 144 } 145 146 public Set<String> getEntityRefs(EntityRefExclusions entityRefExclusions, Object object) { 147 Set<String> entityRefs = new HashSet<>(); 148 Set<Object> visitedObjects = new HashSet<>(); 149 150 if(BaseTransferUtilsDebugFlags.LogGetEntityRefs) { 151 log.info("Starting getEntityRefs for " + object); 152 } 153 154 if(object instanceof BaseTransfer || object instanceof BaseWrapper) { 155 getEntityRefs(entityRefExclusions, entityRefs, visitedObjects, object, 1); 156 } else { 157 throw new IllegalArgumentException("Object for getEntityRefs(...) must be a BaseTransfer or BaseWrapper object."); 158 } 159 160 if(BaseTransferUtilsDebugFlags.LogGetEntityRefs) { 161 log.info("Ending getEntityRefs"); 162 } 163 164 return entityRefs; 165 } 166 167}