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