Project

General

Profile

« Previous | Next » 

Revision 94e54bd9

Added by Andreas Kohlbecker over 6 years ago

PersistentContextAnalyzer as subclass of CdmEntityCache

View differences:

src/main/java/eu/etaxonomy/cdm/debug/PersistentContextAnalyzer.java
8 8
*/
9 9
package eu.etaxonomy.cdm.debug;
10 10

  
11
import java.beans.PropertyDescriptor;
12 11
import java.io.PrintStream;
13
import java.lang.reflect.InvocationTargetException;
14
import java.util.ArrayList;
15
import java.util.Collection;
16
import java.util.HashMap;
17
import java.util.HashSet;
18
import java.util.List;
19
import java.util.Map;
20
import java.util.Set;
21 12

  
22
import org.apache.commons.beanutils.PropertyUtils;
23
import org.apache.commons.lang.builder.HashCodeBuilder;
24 13
import org.apache.log4j.Logger;
25
import org.hibernate.Hibernate;
26 14
import org.hibernate.Session;
27
import org.hibernate.collection.internal.AbstractPersistentCollection;
28
import org.hibernate.envers.internal.entities.mapper.relation.lazy.proxy.CollectionProxy;
29
import org.hibernate.envers.internal.entities.mapper.relation.lazy.proxy.MapProxy;
30
import org.hibernate.envers.internal.entities.mapper.relation.lazy.proxy.SortedMapProxy;
31 15

  
32
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
16
import eu.etaxonomy.cdm.cache.CdmEntityCache;
33 17
import eu.etaxonomy.cdm.model.common.CdmBase;
34
import eu.etaxonomy.cdm.persistence.dao.initializer.AbstractBeanInitializer;
35 18

  
36 19
/**
37 20
 * @author a.kohlbecker
38 21
 * @since 08.11.2017
39 22
 *
40 23
 */
41
public class PersistentContextAnalyzer {
24
public class PersistentContextAnalyzer extends CdmEntityCache {
42 25

  
43
    /**
44
     *
45
     */
46
    private static final char HASH_SEPARATOR = '.';
47 26

  
48
    /**
49
     *
50
     */
51
    private static final String COPY_ENTITY = "!";
27
    private static final char HASH_SEPARATOR = '.';
52 28

  
53
    /**
54
     *
55
     */
56 29
    private static final String IN_PERSITENT_CONTEXT = "*";
57 30

  
58 31
    private final static Logger logger = Logger.getLogger(PersistentContextAnalyzer.class);
59 32

  
60 33
    private Session session;
61 34

  
62
    private CdmBase entity;
63

  
64
    private Map<EntityKey, CdmBase> entityyMap = new HashMap<>();
65

  
66
    private List<String> entityPathList = new ArrayList<>();
67

  
68
    private Map<EntityKey, List<String>> entityPathsMap = new HashMap<>();
69

  
70
    private Set<EntityKey> copyEntitiyKeys = new HashSet<>();
71

  
72
    private Set<Object> objectsSeen = new HashSet<>();
73

  
74 35
    private boolean showHashCodes = false;
75 36

  
76 37
    /**
77
     * TODO the PersistentContextAnalyzer should be a subclass od the CdmEntityCache!!!
78
     *
79 38
     * @param entity
80 39
     * @param session
81 40
     */
82 41
    public PersistentContextAnalyzer(CdmBase entity, Session session){
83 42
        this.session = session;
84
        this.entity = entity;
43
        this.entities.add(entity);
85 44
        update();
86 45
    }
87 46

  
......
89 48
        this(entity, null);
90 49
    }
91 50

  
92
    /**
93
     * - find copied entities in the graph
94
     */
95
    private void update() {
96

  
97
        entityyMap.clear();
98
        entityPathList.clear();
99
        entityPathsMap.clear();
100
        copyEntitiyKeys.clear();
101
        objectsSeen.clear();
102

  
103
        String propertyPath = "";
104

  
105
        analyzeEntity(entity, propertyPath);
106
    }
51
    public PersistentContextAnalyzer(CdmEntityCache entityCache, Session session){
52
        this.session = session;
53
        this.entities.addAll(entityCache.getEntities());
107 54

  
108
    public void printEntityGraph(PrintStream printStream){
109
        printLegend(printStream);
110
        for(String path : entityPathList) {
111
            printStream.println(path);
112
        }
113 55
    }
114 56

  
115
    public void printCopyEntities(PrintStream printStream){
116
        printLegend(printStream);
117
        for(EntityKey key : copyEntitiyKeys){
118
            for(String path : entityPathsMap.get(key)) {
119
                printStream.println(path);
120
            }
121
        }
122
    }
123 57

  
124 58
    /**
125 59
     * @param printStream
126 60
     */
61
    @Override
127 62
    protected void printLegend(PrintStream printStream) {
128 63
        printStream.println("PersistentContextAnalyzer legend: ");
129 64
        printStream.println("    - '.{objectHash}': unique copy entity, followed by object hash (only shown when showHashCodes is enabled)");
......
131 66
        printStream.println("    - '*': entity mapped in persistent context");
132 67
    }
133 68

  
134
    /**
135
     *
136
     */
137
    protected void analyzeEntity(CdmBase bean, String propertyPath) {
138

  
139
        EntityKey entityKey = new EntityKey(bean);
140

  
141
        propertyPath += "[" + entityKey;
142
        String flags = "";
143
        CdmBase mappedEntity = entityyMap.put(entityKey, bean);
69
    @Override
70
    protected String analyzeMore(CdmBase bean, EntityKey entityKey, String flags, CdmBase mappedEntity) {
144 71

  
145 72
        boolean hashAdded = false;
146 73

  
147
        if(session != null && session.contains(bean)){
148
            flags += IN_PERSITENT_CONTEXT;
149
        }
150 74
        if(mappedEntity != null && mappedEntity != bean) {
151
            copyEntitiyKeys.add(entityKey);
152
            flags += COPY_ENTITY + bean.hashCode();
75
            flags += bean.hashCode();
153 76
            hashAdded = true;
154 77
        }
78
        if(session != null && session.contains(bean)){
79
            flags += IN_PERSITENT_CONTEXT;
80
        }
155 81
        if(showHashCodes && ! hashAdded){
156 82
            flags += HASH_SEPARATOR + bean.hashCode();
157 83
        }
158
        if(!flags.isEmpty()){
159
            propertyPath += "(" + flags + ")";
160
        }
161
        propertyPath += "]";
162

  
163
        logger.debug(propertyPath);
164

  
165
        entityPathList.add(propertyPath);
166
        if(!entityPathsMap.containsKey(entityKey)){
167
            entityPathsMap.put(entityKey, new ArrayList<>());
168
        }
169
        entityPathsMap.get(entityKey).add(propertyPath);
170

  
171
        if(!objectsSeen.add(bean)){
172
            // avoid cycles, do not recurse into properties of objects that have been analyzed already
173
            return;
174
        }
175

  
176
        Set<PropertyDescriptor> properties = AbstractBeanInitializer.getProperties(bean, null);
177
        for(PropertyDescriptor prop : properties){
178

  
179
            try {
180
                Object propertyValue = PropertyUtils.getProperty(bean, prop.getName());
181

  
182
                if(propertyValue == null){
183
                    continue;
184
                }
185

  
186
                String propertyPathSuffix = "." + prop.getName();
187

  
188
                if(Hibernate.isInitialized(propertyValue)) {
189

  
190
                    if(CdmBase.class.isAssignableFrom(prop.getPropertyType())){
191
                        analyzeEntity(HibernateProxyHelper.deproxy(propertyValue, CdmBase.class), propertyPath + propertyPathSuffix);
192
                        continue;
193
                    }
194

  
195
                    Collection<CdmBase> collection = null;
196
                    if(propertyValue instanceof AbstractPersistentCollection){
197
                        if (propertyValue  instanceof Collection) {
198
                            collection = (Collection<CdmBase>) propertyValue;
199
                        } else if (propertyValue instanceof Map) {
200
                            collection = ((Map<?,CdmBase>)propertyValue).values();
201
                        } else {
202
                            logger.error("unhandled subtype of AbstractPersistentCollection");
203
                        }
204
                    } else if (propertyValue instanceof CollectionProxy
205
                                || propertyValue instanceof MapProxy<?, ?>
206
                                || propertyValue instanceof SortedMapProxy<?, ?>){
207
                            //hibernate envers collections
208
                            collection = (Collection<CdmBase>)propertyValue;
209
                    }
210

  
211
                    if(collection != null){
212
                        for(CdmBase collectionItem : collection){
213
                            analyzeEntity(HibernateProxyHelper.deproxy(collectionItem, CdmBase.class), propertyPath + propertyPathSuffix);
214
                        }
215
                    } else {
216
                        // logger.error("Unhandled property type " + propertyValue.getClass().getName());
217
                    }
218
                }
219

  
220
            } catch (IllegalAccessException e) {
221
                String message = "Illegal access on property " + prop;
222
                logger.error(message);
223
                throw new RuntimeException(message, e);
224
            } catch (InvocationTargetException e) {
225
                String message = "Cannot invoke property " + prop + " not found";
226
                logger.error(message);
227
                throw new RuntimeException(message, e);
228
            } catch (NoSuchMethodException e) {
229
                String message = "Property " + prop.getName() + " not found for class " + bean.getClass();
230
                logger.error(message);
231
            }
232

  
233
        }
84
        return flags;
234 85
    }
235 86

  
236 87
    /**
......
251 102
        }
252 103
    }
253 104

  
254
    class EntityKey {
255

  
256
        Class type;
257
        int id;
258

  
259
        public EntityKey(CdmBase entity){
260
            type = entity.getClass();
261
            id = entity.getId();
262
        }
263

  
264
        /**
265
         * @return the type
266
         */
267
        public Class getType() {
268
            return type;
269
        }
270

  
271
        /**
272
         * @return the id
273
         */
274
        public int getId() {
275
            return id;
276
        }
277

  
278
        /**
279
         * {@inheritDoc}
280
         */
281
        @Override
282
        public int hashCode() {
283
            return new HashCodeBuilder(17, 31)
284
                    .append(type)
285
                    .append(id)
286
                    .toHashCode();
287
        }
288

  
289
        @Override
290
        public String toString() {
291
            return type.getSimpleName() + "#" + getId();
292
        }
293

  
294
    }
295

  
296

  
297 105
}

Also available in: Unified diff