diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/FileSysOperationsFactory.java b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/FileSysOperationsFactory.java index b229aed0c15775ae585f006ca6beba3dd54172c3..bc211e2cdb03e54ba32fce0c39a46cdb8968b454 100644 --- a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/FileSysOperationsFactory.java +++ b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/FileSysOperationsFactory.java @@ -18,6 +18,7 @@ package ch.systemsx.cisd.datamover.filesystem; import java.io.File; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; @@ -49,41 +50,37 @@ public class FileSysOperationsFactory implements IFileSysOperationsFactory private static final Logger notificationLog = LogFactory.getLogger(LogCategory.NOTIFY, FileSysOperationsFactory.class); - final private IFileSysParameters parameters; + private final IFileSysParameters parameters; - public FileSysOperationsFactory(IFileSysParameters parameters) + public FileSysOperationsFactory(final IFileSysParameters parameters) { assert parameters != null; this.parameters = parameters; } - public IPathRemover getRemover() + private final static File findRsyncExecutable(final String rsyncExecutablePath) { - return new RetryingPathRemover(MAX_RETRIES_ON_FAILURE, MILLIS_TO_SLEEP_ON_FAILURE); - } - - public IPathImmutableCopier getImmutableCopier() - { - String lnExec = parameters.getHardLinkExecutable(); - if (lnExec != null) + final File rsyncExecutable; + if (rsyncExecutablePath != null) { - return RecursiveHardLinkMaker.create(lnExec); + rsyncExecutable = new File(rsyncExecutablePath); + } else if (OSUtilities.isWindows() == false) + { + rsyncExecutable = OSUtilities.findExecutable("rsync"); + } else + { + rsyncExecutable = null; } - - IPathImmutableCopier copier = null; - if (OSUtilities.isWindows() == false) + if (rsyncExecutable != null && OSUtilities.executableExists(rsyncExecutable) == false) { - copier = RecursiveHardLinkMaker.tryCreate(); - if (copier != null) - { - return copier; - } + throw ConfigurationFailureException.fromTemplate("Cannot find rsync executable '%s'.", + rsyncExecutable.getAbsoluteFile()); } - return createFakedImmCopier(); + return rsyncExecutable; } - private IPathImmutableCopier createFakedImmCopier() + private final IPathImmutableCopier createFakedImmCopier() { final IPathCopier normalCopier = getCopier(false); return new IPathImmutableCopier() @@ -109,54 +106,56 @@ public class FileSysOperationsFactory implements IFileSysOperationsFactory }; } - public IPathCopier getCopier(boolean requiresDeletionBeforeCreation) + // + // IFileSysOperationsFactory + // + + public final IPathRemover getRemover() { - final File rsyncExecutable = findRsyncExecutable(parameters.getRsyncExecutable()); - final File sshExecutable = findSshExecutable(parameters.getSshExecutable()); - if (rsyncExecutable != null) + return new RetryingPathRemover(MAX_RETRIES_ON_FAILURE, MILLIS_TO_SLEEP_ON_FAILURE); + } + + public final IPathImmutableCopier getImmutableCopier() + { + final String lnExec = parameters.getHardLinkExecutable(); + if (lnExec != null) { - return new RsyncCopier(rsyncExecutable, sshExecutable, requiresDeletionBeforeCreation, - parameters.isRsyncOverwrite()); - } else + return RecursiveHardLinkMaker.create(lnExec); + } + + IPathImmutableCopier copier = null; + if (OSUtilities.isWindows() == false) { - throw new ConfigurationFailureException("Unable to find a copy engine."); + copier = RecursiveHardLinkMaker.tryCreate(); + if (copier != null) + { + return copier; + } } + return createFakedImmCopier(); } - private static File findRsyncExecutable(final String rsyncExecutablePath) + public final IPathCopier getCopier(final boolean requiresDeletionBeforeCreation) { - final File rsyncExecutable; - if (rsyncExecutablePath != null) - { - rsyncExecutable = new File(rsyncExecutablePath); - } else if (OSUtilities.isWindows() == false) + final File rsyncExecutable = findRsyncExecutable(parameters.getRsyncExecutable()); + final File sshExecutable = tryFindSshExecutable(); + if (rsyncExecutable != null) { - rsyncExecutable = OSUtilities.findExecutable("rsync"); + return new RsyncCopier(rsyncExecutable, sshExecutable, requiresDeletionBeforeCreation, + parameters.isRsyncOverwrite()); } else { - rsyncExecutable = null; - } - if (rsyncExecutable != null && OSUtilities.executableExists(rsyncExecutable) == false) - { - throw ConfigurationFailureException.fromTemplate("Cannot find rsync executable '%s'.", - rsyncExecutable.getAbsoluteFile()); + throw new ConfigurationFailureException("Unable to find a copy engine."); } - return rsyncExecutable; } - private static File findSshExecutable(String sshExecutablePath) + public final File tryFindSshExecutable() { - final File sshExecutable; - if (sshExecutablePath != null) + final String sshExecutablePath = parameters.getSshExecutable(); + File sshExecutable = null; + if (StringUtils.isNotBlank(sshExecutablePath)) { - if (sshExecutablePath.length() > 0) - { - sshExecutable = new File(sshExecutablePath); - } else - // Explicitly disable tunneling via ssh on the command line. - { - sshExecutable = null; - } + sshExecutable = new File(sshExecutablePath); } else { sshExecutable = OSUtilities.findExecutable("ssh"); @@ -169,7 +168,7 @@ public class FileSysOperationsFactory implements IFileSysOperationsFactory return sshExecutable; } - public IPathMover getMover() + public final IPathMover getMover() { return new RetryingPathMover(MAX_RETRIES_ON_FAILURE, MILLIS_TO_SLEEP_ON_FAILURE); } diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/IFileSysOperationsFactory.java b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/IFileSysOperationsFactory.java index e7fe4bb220addb486461ea60cb9de932635f5ddc..e1c7a5e9327908fe87db6f0bc8a668bd5136c0ff 100644 --- a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/IFileSysOperationsFactory.java +++ b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/IFileSysOperationsFactory.java @@ -15,6 +15,8 @@ */ package ch.systemsx.cisd.datamover.filesystem.intf; +import java.io.File; + import ch.systemsx.cisd.common.utilities.IPathImmutableCopier; /** @@ -31,4 +33,11 @@ public interface IFileSysOperationsFactory public IPathRemover getRemover(); public IPathMover getMover(); + + /** + * Tries to find the <code>ssh</code> executable. + * + * @return <code>null</code> if not found. + */ + public File tryFindSshExecutable(); } \ No newline at end of file diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreRemote.java b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreRemote.java index 5595f74b7ca490c0f2384ed7a99047bdcd43a6db..1f68aa430c5bdb1258e828ef32eb85329b16a782 100644 --- a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreRemote.java +++ b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreRemote.java @@ -16,16 +16,23 @@ package ch.systemsx.cisd.datamover.filesystem.store; +import java.io.File; + +import org.apache.log4j.Logger; + import ch.systemsx.cisd.common.exceptions.NotImplementedException; import ch.systemsx.cisd.common.exceptions.Status; import ch.systemsx.cisd.common.highwatermark.FileWithHighwaterMark; import ch.systemsx.cisd.common.highwatermark.HighwaterMarkWatcher; import ch.systemsx.cisd.common.logging.ISimpleLogger; +import ch.systemsx.cisd.common.logging.LogCategory; +import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.common.utilities.StoreItem; import ch.systemsx.cisd.datamover.filesystem.intf.FileStore; import ch.systemsx.cisd.datamover.filesystem.intf.IExtendedFileStore; import ch.systemsx.cisd.datamover.filesystem.intf.IFileSysOperationsFactory; import ch.systemsx.cisd.datamover.filesystem.intf.IStoreCopier; +import ch.systemsx.cisd.datamover.utils.RemoteFreeSpaceProvider; /** * @author Tomasz Pylak @@ -34,10 +41,32 @@ import ch.systemsx.cisd.datamover.filesystem.intf.IStoreCopier; // dummy implementation. public class FileStoreRemote extends FileStore { + private static final Logger operationLog = + LogFactory.getLogger(LogCategory.OPERATION, FileStoreRemote.class); + + private final HighwaterMarkWatcher highwaterMarkWatcher; + public FileStoreRemote(final FileWithHighwaterMark path, final String host, final String kind, final IFileSysOperationsFactory factory) { super(path, host, true, kind, factory); + assert host != null : "Unspecified host"; + highwaterMarkWatcher = createHighwaterMarkWatcher(path.getHighwaterMark(), host); + } + + private final HighwaterMarkWatcher createHighwaterMarkWatcher(final long highwaterMark, + final String host) + { + final File sshExecutable = factory.tryFindSshExecutable(); + if (sshExecutable != null) + { + return new HighwaterMarkWatcher(highwaterMark, new RemoteFreeSpaceProvider(host, + sshExecutable)); + } + // We set the "high water mark" to -1, meaning that the system will not be watching. + operationLog.warn("Impossible to remotely watch the 'high water mark' " + + "(ssh executable not found)."); + return new HighwaterMarkWatcher(-1); } // @@ -109,6 +138,7 @@ public class FileStoreRemote extends FileStore public final HighwaterMarkWatcher getHighwaterMarkWatcher() { - throw new NotImplementedException(); + return highwaterMarkWatcher; } + } diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/utils/RemoteFreeSpaceProvider.java b/datamover/source/java/ch/systemsx/cisd/datamover/utils/RemoteFreeSpaceProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..7ef9a2b99009bb678a8a75ae2e0c344927cd314a --- /dev/null +++ b/datamover/source/java/ch/systemsx/cisd/datamover/utils/RemoteFreeSpaceProvider.java @@ -0,0 +1,63 @@ +/* + * Copyright 2008 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.datamover.utils; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import org.apache.log4j.Logger; + +import ch.systemsx.cisd.common.highwatermark.HighwaterMarkWatcher.IFreeSpaceProvider; +import ch.systemsx.cisd.common.process.ProcessExecutionHelper; +import ch.systemsx.cisd.common.process.ProcessResult; + +/** + * An <code>IFreeSpaceProvider</code> implementation for computing the free space on a remote + * computer. + * + * @author Christian Ribeaud + */ +public final class RemoteFreeSpaceProvider implements IFreeSpaceProvider +{ + private final File sshExecutable; + + private final String host; + + public RemoteFreeSpaceProvider(final String host, final File sshExecutable) + { + this.host = host; + this.sshExecutable = sshExecutable; + } + + // + // IFreeSpaceProvider + // + + public final long freeSpaceKb(final File path) throws IOException + { + final List<String> command = + Arrays.asList(sshExecutable.getPath(), host, "df -k " + path.getPath() + ""); + Logger rootLogger = Logger.getRootLogger(); + System.out.println(command); + final ProcessResult processResult = + ProcessExecutionHelper.run(command, 2000L, rootLogger, rootLogger); + System.out.println(processResult.getProcessOutput()); + return 0L; + } +} \ No newline at end of file diff --git a/datamover/sourceTest/java/ch/systemsx/cisd/datamover/utils/RemoteFreeSpaceProviderTest.java b/datamover/sourceTest/java/ch/systemsx/cisd/datamover/utils/RemoteFreeSpaceProviderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fe83da17e08991bc6ec236a590ee0a4d9939e283 --- /dev/null +++ b/datamover/sourceTest/java/ch/systemsx/cisd/datamover/utils/RemoteFreeSpaceProviderTest.java @@ -0,0 +1,45 @@ +/* + * Copyright 2008 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.datamover.utils; + +import static org.testng.AssertJUnit.assertNotNull; + +import java.io.File; +import java.io.IOException; + +import org.testng.annotations.Test; + +import ch.systemsx.cisd.common.utilities.OSUtilities; + +/** + * Test cases for {@link RemoteFreeSpaceProvider}. + * + * @author Christian Ribeaud + */ +public final class RemoteFreeSpaceProviderTest +{ + + @Test(groups = "broken") + public final void testFreeSpaceKb() throws IOException + { + final File sshExecutable = OSUtilities.findExecutable("ssh"); + assertNotNull(sshExecutable); + final RemoteFreeSpaceProvider freeSpaceProvider = + new RemoteFreeSpaceProvider("sprint-ob", sshExecutable); + System.out.println(freeSpaceProvider.freeSpaceKb(new File("/"))); + } +} diff --git a/datamover/temp-testng-customsuite.xml b/datamover/temp-testng-customsuite.xml new file mode 100644 index 0000000000000000000000000000000000000000..8a56dfb8f0fae28722127c9d45dfa6edc1f90975 --- /dev/null +++ b/datamover/temp-testng-customsuite.xml @@ -0,0 +1,8 @@ +<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> +<suite name="datamover"> + <test verbose="2" name="ch.systemsx.cisd.datamover.utils.RemoteFreeSpaceProviderTest" annotations="JDK"> + <classes> + <class name="ch.systemsx.cisd.datamover.utils.RemoteFreeSpaceProviderTest"/> + </classes> + </test> +</suite>