001: //========================================================================
002: //Copyright 2005 Mort Bay Consulting Pty. Ltd.
003: //------------------------------------------------------------------------
004: //Licensed under the Apache License, Version 2.0 (the "License");
005: //you may not use this file except in compliance with the License.
006: //You may obtain a copy of the License at
007: //http://www.apache.org/licenses/LICENSE-2.0
008: //Unless required by applicable law or agreed to in writing, software
009: //distributed under the License is distributed on an "AS IS" BASIS,
010: //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011: //See the License for the specific language governing permissions and
012: //limitations under the License.
013: //========================================================================
014:
015: package org.mortbay.component;
016:
017: import java.util.EventListener;
018:
019: import org.mortbay.log.Log;
020: import org.mortbay.util.LazyList;
021:
022: /* ------------------------------------------------------------ */
023: /** Container.
024: * This class allows a containment events to be generated from update methods.
025: *
026: * The style of usage is: <pre>
027: * public void setFoo(Foo foo)
028: * {
029: * getContainer().update(this,this.foo,foo,"foo");
030: * this.foo=foo;
031: * }
032: *
033: * public void setBars(Bar[] bars)
034: * {
035: * getContainer().update(this,this.bars,bars,"bar");
036: * this.bars=bars;
037: * }
038: * </pre>
039: *
040: * @author gregw
041: *
042: */
043: public class Container {
044: private Object _listeners;
045:
046: public synchronized void addEventListener(
047: Container.Listener listener) {
048: _listeners = LazyList.add(_listeners, listener);
049: }
050:
051: public synchronized void removeEventListener(
052: Container.Listener listener) {
053: _listeners = LazyList.remove(_listeners, listener);
054: }
055:
056: /* ------------------------------------------------------------ */
057: /** Update single parent to child relationship.
058: * @param parent The parent of the child.
059: * @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.
060: * @param child The current child. If this is non null and differs from <code>oldChild</code>, then an add event is generated.
061: * @param relationship The name of the relationship
062: */
063: public synchronized void update(Object parent, Object oldChild,
064: final Object child, String relationship) {
065: if (oldChild != null && !oldChild.equals(child))
066: remove(parent, oldChild, relationship);
067: if (child != null && !child.equals(oldChild))
068: add(parent, child, relationship);
069: }
070:
071: /* ------------------------------------------------------------ */
072: /** Update single parent to child relationship.
073: * @param parent The parent of the child.
074: * @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.
075: * @param child The current child. If this is non null and differs from <code>oldChild</code>, then an add event is generated.
076: * @param relationship The name of the relationship
077: * @param addRemoveBean If true add/remove is called for the new/old children as well as the relationships
078: */
079: public synchronized void update(Object parent, Object oldChild,
080: final Object child, String relationship, boolean addRemove) {
081: if (oldChild != null && !oldChild.equals(child)) {
082: remove(parent, oldChild, relationship);
083: if (addRemove)
084: removeBean(oldChild);
085: }
086:
087: if (child != null && !child.equals(oldChild)) {
088: if (addRemove)
089: addBean(child);
090: add(parent, child, relationship);
091: }
092: }
093:
094: /* ------------------------------------------------------------ */
095: /** Update multiple parent to child relationship.
096: * @param parent The parent of the child.
097: * @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.
098: * This array is modified and children that remain in the new children array are nulled out of the old children array.
099: * @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.
100: * @param relationship The name of the relationship
101: */
102: public synchronized void update(Object parent,
103: Object[] oldChildren, final Object[] children,
104: String relationship) {
105: update(parent, oldChildren, children, relationship, false);
106: }
107:
108: /* ------------------------------------------------------------ */
109: /** Update multiple parent to child relationship.
110: * @param parent The parent of the child.
111: * @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.
112: * This array is modified and children that remain in the new children array are nulled out of the old children array.
113: * @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.
114: * @param relationship The name of the relationship
115: * @param addRemoveBean If true add/remove is called for the new/old children as well as the relationships
116: */
117: public synchronized void update(Object parent,
118: Object[] oldChildren, final Object[] children,
119: String relationship, boolean addRemove) {
120: Object[] newChildren = null;
121: if (children != null) {
122: newChildren = new Object[children.length];
123:
124: for (int i = children.length; i-- > 0;) {
125: boolean new_child = true;
126: if (oldChildren != null) {
127: for (int j = oldChildren.length; j-- > 0;) {
128: if (children[i] != null
129: && children[i].equals(oldChildren[j])) {
130: oldChildren[j] = null;
131: new_child = false;
132: }
133: }
134: }
135: if (new_child)
136: newChildren[i] = children[i];
137: }
138: }
139:
140: if (oldChildren != null) {
141: for (int i = oldChildren.length; i-- > 0;) {
142: if (oldChildren[i] != null) {
143: remove(parent, oldChildren[i], relationship);
144: if (addRemove)
145: removeBean(oldChildren[i]);
146: }
147: }
148: }
149:
150: if (newChildren != null) {
151: for (int i = 0; i < newChildren.length; i++)
152: if (newChildren[i] != null) {
153: if (addRemove)
154: addBean(newChildren[i]);
155: add(parent, newChildren[i], relationship);
156: }
157: }
158: }
159:
160: /* ------------------------------------------------------------ */
161: public void addBean(Object obj) {
162: if (_listeners != null) {
163: for (int i = 0; i < LazyList.size(_listeners); i++) {
164: Listener listener = (Listener) LazyList.get(_listeners,
165: i);
166: listener.addBean(obj);
167: }
168: }
169: }
170:
171: /* ------------------------------------------------------------ */
172: public void removeBean(Object obj) {
173: if (_listeners != null) {
174: for (int i = 0; i < LazyList.size(_listeners); i++)
175: ((Listener) LazyList.get(_listeners, i))
176: .removeBean(obj);
177: }
178: }
179:
180: /* ------------------------------------------------------------ */
181: /** Add a parent child relationship
182: * @param parent
183: * @param child
184: * @param relationship
185: */
186: private void add(Object parent, Object child, String relationship) {
187: if (Log.isDebugEnabled())
188: Log.debug("Container " + parent + " + " + child + " as "
189: + relationship);
190: if (_listeners != null) {
191: Relationship event = new Relationship(this , parent, child,
192: relationship);
193: for (int i = 0; i < LazyList.size(_listeners); i++)
194: ((Listener) LazyList.get(_listeners, i)).add(event);
195: }
196: }
197:
198: /* ------------------------------------------------------------ */
199: /** remove a parent child relationship
200: * @param parent
201: * @param child
202: * @param relationship
203: */
204: private void remove(Object parent, Object child, String relationship) {
205: if (Log.isDebugEnabled())
206: Log.debug("Container " + parent + " - " + child + " as "
207: + relationship);
208: if (_listeners != null) {
209: Relationship event = new Relationship(this , parent, child,
210: relationship);
211: for (int i = 0; i < LazyList.size(_listeners); i++)
212: ((Listener) LazyList.get(_listeners, i)).remove(event);
213: }
214: }
215:
216: /* ------------------------------------------------------------ */
217: /** A Container event.
218: * @see Listener
219: *
220: */
221: public static class Relationship {
222: private Object _parent;
223: private Object _child;
224: private String _relationship;
225: private Container _container;
226:
227: private Relationship(Container container, Object parent,
228: Object child, String relationship) {
229: _container = container;
230: _parent = parent;
231: _child = child;
232: _relationship = relationship;
233: }
234:
235: public Container getContainer() {
236: return _container;
237: }
238:
239: public Object getChild() {
240: return _child;
241: }
242:
243: public Object getParent() {
244: return _parent;
245: }
246:
247: public String getRelationship() {
248: return _relationship;
249: }
250:
251: public String toString() {
252: return _parent + "---" + _relationship + "-->" + _child;
253: }
254:
255: public int hashCode() {
256: return _parent.hashCode() + _child.hashCode()
257: + _relationship.hashCode();
258: }
259:
260: public boolean equals(Object o) {
261: if (o == null || !(o instanceof Relationship))
262: return false;
263: Relationship r = (Relationship) o;
264: return r._parent == _parent && r._child == _child
265: && r._relationship.equals(_relationship);
266: }
267: }
268:
269: /* ------------------------------------------------------------ */
270: /** Listener.
271: * A listener for Container events.
272: */
273: public interface Listener extends EventListener {
274: public void addBean(Object bean);
275:
276: public void removeBean(Object bean);
277:
278: public void add(Container.Relationship relationship);
279:
280: public void remove(Container.Relationship relationship);
281:
282: }
283: }
|