2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
41
package org.openide.nodes;
44
import java.beans.IntrospectionException;
45
import java.beans.beancontext.*;
47
import java.lang.ref.*;
50
import java.util.logging.Level;
51
import java.util.logging.Logger;
54
/** Class that represents bean children of a JavaBeans context.
55
* It listens on the bean context changes and creates nodes for
56
* child beans. By default {@link BeanNode}s are created for all
57
* child beans, but this behaviour can be changed by
58
* providing a different factory to the constructor.
60
* @author Jaroslav Tulach, Jesse Glick
62
public class BeanChildren extends Children.Keys {
63
/** default factory for creation of children */
64
private static final Factory DEFAULT_FACTORY = new BeanFactory();
66
/** Map from nodes some BeanChildren have created, to the beans
67
* they were intended to represent. If a node is deleted, we remove
68
* the bean from its context. The nodes are weakly held, and each
69
* value is a 2-element array of weak references to the bean context
73
private static final java.util.Map<Node,Reference[]> nodes2Beans =
74
new WeakHashMap<Node,Reference[]>(); // Map<Node,Reference<Object>[2]>
76
/** bean context to work on */
77
private BeanContext bean;
79
/** factory for creation of subnodes */
80
private Factory factory;
82
/** context listener */
83
private ContextL contextL;
85
/** Create {@link BeanNode} children based on a Bean context.
86
* @param bean the context
88
public BeanChildren(BeanContext bean) {
89
this(bean, DEFAULT_FACTORY);
92
/** Create children based on a Bean context.
93
* @param bean the context
94
* @param factory a factory to use for creation of child nodes
96
public BeanChildren(BeanContext bean, Factory factory) {
98
this.factory = factory;
101
/** Updates the keys from the bean context.
103
final void updateKeys() {
104
setKeys(bean.toArray());
107
/** Creates a node representant for given bean. Uses factory
109
* @param subbean the bean from bean context
110
* @return node created by the factory
112
protected Node[] createNodes(Object subbean) {
114
if (subbean instanceof BeanContextSupport) {
115
BeanContextSupport bcs = (BeanContextSupport) subbean;
117
if (bean.contains(bcs.getBeanContextPeer()) && (bcs != bcs.getBeanContextPeer())) {
118
// sometimes a BeanContextSupport occures in the list of
119
// beans children even there is its peer. we think that
120
// it is desirable to hide the context if the peer is
126
Node n = factory.createNode(subbean);
128
// #7925: deleting from BeanChildren has no effect
129
synchronized (nodes2Beans) {
130
nodes2Beans.put(n, new Reference[] { new WeakReference<BeanContext>(bean), new WeakReference<Object>(subbean) });
133
n.addNodeListener(contextL);
135
return new Node[] { n };
136
} catch (IntrospectionException ex) {
137
Logger.getLogger(BeanChildren.class.getName()).log(Level.WARNING, null, ex);
143
/* Initializes children and attaches listener to bean context.
145
protected void addNotify() {
146
// attaches a listener to the bean
147
contextL = new ContextL(this);
148
bean.addBeanContextMembershipListener(contextL);
153
/** Removes the listener and does some necessary clean up.
155
protected void removeNotify() {
156
if (contextL != null) {
157
bean.removeBeanContextMembershipListener(contextL);
162
setKeys(java.util.Collections.emptySet());
165
/** Controls which nodes
166
* are created for a child bean.
167
* @see BeanChildren#BeanChildren(BeanContext, BeanChildren.Factory)
169
public static interface Factory {
170
/** Create a node for a child bean.
171
* @param bean the bean
172
* @return the node for the bean
173
* @exception IntrospectionException if the node cannot be created
175
public Node createNode(Object bean) throws IntrospectionException;
178
/** Default factory. Creates BeanNode for each bean
180
private static class BeanFactory extends Object implements Factory {
184
/** @return bean node */
185
public Node createNode(Object bean) throws IntrospectionException {
186
return new BeanNode(bean);
190
/** Context listener.
192
private static final class ContextL extends NodeAdapter implements BeanContextMembershipListener {
193
/** weak reference to the BeanChildren object */
194
private WeakReference<BeanChildren> ref;
200
ContextL(BeanChildren bc) {
201
ref = new WeakReference<BeanChildren>(bc);
204
/** Listener method that is called when a bean is added to
206
* @param bcme event describing the action
208
public void childrenAdded(BeanContextMembershipEvent bcme) {
209
BeanChildren bc = ref.get();
216
/** Listener method that is called when a bean is removed to
218
* @param bcme event describing the action
220
public void childrenRemoved(BeanContextMembershipEvent bcme) {
221
BeanChildren bc = ref.get();
228
public void nodeDestroyed(NodeEvent ev) {
229
Node n = ev.getNode();
232
synchronized (nodes2Beans) {
233
refs = nodes2Beans.get(n);
237
BeanContext bean = (BeanContext) refs[0].get();
240
Object subbean = refs[1].get();
242
if (subbean != null) {
243
// This should in turn cause childrenRemoved to be called...
244
// and the node not to be recreated in the next keys update.
246
bean.remove(subbean);
247
} catch (RuntimeException re) {
248
// BeanContext does not document what might be thrown
249
// from this method, but in fact BeanContextSupport
250
// can throw IllegalStateException if either child or
251
// parent refuses the deletion. So better deal with it.
252
Logger.getLogger(BeanChildren.class.getName()).log(Level.WARNING, null, re);