001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.openide.nodes;
042:
043: import java.lang.ref.Reference;
044: import java.util.*;
045: import java.util.logging.Level;
046: import java.util.logging.Logger;
047:
048: /** Holder of nodes for a children object. Communicates
049: * with children to notify when created/finalized.
050: *
051: * @author Jaroslav Tulach
052: */
053: final class ChildrenArray extends NodeAdapter {
054: /** children */
055: public Children children;
056:
057: /** nodes associated */
058: private Node[] nodes;
059:
060: private Map<Children.Info, Collection<Node>> map;
061: /** the reference that points to us */
062: private Reference<ChildrenArray> ref;
063:
064: private static final Logger LOG_NODES_FOR = Logger
065: .getLogger("org.openide.nodes.ChildrenArray.nodesFor"); // NOI18N
066:
067: /** Creates new ChildrenArray */
068: public ChildrenArray() {
069: }
070:
071: public Children getChildren() {
072: return children;
073: }
074:
075: /** When finalized notify the children.
076: */
077: protected void finalize() {
078: children.finalizedChildrenArray(ref);
079: }
080:
081: /** Now points to me */
082: final void pointedBy(Reference<ChildrenArray> ref) {
083: this .ref = ref;
084: }
085:
086: /** Getter method to receive a set of computed nodes.
087: */
088: public Node[] nodes() {
089: if (children == null) {
090: // not fully initialize
091: return null;
092: }
093:
094: if (nodes == null) {
095: nodes = children.justComputeNodes();
096:
097: for (int i = 0; i < nodes.length; i++) {
098: // keeps a hard reference from the children node to this
099: // so we can be GCed only when child nodes are gone
100: nodes[i].reassignTo(children, this );
101: }
102:
103: // if at least one node => be weak
104: children.registerChildrenArray(this , nodes.length > 0);
105: }
106:
107: return nodes;
108: }
109:
110: /** Clears the array of nodes.
111: */
112: public void clear() {
113: if (nodes != null) {
114: nodes = null;
115:
116: // register in the childrens to be hold by hard reference
117: // because we keep no reference to nodes, we can be
118: // hard holded by children
119: children.registerChildrenArray(this , false);
120: }
121: }
122:
123: /** Finalizes nodes by calling get on weak hash map,
124: * all references stored in the map, that are finalized
125: * will be cleared.
126: */
127: public void finalizeNodes() {
128: Map m = map;
129:
130: if (m != null) {
131: // processes the queue of garbage
132: // collected keys
133: m.remove(null);
134: }
135: }
136:
137: /** Initilized if has some nodes.
138: */
139: public boolean isInitialized() {
140: return nodes != null;
141: }
142:
143: private String logInfo(Children.Info info) {
144: return info.toString() + '['
145: + Integer.toHexString(System.identityHashCode(info))
146: + ']';
147: }
148:
149: /** Gets the nodes for given info.
150: * @param info the info
151: * @return the nodes
152: */
153: public synchronized Collection<Node> nodesFor(Children.Info info) {
154: final boolean IS_LOG = LOG_NODES_FOR.isLoggable(Level.FINE);
155: if (IS_LOG) {
156: LOG_NODES_FOR.fine("nodesFor(" + logInfo(info) + ") on "
157: + Thread.currentThread()); // NOI18N
158: }
159: if (map == null) {
160: map = new WeakHashMap<Children.Info, Collection<Node>>(7);
161: }
162: Collection<Node> nodes = map.get(info);
163:
164: if (IS_LOG) {
165: LOG_NODES_FOR.fine(" map size=" + map.size() + ", nodes="
166: + nodes); // NOI18N
167: }
168:
169: if (nodes == null) {
170: nodes = info.entry.nodes();
171: info.length = nodes.size();
172: map.put(info, nodes);
173: if (IS_LOG) {
174: LOG_NODES_FOR.fine(" created nodes=" + nodes); // NOI18N
175: }
176: }
177:
178: if (IS_LOG) {
179: LOG_NODES_FOR.fine(" leaving nodesFor(" + logInfo(info)
180: + ") on " + Thread.currentThread()); // NOI18N
181: }
182: return nodes;
183: }
184:
185: /** Refreshes the nodes for given info.
186: * @param info the info
187: * @return the nodes
188: */
189: public synchronized void useNodes(Children.Info info,
190: Collection<Node> list) {
191: if (map == null) {
192: map = new WeakHashMap<Children.Info, Collection<Node>>(7);
193: }
194:
195: info.length = list.size();
196:
197: map.put(info, list);
198: }
199:
200: public String toString() {
201: return super .toString() + " " + getChildren(); //NOI18N
202: }
203: }
|