KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > nodes > BeanChildren


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.openide.nodes;
20
21
22 import java.beans.IntrospectionException JavaDoc;
23 import java.beans.beancontext.*;
24
25 import java.lang.ref.*;
26
27 import java.util.*;
28 import java.util.logging.Level JavaDoc;
29 import java.util.logging.Logger JavaDoc;
30
31
32 /** Class that represents bean children of a JavaBeans context.
33 * It listens on the bean context changes and creates nodes for
34 * child beans. By default {@link BeanNode}s are created for all
35 * child beans, but this behaviour can be changed by
36 * providing a different factory to the constructor.
37 *
38 * @author Jaroslav Tulach, Jesse Glick
39 */

40 public class BeanChildren extends Children.Keys {
41     /** default factory for creation of children */
42     private static final Factory DEFAULT_FACTORY = new BeanFactory();
43
44     /** Map from nodes some BeanChildren have created, to the beans
45      * they were intended to represent. If a node is deleted, we remove
46      * the bean from its context. The nodes are weakly held, and each
47      * value is a 2-element array of weak references to the bean context
48      * and child, resp.
49      * See #7925.
50      */

51     private static final java.util.Map JavaDoc<Node,Reference[]> nodes2Beans =
52             new WeakHashMap<Node,Reference[]>(); // Map<Node,Reference<Object>[2]>
53

54     /** bean context to work on */
55     private BeanContext bean;
56
57     /** factory for creation of subnodes */
58     private Factory factory;
59
60     /** context listener */
61     private ContextL contextL;
62
63     /** Create {@link BeanNode} children based on a Bean context.
64     * @param bean the context
65     */

66     public BeanChildren(BeanContext bean) {
67         this(bean, DEFAULT_FACTORY);
68     }
69
70     /** Create children based on a Bean context.
71     * @param bean the context
72     * @param factory a factory to use for creation of child nodes
73     */

74     public BeanChildren(BeanContext bean, Factory factory) {
75         this.bean = bean;
76         this.factory = factory;
77     }
78
79     /** Updates the keys from the bean context.
80     */

81     final void updateKeys() {
82         setKeys(bean.toArray());
83     }
84
85     /** Creates a node representant for given bean. Uses factory
86     * to get the node.
87     * @param subbean the bean from bean context
88     * @return node created by the factory
89     */

90     protected Node[] createNodes(Object JavaDoc subbean) {
91         try {
92             if (subbean instanceof BeanContextSupport) {
93                 BeanContextSupport bcs = (BeanContextSupport) subbean;
94
95                 if (bean.contains(bcs.getBeanContextPeer()) && (bcs != bcs.getBeanContextPeer())) {
96                     // sometimes a BeanContextSupport occures in the list of
97
// beans children even there is its peer. we think that
98
// it is desirable to hide the context if the peer is
99
// also present
100
return new Node[0];
101                 }
102             }
103
104             Node n = factory.createNode(subbean);
105
106             // #7925: deleting from BeanChildren has no effect
107
synchronized (nodes2Beans) {
108                 nodes2Beans.put(n, new Reference[] { new WeakReference<BeanContext>(bean), new WeakReference<Object JavaDoc>(subbean) });
109             }
110
111             n.addNodeListener(contextL);
112
113             return new Node[] { n };
114         } catch (IntrospectionException JavaDoc ex) {
115             Logger.getLogger(BeanChildren.class.getName()).log(Level.WARNING, null, ex);
116
117             return new Node[0];
118         }
119     }
120
121     /* Initializes children and attaches listener to bean context.
122     */

123     protected void addNotify() {
124         // attaches a listener to the bean
125
contextL = new ContextL(this);
126         bean.addBeanContextMembershipListener(contextL);
127
128         updateKeys();
129     }
130
131     /** Removes the listener and does some necessary clean up.
132     */

133     protected void removeNotify() {
134         if (contextL != null) {
135             bean.removeBeanContextMembershipListener(contextL);
136         }
137
138         contextL = null;
139
140         setKeys(java.util.Collections.EMPTY_SET);
141     }
142
143     /** Controls which nodes
144     * are created for a child bean.
145     * @see BeanChildren#BeanChildren(BeanContext, BeanChildren.Factory)
146     */

147     public static interface Factory {
148         /** Create a node for a child bean.
149         * @param bean the bean
150         * @return the node for the bean
151         * @exception IntrospectionException if the node cannot be created
152         */

153         public Node createNode(Object JavaDoc bean) throws IntrospectionException JavaDoc;
154     }
155
156     /** Default factory. Creates BeanNode for each bean
157     */

158     private static class BeanFactory extends Object JavaDoc implements Factory {
159         BeanFactory() {
160         }
161
162         /** @return bean node */
163         public Node createNode(Object JavaDoc bean) throws IntrospectionException JavaDoc {
164             return new BeanNode(bean);
165         }
166     }
167
168     /** Context listener.
169     */

170     private static final class ContextL extends NodeAdapter implements BeanContextMembershipListener {
171         /** weak reference to the BeanChildren object */
172         private WeakReference<BeanChildren> ref;
173
174         ContextL() {
175         }
176
177         /** Constructor */
178         ContextL(BeanChildren bc) {
179             ref = new WeakReference<BeanChildren>(bc);
180         }
181
182         /** Listener method that is called when a bean is added to
183         * the bean context.
184         * @param bcme event describing the action
185         */

186         public void childrenAdded(BeanContextMembershipEvent bcme) {
187             BeanChildren bc = ref.get();
188
189             if (bc != null) {
190                 bc.updateKeys();
191             }
192         }
193
194         /** Listener method that is called when a bean is removed to
195         * the bean context.
196         * @param bcme event describing the action
197         */

198         public void childrenRemoved(BeanContextMembershipEvent bcme) {
199             BeanChildren bc = ref.get();
200
201             if (bc != null) {
202                 bc.updateKeys();
203             }
204         }
205
206         public void nodeDestroyed(NodeEvent ev) {
207             Node n = ev.getNode();
208             Reference[] refs;
209
210             synchronized (nodes2Beans) {
211                 refs = nodes2Beans.get(n);
212             }
213
214             if (refs != null) {
215                 BeanContext bean = (BeanContext) refs[0].get();
216
217                 if (bean != null) {
218                     Object JavaDoc subbean = refs[1].get();
219
220                     if (subbean != null) {
221                         // This should in turn cause childrenRemoved to be called...
222
// and the node not to be recreated in the next keys update.
223
try {
224                             bean.remove(subbean);
225                         } catch (RuntimeException JavaDoc re) {
226                             // BeanContext does not document what might be thrown
227
// from this method, but in fact BeanContextSupport
228
// can throw IllegalStateException if either child or
229
// parent refuses the deletion. So better deal with it.
230
Logger.getLogger(BeanChildren.class.getName()).log(Level.WARNING, null, re);
231                         }
232                     }
233                 }
234             }
235         }
236     }
237 }
238
Popular Tags