/******************************************************************************* * Copyright (c) 2014, 2015 Wind River Systems, Inc. * 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: * Markus Schorn - initial API and implementation *******************************************************************************/ package org.eclipse.tcf.te.tcf.remote.core.operation; import static java.text.MessageFormat.format; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.tcf.protocol.IChannel; import org.eclipse.tcf.protocol.IChannel.IChannelListener; import org.eclipse.tcf.protocol.IPeer; import org.eclipse.tcf.protocol.IToken; import org.eclipse.tcf.protocol.Protocol; import org.eclipse.tcf.services.IFileSystem; import org.eclipse.tcf.services.IFileSystem.DoneUser; import org.eclipse.tcf.services.IFileSystem.FileSystemException; import org.eclipse.tcf.te.core.interfaces.IConnectable; import org.eclipse.tcf.te.tcf.core.Tcf; import org.eclipse.tcf.te.tcf.core.interfaces.IChannelManager; import org.eclipse.tcf.te.tcf.core.interfaces.IChannelManager.DoneOpenChannel; import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerNode; import org.eclipse.tcf.te.tcf.remote.core.activator.CoreBundleActivator; import org.eclipse.tcf.te.tcf.remote.core.nls.Messages; public final class PeerInfo implements IChannelListener { private IFileSystem fFileSystem; private boolean fPendingOpen; private List<DoneGetFileSystem> fCallbacks = emptyList(); private User fUser; public interface DoneGetFileSystem { void done(IFileSystem fileSystem, IStatus status); } public void getFileSystem(final IPeerNode peerNode, final DoneGetFileSystem callback) { assert Protocol.isDispatchThread(); if (peerNode.getConnectState() != IConnectable.STATE_CONNECTED) { callback.done(null, errorStatus(format(Messages.PeerInfo_errorPeerNotConnected, peerNode.getName()), null)); } else if (fFileSystem != null) { callback.done(fFileSystem, Status.OK_STATUS); } else { openChannel(peerNode, callback); } } public void openChannel(final IPeerNode peerNode, final DoneGetFileSystem callback) { if (fCallbacks.isEmpty()) { fCallbacks = singletonList(callback); } else { if (fCallbacks.size() == 1) { fCallbacks = new ArrayList<DoneGetFileSystem>(fCallbacks); } fCallbacks.add(callback); } if (fPendingOpen) return; // Open the channel fPendingOpen = true; final IPeer peer = peerNode.getPeer(); Map<String, Boolean> flags = new HashMap<String, Boolean>(); flags.put(IChannelManager.FLAG_NO_PATH_MAP, Boolean.TRUE); flags.put(IChannelManager.FLAG_FORCE_NEW, Boolean.TRUE); Tcf.getChannelManager().openChannel(peer, flags, new DoneOpenChannel() { @Override @SuppressWarnings("synthetic-access") public void doneOpenChannel(Throwable error, IChannel channel) { fPendingOpen = false; IStatus fsStatus = Status.OK_STATUS; if (error != null) { fsStatus = errorStatus(format(Messages.PeerInfo_errorCannotOpenChannel, peer.getName()), error); } else { channel.addChannelListener(PeerInfo.this); fFileSystem = channel.getRemoteService(IFileSystem.class); if (fFileSystem == null) { fsStatus = errorStatus(format(Messages.PeerInfo_errorNoFileSystemService, peer.getName()), null); } } for (DoneGetFileSystem callback : fCallbacks) { callback.done(fFileSystem, fsStatus); } } }); } private IStatus errorStatus(String msg, Throwable cause) { return new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), msg, cause); } @Override public void congestionLevel(int level) { } @Override public void onChannelOpened() { } @Override public void onChannelClosed(Throwable error) { // Connection was closed, next time we attempt to open a channel again. fFileSystem = null; fCallbacks = emptyList(); } public interface DoneGetUser { void done(User user, IStatus status); } public final class User { public final int fEffectiveGID; public final int fEffectiveUID; User(int effectiveUID, int effectiveGID) { fEffectiveUID = effectiveUID; fEffectiveGID = effectiveGID; } } public void getUser(final IFileSystem fs, final DoneGetUser callback) { assert Protocol.isDispatchThread(); if (fUser != null) { callback.done(fUser, Status.OK_STATUS); return; } fs.user(new DoneUser() { @Override @SuppressWarnings("synthetic-access") public void doneUser(IToken token, FileSystemException error, int realUID, int effectiveUID, int realGID, int effectiveGID, String home) { if (error != null) { callback.done(null, errorStatus(error.getMessage(), error)); } else { fUser = new User(effectiveUID, effectiveGID); callback.done(fUser, Status.OK_STATUS); } } }); } }