/******************************************************************************* * Copyright (c) 2014 Wind River Systems, Inc. and others. All rights reserved. * This program and the accompanying materials are 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: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.tcf.te.tcf.locator.nodes; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.core.runtime.Assert; import org.eclipse.tcf.protocol.IPeer; import org.eclipse.tcf.protocol.Protocol; import org.eclipse.tcf.te.runtime.model.ContainerModelNode; import org.eclipse.tcf.te.runtime.model.contexts.AsyncRefreshableCtxAdapter; import org.eclipse.tcf.te.runtime.model.interfaces.IModelNode; import org.eclipse.tcf.te.runtime.model.interfaces.contexts.IAsyncRefreshableCtx; import org.eclipse.tcf.te.runtime.model.interfaces.contexts.IAsyncRefreshableCtx.QueryState; import org.eclipse.tcf.te.runtime.model.interfaces.contexts.IAsyncRefreshableCtx.QueryType; import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.ILocatorModel; import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.ILocatorNode; import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerNodeProperties; import org.eclipse.tcf.te.tcf.locator.interfaces.services.ILocatorModelRefreshService; import org.eclipse.tcf.te.tcf.locator.model.ModelManager; /** * Default locator node implementation. */ public class LocatorNode extends ContainerModelNode implements ILocatorNode { // Locator nodes needs asynchronous refreshes private final IAsyncRefreshableCtx refreshableCtxAdapter = new AsyncRefreshableCtxAdapter(); /** * Constructor. */ public LocatorNode(IPeer peer, boolean isStatic) { super(); Assert.isNotNull(peer); // Set the default properties before enabling the change events. // The properties changed listeners should not be called from the // constructor. setProperty(IPeerNodeProperties.PROPERTY_INSTANCE, peer); setProperty(ILocatorNode.PROPERTY_STATIC_INSTANCE, isStatic ? peer : null); PendingOperationNode pendingNode = new PendingOperationNode(); pendingNode.setParent(this); refreshableCtxAdapter.setPendingOperationNode(pendingNode); // Enable change events setChangeEventsEnabled(true); } /** * Constructor. * * @param peer The peer. Must not be <code>null</code>. */ public LocatorNode(IPeer peer) { this(peer, false); } /* (non-Javadoc) * @see org.eclipse.tcf.te.runtime.model.ContainerModelNode#add(org.eclipse.tcf.te.runtime.model.interfaces.IModelNode) */ @Override public boolean add(IModelNode node) { return super.add(node); } /* (non-Javadoc) * @see org.eclipse.tcf.te.runtime.properties.PropertiesContainer#checkThreadAccess() */ @Override protected final boolean checkThreadAccess() { return Protocol.isDispatchThread(); } /* (non-Javadoc) * @see org.eclipse.tcf.te.tcf.locator.interfaces.nodes.ILocatorNode#isDiscovered() */ @Override public boolean isDiscovered() { final AtomicBoolean isDiscovered = new AtomicBoolean(false); Protocol.invokeAndWait(new Runnable() { @Override public void run() { isDiscovered.set(getProperty(PROPERTY_STATIC_INSTANCE) != getProperty(IPeerNodeProperties.PROPERTY_INSTANCE)); } }); return isDiscovered.get(); } /* (non-Javadoc) * @see org.eclipse.tcf.te.tcf.locator.interfaces.nodes.ILocatorNode#isStatic() */ @Override public boolean isStatic() { final AtomicBoolean isStatic = new AtomicBoolean(false); Protocol.invokeAndWait(new Runnable() { @Override public void run() { isStatic.set(getProperty(PROPERTY_STATIC_INSTANCE) != null); } }); return isStatic.get(); } /* (non-Javadoc) * @see org.eclipse.tcf.te.tcf.locator.interfaces.nodes.ILocatorNode#getPeer() */ @Override public IPeer getPeer() { return (IPeer)getAdapter(IPeer.class); } /* (non-Javadoc) * @see org.eclipse.tcf.te.tcf.locator.interfaces.nodes.ILocatorNode#getPeers() */ @Override public IPeer[] getPeers() { List<IPeer> peers = new ArrayList<IPeer>(); for (ILocatorNode locatorNode : getChildren(ILocatorNode.class)) { peers.add(locatorNode.getPeer()); } return peers.toArray(new IPeer[peers.size()]); } /* (non-Javadoc) * @see org.eclipse.tcf.te.runtime.model.ModelNode#getName() */ @Override public String getName() { return getPeer().getName(); } /* (non-Javadoc) * @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class) */ @Override public Object getAdapter(final Class adapter) { // NOTE: The getAdapter(...) method can be invoked from many place and // many threads where we cannot control the calls. Therefore, this // method is allowed be called from any thread. final AtomicReference<Object> object = new AtomicReference<Object>(); Runnable runnable = new Runnable() { @Override public void run() { object.set(doGetAdapter(adapter)); } }; if (Protocol.isDispatchThread()) { runnable.run(); } else { Protocol.invokeAndWait(runnable); } return object.get() != null ? object.get() : super.getAdapter(adapter); } /** * Returns an object which is an instance of the given class associated with this object. * Returns <code>null</code> if no such object can be found. * <p> * This method must be called within the TCF dispatch thread! * * @param adapter The adapter class to look up. * @return The adapter or <code>null</code>. */ protected Object doGetAdapter(Class<?> adapter) { Assert.isTrue(checkThreadAccess(), "Illegal Thread Access"); //$NON-NLS-1$ if (ILocatorModel.class.isAssignableFrom(adapter)) { return ModelManager.getLocatorModel(); } if (IAsyncRefreshableCtx.class.isAssignableFrom(adapter)) { return refreshableCtxAdapter; } Object peer = getProperty(IPeerNodeProperties.PROPERTY_INSTANCE); // Check with adapter.isAssignableFrom(...) to return the peer instance // correctly if adapter is IPeer.class. if (peer != null && adapter.isAssignableFrom(peer.getClass())) { return peer; } return null; } /* (non-Javadoc) * @see org.eclipse.tcf.te.runtime.properties.PropertiesContainer#toString() */ @Override public String toString() { final StringBuilder buffer = new StringBuilder(getClass().getSimpleName()); Runnable runnable = new Runnable() { @Override public void run() { IPeer peer = getPeer(); buffer.append(": id=" + peer.getID()); //$NON-NLS-1$ buffer.append(", name=" + peer.getName()); //$NON-NLS-1$ } }; if (Protocol.isDispatchThread()) { runnable.run(); } else { Protocol.invokeAndWait(runnable); } buffer.append(", " + super.toString()); //$NON-NLS-1$ return buffer.toString(); } /* (non-Javadoc) * @see org.eclipse.tcf.te.runtime.model.ContainerModelNode#hasChildren() */ @Override public boolean hasChildren() { QueryState ctxQuery = refreshableCtxAdapter.getQueryState(QueryType.CONTEXT); QueryState childQuery = refreshableCtxAdapter.getQueryState(QueryType.CHILD_LIST); if (ctxQuery == QueryState.IN_PROGRESS || ctxQuery == QueryState.PENDING) { return true; } if (childQuery == QueryState.IN_PROGRESS || childQuery == QueryState.PENDING) { return true; } return super.hasChildren(); } /* (non-Javadoc) * @see org.eclipse.tcf.te.runtime.model.ContainerModelNode#getChildren() */ @Override public IModelNode[] getChildren() { List<IModelNode> children = getChildren(IModelNode.class); QueryState ctxQuery = refreshableCtxAdapter.getQueryState(QueryType.CONTEXT); QueryState childQuery = refreshableCtxAdapter.getQueryState(QueryType.CHILD_LIST); if (ctxQuery == QueryState.PENDING || childQuery == QueryState.PENDING) { Protocol.invokeLater(new Runnable() { @Override public void run() { ILocatorModelRefreshService service = ModelManager.getLocatorModel().getService(ILocatorModelRefreshService.class); service.refresh(LocatorNode.this, null); } }); children.add(refreshableCtxAdapter.getPendingOperationNode()); } if (ctxQuery == QueryState.IN_PROGRESS || childQuery == QueryState.IN_PROGRESS) { children.add(refreshableCtxAdapter.getPendingOperationNode()); } return children.toArray(new IModelNode[children.size()]); } }