1 //======================================================================== 2 //Copyright 2005 Mort Bay Consulting Pty. Ltd. 3 //------------------------------------------------------------------------ 4 //Licensed under the Apache License, Version 2.0 (the "License"); 5 //you may not use this file except in compliance with the License. 6 //You may obtain a copy of the License at 7 //http://www.apache.org/licenses/LICENSE-2.0 8 //Unless required by applicable law or agreed to in writing, software 9 //distributed under the License is distributed on an "AS IS" BASIS, 10 //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 //See the License for the specific language governing permissions and 12 //limitations under the License. 13 //======================================================================== 14 15 package org.mortbay.component; 16 import java.util.EventListener; 17 18 import org.mortbay.log.Log; 19 import org.mortbay.util.LazyList; 20 21 /* ------------------------------------------------------------ */ 22 /** Container. 23 * This class allows a containment events to be generated from update methods. 24 * 25 * The style of usage is: <pre> 26 * public void setFoo(Foo foo) 27 * { 28 * getContainer().update(this,this.foo,foo,"foo"); 29 * this.foo=foo; 30 * } 31 * 32 * public void setBars(Bar[] bars) 33 * { 34 * getContainer().update(this,this.bars,bars,"bar"); 35 * this.bars=bars; 36 * } 37 * </pre> 38 * 39 * @author gregw 40 * 41 */ 42 public class Container 43 { 44 private Object _listeners; 45 addEventListener(Container.Listener listener)46 public synchronized void addEventListener(Container.Listener listener) 47 { 48 _listeners=LazyList.add(_listeners,listener); 49 } 50 removeEventListener(Container.Listener listener)51 public synchronized void removeEventListener(Container.Listener listener) 52 { 53 _listeners=LazyList.remove(_listeners,listener); 54 } 55 56 /* ------------------------------------------------------------ */ 57 /** Update single parent to child relationship. 58 * @param parent The parent of the child. 59 * @param oldChild The previous value of the child. If this is non null and differs from <code>child</code>, then a remove event is generated. 60 * @param child The current child. If this is non null and differs from <code>oldChild</code>, then an add event is generated. 61 * @param relationship The name of the relationship 62 */ update(Object parent, Object oldChild, final Object child, String relationship)63 public synchronized void update(Object parent, Object oldChild, final Object child, String relationship) 64 { 65 if (oldChild!=null && !oldChild.equals(child)) 66 remove(parent,oldChild,relationship); 67 if (child!=null && !child.equals(oldChild)) 68 add(parent,child,relationship); 69 } 70 71 /* ------------------------------------------------------------ */ 72 /** Update single parent to child relationship. 73 * @param parent The parent of the child. 74 * @param oldChild The previous value of the child. If this is non null and differs from <code>child</code>, then a remove event is generated. 75 * @param child The current child. If this is non null and differs from <code>oldChild</code>, then an add event is generated. 76 * @param relationship The name of the relationship 77 * @param addRemoveBean If true add/remove is called for the new/old children as well as the relationships 78 */ update(Object parent, Object oldChild, final Object child, String relationship,boolean addRemove)79 public synchronized void update(Object parent, Object oldChild, final Object child, String relationship,boolean addRemove) 80 { 81 if (oldChild!=null && !oldChild.equals(child)) 82 { 83 remove(parent,oldChild,relationship); 84 if (addRemove) 85 removeBean(oldChild); 86 } 87 88 if (child!=null && !child.equals(oldChild)) 89 { 90 if (addRemove) 91 addBean(child); 92 add(parent,child,relationship); 93 } 94 } 95 96 /* ------------------------------------------------------------ */ 97 /** Update multiple parent to child relationship. 98 * @param parent The parent of the child. 99 * @param oldChildren The previous array of children. A remove event is generated for any child in this array but not in the <code>children</code> array. 100 * This array is modified and children that remain in the new children array are nulled out of the old children array. 101 * @param children The current array of children. An add event is generated for any child in this array but not in the <code>oldChildren</code> array. 102 * @param relationship The name of the relationship 103 */ update(Object parent, Object[] oldChildren, final Object[] children, String relationship)104 public synchronized void update(Object parent, Object[] oldChildren, final Object[] children, String relationship) 105 { 106 update(parent,oldChildren,children,relationship,false); 107 } 108 109 /* ------------------------------------------------------------ */ 110 /** Update multiple parent to child relationship. 111 * @param parent The parent of the child. 112 * @param oldChildren The previous array of children. A remove event is generated for any child in this array but not in the <code>children</code> array. 113 * This array is modified and children that remain in the new children array are nulled out of the old children array. 114 * @param children The current array of children. An add event is generated for any child in this array but not in the <code>oldChildren</code> array. 115 * @param relationship The name of the relationship 116 * @param addRemoveBean If true add/remove is called for the new/old children as well as the relationships 117 */ update(Object parent, Object[] oldChildren, final Object[] children, String relationship, boolean addRemove)118 public synchronized void update(Object parent, Object[] oldChildren, final Object[] children, String relationship, boolean addRemove) 119 { 120 Object[] newChildren = null; 121 if (children!=null) 122 { 123 newChildren = new Object[children.length]; 124 125 for (int i=children.length;i-->0;) 126 { 127 boolean new_child=true; 128 if (oldChildren!=null) 129 { 130 for (int j=oldChildren.length;j-->0;) 131 { 132 if (children[i]!=null && children[i].equals(oldChildren[j])) 133 { 134 oldChildren[j]=null; 135 new_child=false; 136 } 137 } 138 } 139 if (new_child) 140 newChildren[i]=children[i]; 141 } 142 } 143 144 if (oldChildren!=null) 145 { 146 for (int i=oldChildren.length;i-->0;) 147 { 148 if (oldChildren[i]!=null) 149 { 150 remove(parent,oldChildren[i],relationship); 151 if (addRemove) 152 removeBean(oldChildren[i]); 153 } 154 } 155 } 156 157 if (newChildren!=null) 158 { 159 for (int i=0;i<newChildren.length;i++) 160 if (newChildren[i]!=null) 161 { 162 if (addRemove) 163 addBean(newChildren[i]); 164 add(parent,newChildren[i],relationship); 165 } 166 } 167 } 168 169 /* ------------------------------------------------------------ */ addBean(Object obj)170 public void addBean(Object obj) 171 { 172 if (_listeners!=null) 173 { 174 for (int i=0; i<LazyList.size(_listeners); i++) 175 { 176 Listener listener=(Listener)LazyList.get(_listeners, i); 177 listener.addBean(obj); 178 } 179 } 180 } 181 182 /* ------------------------------------------------------------ */ removeBean(Object obj)183 public void removeBean(Object obj) 184 { 185 if (_listeners!=null) 186 { 187 for (int i=0; i<LazyList.size(_listeners); i++) 188 ((Listener)LazyList.get(_listeners, i)).removeBean(obj); 189 } 190 } 191 192 /* ------------------------------------------------------------ */ 193 /** Add a parent child relationship 194 * @param parent 195 * @param child 196 * @param relationship 197 */ add(Object parent, Object child, String relationship)198 private void add(Object parent, Object child, String relationship) 199 { 200 if (Log.isDebugEnabled()) 201 Log.debug("Container "+parent+" + "+child+" as "+relationship); 202 if (_listeners!=null) 203 { 204 Relationship event=new Relationship(this,parent,child,relationship); 205 for (int i=0; i<LazyList.size(_listeners); i++) 206 ((Listener)LazyList.get(_listeners, i)).add(event); 207 } 208 } 209 210 /* ------------------------------------------------------------ */ 211 /** remove a parent child relationship 212 * @param parent 213 * @param child 214 * @param relationship 215 */ remove(Object parent, Object child, String relationship)216 private void remove(Object parent, Object child, String relationship) 217 { 218 if (Log.isDebugEnabled()) 219 Log.debug("Container "+parent+" - "+child+" as "+relationship); 220 if (_listeners!=null) 221 { 222 Relationship event=new Relationship(this,parent,child,relationship); 223 for (int i=0; i<LazyList.size(_listeners); i++) 224 ((Listener)LazyList.get(_listeners, i)).remove(event); 225 } 226 } 227 228 /* ------------------------------------------------------------ */ 229 /** A Container event. 230 * @see Listener 231 * 232 */ 233 public static class Relationship 234 { 235 private Object _parent; 236 private Object _child; 237 private String _relationship; 238 private Container _container; 239 Relationship(Container container, Object parent,Object child, String relationship)240 private Relationship(Container container, Object parent,Object child, String relationship) 241 { 242 _container=container; 243 _parent=parent; 244 _child=child; 245 _relationship=relationship; 246 } 247 getContainer()248 public Container getContainer() 249 { 250 return _container; 251 } 252 getChild()253 public Object getChild() 254 { 255 return _child; 256 } 257 getParent()258 public Object getParent() 259 { 260 return _parent; 261 } 262 getRelationship()263 public String getRelationship() 264 { 265 return _relationship; 266 } 267 toString()268 public String toString() 269 { 270 return _parent+"---"+_relationship+"-->"+_child; 271 } 272 hashCode()273 public int hashCode() 274 { 275 return _parent.hashCode()+_child.hashCode()+_relationship.hashCode(); 276 } 277 equals(Object o)278 public boolean equals(Object o) 279 { 280 if (o==null || !(o instanceof Relationship)) 281 return false; 282 Relationship r = (Relationship)o; 283 return r._parent==_parent && r._child==_child && r._relationship.equals(_relationship); 284 } 285 } 286 287 /* ------------------------------------------------------------ */ 288 /** Listener. 289 * A listener for Container events. 290 */ 291 public interface Listener extends EventListener 292 { addBean(Object bean)293 public void addBean(Object bean); removeBean(Object bean)294 public void removeBean(Object bean); add(Container.Relationship relationship)295 public void add(Container.Relationship relationship); remove(Container.Relationship relationship)296 public void remove(Container.Relationship relationship); 297 298 } 299 } 300