001package io.ebean.bean;
002
003import java.lang.ref.WeakReference;
004import java.util.LinkedHashSet;
005import java.util.Set;
006
007/**
008 * Collects profile information for a bean (or reference/proxy bean) at a given node.
009 * <p>
010 * The node identifies the location of the bean in the object graph.
011 * </p>
012 * <p>
013 * It has to use a weak reference so as to ensure that it does not stop the
014 * associated bean from being garbage collected.
015 * </p>
016 */
017public final class NodeUsageCollector {
018
019  /**
020   * The point in the object graph for a specific query and call stack point.
021   */
022  private final ObjectGraphNode node;
023
024  /**
025   * Weak to allow garbage collection.
026   */
027  private final WeakReference<NodeUsageListener> managerRef;
028
029  /**
030   * The properties used at this profile point.
031   */
032  private final Set<String> used = new LinkedHashSet<>();
033
034  /**
035   * set to true if the bean is modified (setter called)
036   */
037  private boolean modified;
038
039  /**
040   * The property that cause a reference to lazy load.
041   */
042  private String loadProperty;
043
044  public NodeUsageCollector(ObjectGraphNode node, WeakReference<NodeUsageListener> managerRef) {
045    this.node = node;
046    // weak to allow garbage collection.
047    this.managerRef = managerRef;
048  }
049
050  /**
051   * The bean has been modified by a setter method.
052   */
053  public void setModified() {
054    modified = true;
055  }
056
057  /**
058   * Add the name of a property that has been used.
059   */
060  public void addUsed(String property) {
061    used.add(property);
062  }
063
064  /**
065   * The property that invoked a lazy load.
066   */
067  public void setLoadProperty(String loadProperty) {
068    this.loadProperty = loadProperty;
069  }
070
071  /**
072   * Publish the usage info to the manager.
073   */
074  private void publishUsageInfo() {
075    NodeUsageListener manager = managerRef.get();
076    if (manager != null) {
077      manager.collectNodeUsage(this);
078    }
079  }
080
081  /**
082   * publish the collected usage information when garbage collection occurs.
083   */
084  @Override
085  protected void finalize() throws Throwable {
086    publishUsageInfo();
087    super.finalize();
088  }
089
090  /**
091   * Return the associated node which identifies the location in the object
092   * graph of the bean/reference.
093   */
094  public ObjectGraphNode getNode() {
095    return node;
096  }
097
098  /**
099   * Return true if no properties where used.
100   */
101  public boolean isEmpty() {
102    return used.isEmpty();
103  }
104
105  /**
106   * Return the set of used properties.
107   */
108  public Set<String> getUsed() {
109    return used;
110  }
111
112  /**
113   * Return true if the bean was modified by a setter.
114   */
115  public boolean isModified() {
116    return modified;
117  }
118
119  public String getLoadProperty() {
120    return loadProperty;
121  }
122
123  @Override
124  public String toString() {
125    return node + " read:" + used + " modified:" + modified;
126  }
127}