org.openide.nodes.EntrySupportLazyState Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.openide.nodes;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import org.openide.nodes.Children.Entry;
import org.openide.util.Utilities;
/** This class should represent an immutable state of a EntrySupportLazy instance.
*
* @author Jaroslav Tulach
*/
final class EntrySupportLazyState {
static final EntrySupportLazyState UNINITIALIZED = new EntrySupportLazyState();
private EntrySupportLazyState() {
this(
false, null, false, false,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyMap()
);
}
private EntrySupportLazyState(
boolean inited,
Thread initThread,
boolean initInProgress,
boolean mustNotifySetEntries,
List entries,
List visibleEntries,
Map entryToInfo
) {
this.inited = inited;
this.initThread = initThread;
this.initInProgress = initInProgress;
this.mustNotifySetEntries = mustNotifySetEntries;
this.entries = entries;
this.visibleEntries = visibleEntries;
this.entryToInfo = entryToInfo;
}
private final boolean inited;
private final Thread initThread;
private final boolean initInProgress;
private final boolean mustNotifySetEntries;
private final List entries;
private final List visibleEntries;
private final Map entryToInfo;
final boolean isInited() {
return inited;
}
final boolean isInitInProgress() {
return initInProgress;
}
final Thread initThread() {
return initThread;
}
final boolean isMustNotify() {
return mustNotifySetEntries;
}
final List getEntries() {
return Collections.unmodifiableList(entries);
}
final List getVisibleEntries() {
return Collections.unmodifiableList(visibleEntries);
}
final Map getEntryToInfo() {
return Collections.unmodifiableMap(entryToInfo);
}
private EntrySupportLazyState cloneState() {
try {
return (EntrySupportLazyState)clone();
} catch (CloneNotSupportedException ex) {
throw new IllegalStateException(ex);
}
}
final EntrySupportLazyState changeInited(boolean newInited) {
return new EntrySupportLazyState(
newInited, initThread,
initInProgress, mustNotifySetEntries,
entries, visibleEntries, entryToInfo
);
}
final EntrySupportLazyState changeThread(Thread t) {
return new EntrySupportLazyState(
inited, t,
initInProgress, mustNotifySetEntries,
entries, visibleEntries, entryToInfo
);
}
final EntrySupportLazyState changeProgress(boolean b) {
return new EntrySupportLazyState(
inited, initThread,
b, mustNotifySetEntries,
entries, visibleEntries, entryToInfo
);
}
final EntrySupportLazyState changeMustNotify(boolean b) {
return new EntrySupportLazyState(
inited, initThread,
initInProgress, b,
entries, visibleEntries, entryToInfo
);
}
final EntrySupportLazyState changeEntries(
List entries,
List visibleEntries,
Map entryToInfo
) {
if (entries == null) {
entries = this.entries;
}
if (visibleEntries == null) {
visibleEntries = this.visibleEntries;
}
if (entryToInfo == null) {
entryToInfo = this.entryToInfo;
}
EntrySupportLazyState state = new EntrySupportLazyState(
inited, initThread,
initInProgress, mustNotifySetEntries,
entries, visibleEntries, entryToInfo
);
int entriesSize = 0;
int entryToInfoSize = 0;
assert (entriesSize = state.getEntries().size()) >= 0;
assert (entryToInfoSize = state.getEntryToInfo().size()) >= 0;
assert state.getEntries().size() == state.getEntryToInfo().size() : "Entries: " + state.getEntries().size() + "; vis. entries: " + EntrySupportLazy.notNull(state.getVisibleEntries()).size() + "; Infos: " + state.getEntryToInfo().size() + "; entriesSize: " + entriesSize + "; entryToInfoSize: " + entryToInfoSize + EntrySupportLazy.dumpEntriesInfos(state.getEntries(), state.getEntryToInfo()); // NOI18N
return state;
}
@Override
public String toString() {
int entriesSize = getEntries().size();
int entryToInfoSize = getEntryToInfo().size();
return
"Inited: " + inited +
"\nThread: " + initThread +
"\nInProgress: " + initInProgress +
"\nMustNotify: " + mustNotifySetEntries +
"\nEntries: " + getEntries().size() + "; vis. entries: " +
EntrySupportLazy.notNull(getVisibleEntries()).size() + "; Infos: " +
getEntryToInfo().size() + "; entriesSize: " +
entriesSize + "; entryToInfoSize: " + entryToInfoSize +
EntrySupportLazy.dumpEntriesInfos(getEntries(), getEntryToInfo());
}
static final class EntryInfo {
private final EntrySupportLazy lazy;
private final Entry entry;
/**
* my index in list of entries
*/
private final int index;
/**
* cached node for this entry
*/
private NodeRef refNode;
/** reference to thread which is just creating the node for this info */
Thread creatingNodeThread;
public EntryInfo(EntrySupportLazy lazy, Entry entry) {
this(lazy, entry, -1, (NodeRef)null);
}
private EntryInfo(EntrySupportLazy lazy, Entry entry, int index, NodeRef refNode) {
this.lazy = lazy;
this.entry = entry;
this.index = index;
this.refNode = refNode;
}
private EntryInfo(EntrySupportLazy lazy, Entry entry, int index, Node refNode) {
this.lazy = lazy;
this.entry = entry;
this.index = index;
this.refNode = new NodeRef(refNode, this);
}
final EntryInfo changeNode(Node node) {
if (node != null) {
return new EntryInfo(lazy, entry, index, node);
} else {
return new EntryInfo(lazy, entry, index, refNode);
}
}
final EntryInfo changeIndex(int index) {
return new EntryInfo(lazy, entry, index, refNode);
}
final EntrySupportLazy lazy() {
return lazy;
}
final Entry entry() {
return entry;
}
private Object lock() {
return lazy.LOCK;
}
/**
* Gets or computes the nodes. It holds them using weak reference so
* they can get garbage collected.
*/
public final Node getNode() {
return getNode(false, null);
}
public final Node getNode(boolean refresh, Object source) {
while (true) {
Node node;
boolean creating = false;
synchronized (lock()) {
if (refresh) {
refNode = null;
}
if (refNode != null) {
node = refNode.get();
if (node != null) {
return node;
}
}
if (creatingNodeThread != null) {
if (creatingNodeThread == Thread.currentThread()) {
return new EntrySupportLazy.DummyNode();
}
try {
lock().wait();
} catch (InterruptedException ex) {
}
} else {
creatingNodeThread = Thread.currentThread();
creating = true;
}
}
Collection nodes = Collections.emptyList();
try {
if (creating) {
try {
nodes = entry.nodes(source);
} catch (RuntimeException ex) {
NodeOp.warning(ex);
}
}
} finally {
synchronized (lock()) {
if (!creating) {
if (refNode != null) {
node = refNode.get();
if (node != null) {
return node;
}
}
// node created by other thread was GCed meanwhile, try once again
continue;
}
if (nodes.isEmpty()) {
node = new EntrySupportLazy.DummyNode();
} else {
if (nodes.size() > 1) {
EntrySupportLazy.LOGGER.log(Level.FINE,
"Number of nodes for Entry: {0} is {1} instead of 1", // NOI18N
new Object[]{entry, nodes.size()}
);
}
node = nodes.iterator().next();
}
refNode = new NodeRef(node, this);
if (creating) {
creatingNodeThread = null;
lock().notifyAll();
}
}
}
final Children ch = lazy().children;
// assign node to the new children
node.assignTo(ch, -1);
node.fireParentNodeChange(null, ch.parent);
return node;
}
}
/**
* extract current node (if was already created)
*/
Node currentNode() {
synchronized (lock()) {
return refNode == null ? null : refNode.get();
}
}
final boolean isHidden() {
return this.index == -2;
}
/**
* Get index.
*/
final int getIndex() {
assert index >= 0 : "When first asked for it has to be set: " + index; // NOI18N
return index;
}
@Override
public String toString() {
return "EntryInfo for entry: " + entry + ", node: " + (refNode == null ? null : refNode.get()); // NOI18N
}
}
private static final class NodeRef extends WeakReference implements Runnable {
private final EntryInfo info;
public NodeRef(Node node, EntryInfo info) {
super(node, Utilities.activeReferenceQueue());
info.lazy().registerNode(1, info);
this.info = info;
}
@Override
public void run() {
info.lazy().registerNode(-1, info);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy