/*******************************************************************************
* Copyright (c) 2011 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.kie.eclipse.navigator.view.content;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.wst.server.core.IServer;
import org.kie.eclipse.server.IKieResourceHandler;
public abstract class ContainerNode<T extends IContainerNode<?>> extends ContentNode<T> implements IContainerNode<T> {
private IErrorNode error;
protected List<? extends IKieResourceHandler> handlerChildren;
protected List<? extends IContentNode<?>> children;
protected ContainerNode(String name) {
super(name);
}
protected ContainerNode(T parent, IKieResourceHandler handler) {
super(parent, handler);
}
@Override
public boolean hasChildren() {
return isResolved();
}
@Override
public List<? extends IContentNode<?>> getChildren() {
if (error != null) {
return Collections.singletonList(error);
}
if (handlerChildren!=null) {
// The Java Content Provider, which is included as a <contextExtension>
// in our Kie Navigator Viewer's content binding (see plugin.xml),
// will periodically (every 10 seconds or so) force a refresh of the
// entire viewer. This forces potentially many REST calls to the server
// to rebuild the entire tree. In order to avoid this, we set a Part
// Property on the Navigator to signal when a refresh was triggered
// as a result of a real change in the tree caused by user actions.
// The Part Property value is set to "true" in ContentNode.refresh()
// just before refreshing the Navigator viewer, and then back to "false"
// when done. This allows {@code #createChildren()} to be called only
// when necessary.
String internalRefresh = getNavigator().getProperty(INTERNAL_REFRESH_KEY);
if (children==null || Boolean.getBoolean(internalRefresh)==true)
children = updateChildren(children, createChildren());
return children;
}
return null;
}
protected abstract List<? extends IContentNode<?>> createChildren();
@Override
public final void clearChildren() {
clearError();
clearHandlerChildren();
if (children!=null) {
for (IContentNode<?> n : children)
n.dispose();
children.clear();
children = null;
}
}
public final void clearHandlerChildren() {
if (handlerChildren!=null) {
for (IKieResourceHandler h : handlerChildren)
h.dispose();
handlerChildren.clear();
handlerChildren = null;
}
}
protected void setError(IErrorNode error) {
clearError();
this.error = error;
}
@Override
public void dispose() {
clearChildren();
super.dispose();
}
@Override
public final void load() {
if (getServer().getServerState() != IServer.STATE_STARTED) {
setError(new ErrorNode(this, "Not connected"));
return;
}
try {
handlerChildren = getHandler().getChildren();
clearError();
} catch (Exception e) {
setError(new ErrorNode(this, e));
}
}
@SuppressWarnings("unchecked")
public static List<? extends IContentNode<?>> updateChildren(List<? extends IContentNode<?>> children, List<? extends IContentNode<?>> newChildren) {
if (children==null)
children = newChildren;
else {
List<IContentNode<?>> removed = new ArrayList<IContentNode<?>>();
Iterator<? extends IContentNode<?>> newIter = newChildren.iterator();
while (newIter.hasNext()) {
IContentNode<?> newChild = newIter.next();
boolean found = false;
Iterator<? extends IContentNode<?>> oldIter = children.iterator();
while (oldIter.hasNext()) {
IContentNode<?> oldChild = oldIter.next();
if (oldChild.equals(newChild)) {
newChild.dispose();
found = true;
break;
}
}
if (!found) {
((List<IContentNode<?>>)children).add(newChild);
}
}
Iterator<? extends IContentNode<?>> oldIter = children.iterator();
while (oldIter.hasNext()) {
IContentNode<?> oldChild = oldIter.next();
boolean found = false;
Iterator<? extends IContentNode<?>> newIter2 = newChildren.iterator();
while (newIter2.hasNext()) {
IContentNode<?> newChild = newIter2.next();
if (oldChild.equals(newChild)) {
found = true;
break;
}
}
if (!found) {
removed.add(oldChild);
oldChild.dispose();
}
}
children.removeAll(removed);
}
Collections.sort(children);
return children;
}
private void clearError() {
if (error != null) {
error.dispose();
error = null;
}
}
}