/** * Copyright 2015 Palantir Technologies, Inc. * * Licensed 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 com.palantir.giraffe.ssh.internal; import static com.google.common.base.Preconditions.checkNotNull; import java.io.IOException; import java.nio.file.FileSystems; import com.palantir.giraffe.command.ExecutionSystems; import com.palantir.giraffe.host.AbstractHostControlSystem; import com.palantir.giraffe.host.HostControlSystem; import com.palantir.giraffe.ssh.SshSystemRequest; import net.schmizz.sshj.DefaultConfig; /** * A {@link HostControlSystem} implementation that uses the SSH protocol. * * @author bkeyes */ public final class SshHostControlSystem extends AbstractHostControlSystem { private static final class ConnectionFactoryHolder { private static final SshConnectionFactory factory = newFactory(); private static SshConnectionFactory newFactory() { return new SshConnectionFactory(new DefaultConfig()); } } public static Builder builder(SshSystemRequest request) throws IOException { // even if request has the right type, we want a copy here InternalSshSystemRequest internalRequest = new InternalSshSystemRequest(request); internalRequest.setSource(SshHostControlSystem.class); CloseContext closeContext = new CloseContext(); internalRequest.setCloseContext(closeContext); if (internalRequest.setClientIfMissing(ConnectionFactoryHolder.factory)) { closeContext.registerCloseable(internalRequest.getClient(), Integer.MAX_VALUE); } return new Builder(internalRequest); } /** * Builds {@code SshHostControlSystem} instances. */ public static final class Builder { private final InternalSshSystemRequest request; private SshFileSystem fs; private SshExecutionSystem es; private Builder(InternalSshSystemRequest request) { this.request = request; } public Builder setFileSystem(SshFileSystemProvider provider) { fs = new SshFileSystem(provider, request); return this; } public Builder setFileSystem() throws IOException { fs = (SshFileSystem) FileSystems.newFileSystem( request.fileSystemUri(), request.options(), getClass().getClassLoader()); return this; } public Builder setExecutionSystem(SshExecutionSystemProvider provider) { es = new SshExecutionSystem(provider, request); return this; } public Builder setExecutionSystem() throws IOException { es = (SshExecutionSystem) ExecutionSystems.newExecutionSystem( request.executionSystemUri(), request.options(), getClass().getClassLoader()); return this; } public SshHostControlSystem build() { checkNotNull(fs, "file system not set"); checkNotNull(es, "execution system not set"); SshHostControlSystem system = new SshHostControlSystem(this); fs.setSourceSystem(system); es.setSourceSystem(system); return system; } } private final CloseContext closeContext; private SshHostControlSystem(Builder builder) { super(builder.request.uri(), builder.fs, builder.es); this.closeContext = builder.request.getCloseContext(); } @Override public void close() throws IOException { closeContext.close(); } public HostControlSystem asView() { return new View(this); } private static class View extends AbstractHostControlSystem { View(SshHostControlSystem source) { super(source.uri(), source.getFileSystem(), source.getExecutionSystem()); } @Override public void close() { // do nothing } } }