001package com.avaje.ebean.common;
002
003import com.avaje.ebean.Ebean;
004import com.avaje.ebean.ExpressionList;
005import com.avaje.ebean.bean.BeanCollection;
006import com.avaje.ebean.bean.BeanCollectionLoader;
007import com.avaje.ebean.bean.EntityBean;
008
009import javax.persistence.PersistenceException;
010import java.util.Set;
011
012/**
013 * Base class for List Set and Map implementations of BeanCollection.
014 * 
015 * @author rbygrave
016 */
017public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
018
019  private static final long serialVersionUID = 3365725236140187588L;
020
021  protected boolean readOnly;
022
023  protected boolean disableLazyLoad;
024
025  /**
026   * The EbeanServer this is associated with. (used for lazy fetch).
027   */
028  protected transient BeanCollectionLoader loader;
029
030  protected transient ExpressionList<?> filterMany;
031
032  /**
033   * Flag set when registered with the batch loading context.
034   */
035  protected boolean registeredWithLoadContext;
036
037  protected String ebeanServerName;
038
039  /**
040   * The owning bean (used for lazy fetch).
041   */
042  protected EntityBean ownerBean;
043
044  /**
045   * The name of this property in the owning bean (used for lazy fetch).
046   */
047  protected String propertyName;
048
049  protected ModifyHolder<E> modifyHolder;
050
051  protected ModifyListenMode modifyListenMode;
052  protected boolean modifyAddListening;
053  protected boolean modifyRemoveListening;
054  protected boolean modifyListening;
055
056  /**
057   * Constructor not non-lazy loading collection.
058   */
059  public AbstractBeanCollection() {
060  }
061
062  /**
063   * Used to create deferred fetch proxy.
064   */
065  public AbstractBeanCollection(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
066    this.loader = loader;
067    this.ebeanServerName = loader.getName();
068    this.ownerBean = ownerBean;
069    this.propertyName = propertyName;
070    this.readOnly = ownerBean._ebean_getIntercept().isReadOnly();
071  }
072
073  public EntityBean getOwnerBean() {
074    return ownerBean;
075  }
076
077  public String getPropertyName() {
078    return propertyName;
079  }
080
081  public ExpressionList<?> getFilterMany() {
082    return filterMany;
083  }
084
085  public void setFilterMany(ExpressionList<?> filterMany) {
086    this.filterMany = filterMany;
087  }
088
089  @Override
090  public void setDisableLazyLoad(boolean disableLazyLoad) {
091    this.disableLazyLoad = disableLazyLoad;
092  }
093
094  protected void lazyLoadCollection(boolean onlyIds) {
095    if (loader == null) {
096      loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName);
097    }
098    if (loader == null) {
099      String msg = "Lazy loading but LazyLoadEbeanServer is null?"
100          + " The LazyLoadEbeanServer needs to be set after deserialization"
101          + " to support lazy loading.";
102      throw new PersistenceException(msg);
103    }
104
105    loader.loadMany(this, onlyIds);
106    checkEmptyLazyLoad();
107  }
108
109  public boolean isRegisteredWithLoadContext() {
110    return registeredWithLoadContext;
111  }
112
113  public void setLoader(BeanCollectionLoader loader) {
114    this.registeredWithLoadContext = true;
115    this.loader = loader;
116    this.ebeanServerName = loader.getName();
117  }
118
119  public boolean isReadOnly() {
120    return readOnly;
121  }
122
123  public void setReadOnly(boolean readOnly) {
124    this.readOnly = readOnly;
125  }
126
127  protected void checkReadOnly() {
128    if (readOnly) {
129      String msg = "This collection is in ReadOnly mode";
130      throw new IllegalStateException(msg);
131    }
132  }
133
134  // ---------------------------------------------------------
135  // Support for modify additions deletions etc - ManyToMany
136  // ---------------------------------------------------------
137
138  /**
139   * set modifyListening to be on or off.
140   */
141  public void setModifyListening(ModifyListenMode mode) {
142
143    this.modifyListenMode = mode;
144    this.modifyAddListening = ModifyListenMode.ALL.equals(mode);
145    this.modifyRemoveListening = modifyAddListening || ModifyListenMode.REMOVALS.equals(mode);
146    this.modifyListening = modifyRemoveListening || modifyAddListening;
147    if (modifyListening) {
148      // lose any existing modifications
149      modifyHolder = null;
150    }
151  }
152
153  /**
154   * Return the modify listening mode this collection is using.
155   */
156  public ModifyListenMode getModifyListenMode() {
157    return modifyListenMode;
158  }
159
160  protected ModifyHolder<E> getModifyHolder() {
161    if (modifyHolder == null) {
162      modifyHolder = new ModifyHolder<E>();
163    }
164    return modifyHolder;
165  }
166
167  public void modifyAddition(E bean) {
168    if (modifyAddListening) {
169      getModifyHolder().modifyAddition(bean);
170    }
171  }
172
173  public void modifyRemoval(Object bean) {
174    if (modifyRemoveListening) {
175      getModifyHolder().modifyRemoval(bean);
176    }
177  }
178
179  public void modifyReset() {
180    if (modifyHolder != null) {
181      modifyHolder.reset();
182    }
183  }
184
185  public Set<E> getModifyAdditions() {
186    if (modifyHolder == null) {
187      return null;
188    } else {
189      return modifyHolder.getModifyAdditions();
190    }
191  }
192
193  public Set<E> getModifyRemovals() {
194    if (modifyHolder == null) {
195      return null;
196    } else {
197      return modifyHolder.getModifyRemovals();
198    }
199  }
200
201  /**
202   * Return true if there are underlying additions or removals.
203   */
204  public boolean holdsModifications() {
205    return modifyHolder != null && modifyHolder.hasModifications();
206  }
207}