/**
* 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;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import com.palantir.giraffe.command.ExecutionSystem;
import com.palantir.giraffe.command.ExecutionSystems;
import com.palantir.giraffe.host.HostAccessors;
import com.palantir.giraffe.host.HostControlSystem;
import com.palantir.giraffe.host.HostControlSystemUpgradeable;
/**
* Creates {@link HostControlSystem} instances from {@link FileSystem} and
* {@link ExecutionSystem} instances.
* <p>
* Converting one system to another does not affect the original system. The new
* system is an always-open view of the original system. Calling {@code close()}
* has no effect and closing the source system closes all views.
* <p>
* Where possible, the new view minimizes resource duplication, reusing
* connections or other state that is safely shared.
* <p>
* Not all file systems and execution systems can be upgraded to
* {@code HostControlSystem}s. If a conversion is not possible, methods in this
* class throw {@code UnsupportedOperationException}. Upgrading the default
* systems of either type is always supported. See provider-specific
* documentation for details about the compatibility of other system
* implementations.
*
* @author bkeyes
*
* @see HostControlSystemUpgradeable
*/
public class SystemUpgrader {
private static final Upgrader<FileSystem> fsUpgrader =
new Upgrader<>(FileSystems.getDefault());
private static final Upgrader<ExecutionSystem> esUpgrader =
new Upgrader<>(ExecutionSystems.getDefault());
/**
* Returns an open {@link HostControlSystem} that accesses the same
* resources as the given execution system. The execution system is not
* modified.
* <p>
* The new system can read and modify the same files that are accessible to
* commands executed by the execution system. Changes made by one system are
* visible to the other, given certain system-dependent conditions are true.
* In particular, no guarantees are made for concurrent modification or
* modifications from different threads.
*
* @param es the execution system
*
* @return an open {@code HostControlSystem}
*
* @throws IOException if an I/O error occurs while creating the system
* @throws UnsupportedOperationException if the execution system does not
* support upgrades
*/
public static HostControlSystem upgrade(ExecutionSystem es) throws IOException {
return esUpgrader.upgrade(es);
}
/**
* Returns an open {@link HostControlSystem} that accesses the same
* resources as the given file system. The file system is not modified.
* <p>
* Commands executed by the new system can read and modify the same files
* that are accessible by the file system. Changes made by one system are
* visible to the other, given certain system-dependent conditions are true.
* In particular, no guarantees are made for concurrent modification or
* modifications from different threads.
*
* @param fs the file system
*
* @return an open {@code HostControlSystem}
*
* @throws IOException if an I/O error occurs while creating the system
* @throws UnsupportedOperationException if the file system does not support
* upgrades
*/
public static HostControlSystem upgrade(FileSystem fs) throws IOException {
return fsUpgrader.upgrade(fs);
}
/**
* Returns {@code true} if the given file system can be upgrade to a host
* control system.
*/
public static boolean isUpgradeable(FileSystem fs) {
return fsUpgrader.isUpgradeable(fs);
}
/**
* Returns {@code true} if the given execution system can be upgraded to a
* host control system.
*/
public static boolean isUpgradeable(ExecutionSystem es) {
return esUpgrader.isUpgradeable(es);
}
private static final class Upgrader<S> {
private final S defaultSystem;
Upgrader(S defaultSystem) {
this.defaultSystem = defaultSystem;
}
public boolean isUpgradeable(S system) {
checkNotNull(system, "system must be non-null");
return defaultSystem.equals(system) || system instanceof HostControlSystemUpgradeable;
}
public HostControlSystem upgrade(S system) throws IOException {
checkNotNull(system, "system must be non-null");
if (!isUpgradeable(system)) {
String msg = system.getClass().getName() + " is not upgradeable";
throw new UnsupportedOperationException(msg);
}
if (system.equals(defaultSystem)) {
return HostAccessors.getDefault().open();
} else {
return ((HostControlSystemUpgradeable) system).asHostControlSystem();
}
}
}
private SystemUpgrader() {
throw new UnsupportedOperationException();
}
}