com.oracle.bedrock.runtime.remote.winrm.WindowsSession Maven / Gradle / Ivy
Show all versions of bedrock-runtime-windows Show documentation
/*
* File: WindowsSession.java
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* The contents of this file are subject to the terms and conditions of
* the Common Development and Distribution License 1.0 (the "License").
*
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the License by consulting the LICENSE.txt file
* distributed with this file, or by consulting https://oss.oracle.com/licenses/CDDL
*
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file LICENSE.txt.
*
* MODIFICATIONS:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*/
package com.oracle.bedrock.runtime.remote.winrm;
import com.microsoft.wsman.shell.CommandLine;
import com.microsoft.wsman.shell.CommandResponse;
import com.microsoft.wsman.shell.DesiredStreamType;
import com.microsoft.wsman.shell.EnvironmentVariable;
import com.microsoft.wsman.shell.EnvironmentVariableList;
import com.microsoft.wsman.shell.Receive;
import com.microsoft.wsman.shell.ReceiveResponse;
import com.microsoft.wsman.shell.Send;
import com.microsoft.wsman.shell.ShellType;
import com.microsoft.wsman.shell.Signal;
import com.microsoft.wsman.shell.StreamType;
import com.oracle.bedrock.Option;
import com.oracle.bedrock.OptionsByType;
import com.oracle.bedrock.lang.StringHelper;
import com.oracle.bedrock.runtime.remote.Authentication;
import org.dmtf.wsman.AttributableDuration;
import org.dmtf.wsman.AttributableURI;
import org.dmtf.wsman.MaxEnvelopeSizeType;
import org.dmtf.wsman.OptionSet;
import org.dmtf.wsman.OptionType;
import org.dmtf.wsman.SelectorSetType;
import org.dmtf.wsman.SelectorType;
import org.w3c.soap.envelope.Body;
import org.w3c.soap.envelope.Envelope;
import org.w3c.soap.envelope.Header;
import org.xmlsoap.ws.addressing.AttributedURI;
import org.xmlsoap.ws.addressing.EndpointReferenceType;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
/**
* This class represents a reference to a WinRS remote
* shell.
*
* Copyright (c) 2015. All Rights Reserved. Oracle Corporation.
* Oracle is a registered trademark of Oracle Corporation and/or its affiliates.
*
* @author Jonathan Knight
*/
public class WindowsSession implements Closeable
{
/**
* The action name for the WS-Man Create action
*/
public static final String ACTION_CREATE = "http://schemas.xmlsoap.org/ws/2004/09/transfer/Create";
/**
* The action name for the WinRM Command action
*/
public static final String ACTION_COMMAND = "http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Command";
/**
* The action name for the WinRM Receive action
*/
public static final String ACTION_RECEIVE = "http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive";
/**
* The action name for the WinRM Signal action
*/
public static final String ACTION_SIGNAL = "http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Signal";
/**
* The action name for the WinRM Delete action
*/
public static final String ACTION_DELETE = "http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete";
/**
* The action name for the WinRM Send action
*/
public static final String ACTION_SEND = "http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Send";
/**
* The action name for the WinRM terminate signal
*/
public static final String SIGNAL_TERM = "http://schemas.microsoft.com/wbem/wsman/1/windows/shell/signal/terminate";
/**
* The WinRM resource URI used in the SOAP envelope
*/
public static final String URI_WINRM_RESOURCE = "http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd";
/**
* The reply-to URI used in the SOAP envelope
*/
public static final String URI_REPLY_TO = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";
/**
* The default port that WinRM listens on
*/
public static final int DEFAULT_WINRM_PORT = 5985;
/**
* The default WinRM url suffix
*/
public static final String WSMAN_PATH = "/wsman";
/**
* The set of {@link OptionsByType} to use to control the session
*/
private OptionsByType optionsByType;
/**
* The {@link SoapConnection} instance to use to send SOAP messages
*/
private SoapConnection connection;
/**
* The reference ID for the remote WinRM shell
*/
private String shellReferenceId;
/**
* The ID of the current command
*/
private String commandId;
/**
* The {@link OutputStreamConnector} for the currently executing command
*/
private OutputStreamConnector outputStreamConnector;
/**
* The {@link InputStreamConnector} for the currently executing command
*/
private InputStreamConnector inputStreamConnector;
/**
* Create a new {@link WindowsSession} that connects to the
* WinRM service on the specified host.
*
* @param connection the {@link SoapConnection} to use to send SOAP messages
* @param options the {@link com.oracle.bedrock.Option}s controlling the session
*/
public WindowsSession(SoapConnection connection,
Option... options)
{
this.connection = connection;
this.optionsByType = OptionsByType.of(options);
}
/**
* Create a new {@link WindowsSession} that connects to the
* WinRM service on the specified host.
*
* @param hostName the host name of the host running the WinRM service
* @param port the port that the WinRM service is listening on
* @param userName the name of the user to use to connect to the WinRM service
* @param authentication the authentication to use to connect to the WinRM
* @param options the {@link Option}s controlling the session
*/
public WindowsSession(String hostName,
int port,
String userName,
Authentication authentication,
Option... options)
{
this(new SoapConnection(hostName, port, WSMAN_PATH, userName, authentication, options), options);
}
/**
* Obtain the {@link SoapConnection} being used by this
* {@link WindowsSession} to send SOAP messages.
*
* @return the {@link SoapConnection} being used by this
* {@link WindowsSession} to send SOAP messages
*/
public SoapConnection getSoapConnection()
{
return connection;
}
/**
* Obtain the ID of the WinRM shell being used by this session.
*
* @return the ID of the WinRM shell being used by this session
*/
public String getShellReferenceId()
{
return shellReferenceId;
}
/**
* Set the reference ID of the currently connected WinRM Shell.
*
* @param id the reference ID of the currently connected WinRM Shell
*/
protected void setShellReferenceId(String id)
{
this.shellReferenceId = id;
}
/**
* Obtain the ID of the currently executing command.
*
* @return the ID of the currently executing command
*/
public String getCommandId()
{
return commandId;
}
/**
* Set the ID of the currently executing command.
*
* @param commandId the ID of the currently
* executing command
*/
protected void setCommandId(String commandId)
{
this.commandId = commandId;
}
/**
* Obtain the {@link InputStreamConnector} that connects the
* current command stdin stream.
*
* @return the {@link InputStreamConnector} that connects the
* current command stdin stream
*/
protected InputStreamConnector getInputStreamConnector()
{
return inputStreamConnector;
}
/**
* Set the {@link InputStreamConnector} that connects the
* current command stdin stream.
*
* @param inputStreamConnector the {@link InputStreamConnector}
* that connects the current command
* stdin stream
*/
protected void setInputStreamConnector(InputStreamConnector inputStreamConnector)
{
this.inputStreamConnector = inputStreamConnector;
}
protected OutputStreamConnector getOutputStreamConnector()
{
return outputStreamConnector;
}
protected void setOutputStreamConnector(OutputStreamConnector outputStreamConnector)
{
this.outputStreamConnector = outputStreamConnector;
}
/**
* Close this {@link WindowsSession}.
*/
@Override
public void close()
{
if (shellReferenceId == null)
{
return;
}
try
{
// Terminate the current command if one is running
try
{
terminateCommand();
}
catch (Exception e)
{
e.printStackTrace();
}
// Delete the current Shell
try
{
connection.send(createEnvelope(ACTION_DELETE));
}
catch (IOException e)
{
e.printStackTrace();
}
}
finally
{
commandId = null;
shellReferenceId = null;
}
}
/**
* Connect this {@link WindowsSession} to the remote Windows
* platform. The working directory will be the users home
* directory.
*
* @throws Exception if the connection fails
*/
protected void connect() throws Exception
{
connect(null);
}
/**
* Connect this {@link WindowsSession} to the remote Windows
* platform. The working directory will be the specified
* directory.
*
* @param workingDirectory the working directory for this session
*
* @throws Exception if the connection fails
*/
protected void connect(String workingDirectory) throws Exception
{
connect(workingDirectory, null);
}
/**
* Connect this {@link WindowsSession} to the remote Windows
* platform. The working directory will be the specified
* directory.
*
* @param workingDirectory the working directory for this session
* @param environment the environment variables to set for the
* session
*
* @throws IOException if the connection fails
* @throws IllegalStateException if this session is already connected
*/
protected void connect(String workingDirectory,
Properties environment) throws IOException
{
if (shellReferenceId != null)
{
throw new IllegalStateException("Already connected to shell " + shellReferenceId);
}
WindowsShellOptions shellOptions = optionsByType.getOrSetDefault(WindowsShellOptions.class,
WindowsShellOptions.basic());
ShellType shellType = ObjectFactories.SHELL.createShellType();
if (workingDirectory == null || workingDirectory.isEmpty())
{
shellType.setWorkingDirectory("%USERPROFILE%");
}
else
{
shellType.setWorkingDirectory(workingDirectory);
}
shellType.setLifetime(shellOptions.getShellLifetime());
shellType.getInputStreams().add("stdin");
shellType.getOutputStreams().add("stdout");
shellType.getOutputStreams().add("stderr");
if (environment != null && environment.size() > 0)
{
EnvironmentVariableList environmentVariableList = ObjectFactories.SHELL.createEnvironmentVariableList();
List variables = environmentVariableList.getVariable();
for (String name : environment.stringPropertyNames())
{
EnvironmentVariable variable = ObjectFactories.SHELL.createEnvironmentVariable();
variable.setName(name);
variable.setValue(StringHelper.doubleQuoteIfNecessary(environment.getProperty(name)));
variables.add(variable);
}
shellType.setEnvironment(environmentVariableList);
}
AttributedURI toURI = ObjectFactories.ADDRESSING.createAttributedURI();
toURI.setValue(connection.getUrl().toExternalForm());
Properties properties = shellOptions.getBuilder().realize();
OptionSet optionSet = ObjectFactories.WSMAN.createOptionSet();
List optionsList = optionSet.getOption();
for (String name : properties.stringPropertyNames())
{
OptionType optionType = ObjectFactories.WSMAN.createOptionType();
optionType.setName(name);
optionType.setValue(properties.getProperty(name));
optionsList.add(optionType);
}
Envelope envelope = createEnvelope(ACTION_CREATE);
Header header = envelope.getHeader();
List