001/* 002 * Licensed under the Apache License, Version 2.0 (the "License"); 003 * you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at 005 * 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * 008 * Unless required by applicable law or agreed to in writing, software 009 * distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and 012 * limitations under the License. 013 */ 014package de.softwareforge.testing.postgres.embedded; 015 016import static com.google.common.base.Preconditions.checkState; 017 018import java.io.IOException; 019import java.io.InputStream; 020 021import com.google.common.hash.Hashing; 022import com.google.common.hash.HashingInputStream; 023import com.google.common.io.BaseEncoding; 024import com.google.common.io.ByteStreams; 025import edu.umd.cs.findbugs.annotations.CheckForNull; 026import edu.umd.cs.findbugs.annotations.NonNull; 027import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 028 029/** 030 * Locates a native binary on the Filesystem. If necessary, it should download the binary first from the network. 031 * <p> 032 * Implementations of this class <b>must</b> implement {@link Object#hashCode()} and {@link Object#equals(Object)} and *should* implement {@link Object#toString()}. 033 */ 034public interface NativeBinaryLocator { 035 036 String INSTALL_DIRECTORY_PREFIX = "bin-"; 037 038 /** 039 * Returns an input stream from which the contents of the binary archive can be read. 040 * 041 * @return An input stream. May return null. 042 * @throws IOException If the archive could not be located or read. 043 */ 044 @CheckForNull 045 InputStream getInputStream() throws IOException; 046 047 /** 048 * Returns a string identifier that represents the archive returned. This identifier should be stable (same value for the same archive), even across 049 * multiple JVM invocations. The value must only contain characters that can be used as a legal file name. 050 * <p> 051 * The default implementation needs to read the full archive contents and is relatively slow. Implementations of this interface can override this method to 052 * provide a faster way to create a stable identifier based on the specific implementation. 053 * <p> 054 * The default implementation hashes the archive contents and uses it to return a stable file name. 055 * 056 * @return A stable indentifier that can be used as a file name. 057 * @throws IOException If the stream could not be read. 058 */ 059 @NonNull 060 @SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE") // false positive 061 default String getIdentifier() throws IOException { 062 try (InputStream installationArchive = getInputStream()) { 063 checkState(installationArchive != null, "Locator '%s' did not find a suitable archive to unpack!", toString()); 064 try (HashingInputStream hashStream = new HashingInputStream(Hashing.murmur3_128(), installationArchive)) { 065 ByteStreams.exhaust(hashStream); 066 return INSTALL_DIRECTORY_PREFIX + BaseEncoding.base16().encode(hashStream.hash().asBytes()); 067 } 068 } 069 } 070}