blob: 207304ccd073951ce734e4e2cafd94a8cd120aad [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 BestSolution.at and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Tom Schindl<tom.schindl@bestsolution.at> - initial API and implementation
*******************************************************************************/
package org.eclipse.fx.core;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.eclipse.fx.core.function.ExExecutor;
import org.eclipse.fx.core.internal.JavaDSServiceProcessor;
import org.eclipse.fx.core.log.LoggerCreator;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
/**
* Class with static utility methods
*/
public class Util {
/**
* @return <code>true</code> if we are on JavaFX 2
*/
public static boolean isFX2() {
return System.getProperty("javafx.version") != null && System.getProperty("javafx.version").startsWith("2"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
/**
* @return <code>true</code> if we are on JavaFX 9
* @since 2.2.0
*/
public static boolean isFX9() {
return System.getProperty("javafx.version") != null && System.getProperty("javafx.version").startsWith("9"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
}
/**
* @return <code>true</code> if we are on JavaFX 8
* @since 2.2.0
*/
public static boolean isFX8() {
return System.getProperty("javafx.version") != null && System.getProperty("javafx.version").startsWith("8"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
}
/**
* Make use the value is not null
*
* @param value
* the nullable value
* @param defaultValue
* the default if the value is null
* @return a nonnull string
* @since 2.0
*/
@NonNull
public static String notNull(@Nullable String value, @NonNull String defaultValue) {
return value == null ? defaultValue : value;
}
private static Boolean isOSGi;
/**
* @return <code>true</code> if running on OSGi
*/
public static boolean isOsgiEnv() {
if (isOSGi == null) {
isOSGi = Boolean.FALSE;
try {
Class.forName("org.osgi.framework.FrameworkUtil"); //$NON-NLS-1$
if (org.osgi.framework.FrameworkUtil.getBundle(Util.class) != null) {
isOSGi = Boolean.TRUE;
}
} catch (Throwable e) {
// nothing
}
}
return isOSGi.booleanValue();
}
private static <S> @Nullable S _lookupService(@Nullable Class<?> requestor, @NonNull Class<S> serviceClass) {
List<@NonNull S> _lookupServiceList = _lookupServiceList(requestor, serviceClass);
if (!_lookupServiceList.isEmpty()) {
return _lookupServiceList.get(0);
}
return null;
}
private static <S> @NonNull List<@NonNull S> _lookupServiceList(@Nullable Class<?> requestor, @NonNull Class<S> serviceClass) {
if (isOsgiEnv()) {
return OSGiUtil.lookupServiceList(requestor, serviceClass);
} else {
return JavaDSServiceProcessor.lookupServiceList(requestor, serviceClass);
}
}
/**
* Look up the service with the given type
*
* @param requestor
* the class requesting the service
*
* @param serviceClass
* the service class type
* @return the service with the highest rank or <code>null</code>
* @since 1.2
*/
public static <S> @Nullable S lookupService(@NonNull Class<?> requestor, @NonNull Class<S> serviceClass) {
return _lookupService(requestor, serviceClass);
}
/**
* Look up the service with the given type
*
* @param serviceClass
* the service class type
* @return the service with the highest rank or <code>null</code>
* @since 1.2
*/
public static <S> @Nullable S lookupService(@NonNull Class<S> serviceClass) {
return _lookupService(null, serviceClass);
}
/**
* Lookup the service with the given type
*
* @param serviceClass
* the service class type
* @return the service with the highest rank as an optional
* @since 2.2.0
*/
@SuppressWarnings("null")
public static <S> @NonNull Optional<S> getService(@NonNull Class<S> serviceClass) {
@Nullable
S v = _lookupService(null, serviceClass);
if (v == null) {
return Optional.empty();
} else {
return Optional.of(v);
}
}
/**
* Look up the service with the given type
*
* @param requestor
* the class requesting the service
*
* @param serviceClass
* the service class type
* @return the service with the highest rank or <code>null</code>
* @since 2.2.0
*/
@SuppressWarnings("null")
public static <S> @NonNull Optional<S> getService(@NonNull Class<?> requestor, @NonNull Class<S> serviceClass) {
@Nullable
S v = _lookupService(requestor, serviceClass);
if (v == null) {
return Optional.empty();
} else {
return Optional.of(v);
}
}
/**
* Look up all service with the given type
*
* @param requestor
* the class requesting the service
*
* @param serviceClass
* the service class type
* @return the service with the highest rank or <code>null</code>
* @since 1.2
*/
public static <S> @NonNull List<@NonNull S> lookupServiceList(@NonNull Class<?> requestor, @NonNull Class<S> serviceClass) {
return _lookupServiceList(requestor, serviceClass);
}
/**
* Look up all service with the given type
*
* @param serviceClass
* the service class type
* @return the service with the highest rank or <code>null</code>
* @since 1.2
*/
public static <S> @NonNull List<@NonNull S> lookupServiceList(@NonNull Class<S> serviceClass) {
return _lookupServiceList(null, serviceClass);
}
/**
* Read the content for the given path
*
* @param path
* the path
* @return the content
* @throws IOException
* if an I/O error occurs
* @since 2.0
*/
public static String slurpFileContent(Path path) throws IOException {
byte[] buf = new byte[(int) Files.size(path)];
try (InputStream in = Files.newInputStream(path)) {
in.read(buf);
return new String(buf);
}
}
/**
* Read the input stream into a string
*
* @param in
* the stream
* @param charset
* the charset to be used
* @return the string
*/
public static String readToString(InputStream in, Charset charset) {
return readToString(in, 1024, charset);
}
/**
* Read the input stream into a string
*
* @param in
* the stream
* @param bufferLength
* the buffer length
* @param charset
* the charset
* @return the string
*/
public static String readToString(InputStream in, int bufferLength, Charset charset) {
StringBuilder b = new StringBuilder();
char[] buf = new char[bufferLength];
InputStreamReader r = new InputStreamReader(in, charset);
int l;
try {
while ((l = r.read(buf, 0, bufferLength)) != -1) {
b.append(buf, 0, l);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return b.toString();
}
/**
* Copy the complete input stream to an output stream
*
* @param sourceStream
* the source stream
* @param targetStream
* the output stream
* @throws IOException
* if something is going wrong
* @since 2.3.0
*/
public static void copyToStream(InputStream sourceStream, OutputStream targetStream) throws IOException {
byte[] buf = new byte[1024];
int l;
while ((l = sourceStream.read(buf)) != -1) {
targetStream.write(buf, 0, l);
}
}
/**
* Zip up a complete directory with all the sub directories
*
* @param dir
* the directory to zip
* @param zipFile
* the zip file or <code>null</code> if you want a temporary zip
* file to be created
* @return the directory
* @throws IOException
* if somethings going wrong
* @since 2.3.0
*/
@SuppressWarnings("null")
public static @NonNull Path zipDirectory(@NonNull Path dir, @Nullable Path zipFile) throws IOException {
Path target = zipFile;
if (target == null) {
target = Files.createTempFile("generated-zip", ".zip"); //$NON-NLS-1$//$NON-NLS-2$
}
try (ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(target))) {
for (Path c : Files.list(dir).collect(Collectors.toList())) {
if (!c.equals(target)) {
addEntry(out, dir, c);
}
}
out.close();
}
return target;
}
private static void addEntry(ZipOutputStream out, Path rootPath, Path p) throws IOException {
if (Files.isDirectory(p)) {
for (Path c : Files.list(p).collect(Collectors.toList())) {
addEntry(out, rootPath, c);
}
} else {
ZipEntry e = new ZipEntry(rootPath.relativize(p).toString());
out.putNextEntry(e);
try (InputStream s = Files.newInputStream(p)) {
copyToStream(s, out);
}
out.closeEntry();
}
}
/**
* @return <code>true</code> if running on OS-X
* @since 2.2.0
*/
public static boolean isMacOS() {
return "Mac OS X".equals(System.getProperty("os.name")); //$NON-NLS-1$//$NON-NLS-2$
}
/**
* @return <code>true</code> if running on windows
* @since 2.2.0
*/
public static boolean isWindows() {
return System.getProperty("os.name").toLowerCase().contains("windows"); //$NON-NLS-1$//$NON-NLS-2$
}
/**
* Constraint the given value to the upper and lower bound
*
* @param v
* the value to constraint
* @param min
* the lower bound (only values >= 0 are applied)
* @param max
* the upper bound (only values >= 0 are applied)
* @return the value
* @since 2.2.0
*/
public static double unsignedConstraintValue(double v, double min, double max) {
double rv = v;
if (min >= 0) {
rv = Math.max(rv, min);
}
if (max >= 0) {
rv = Math.min(rv, max);
}
return rv;
}
/**
* Helper method allowing to insert temporary debug information in an
* {@link Stream} mapping
*
* @param data
* the data
* @return the data
* @since 2.2.0
*/
public static <T> T debugStderr(T data) {
System.err.println(data);
return data;
}
/**
* Convert an URL to a path on the local filesystem
*
* @param url
* the url
* @param copyIfNeeded
* <code>true</code> if the url can not be converted to a local
* the content is copied to the local filesystem
* @return the path
* @since 2.2.0
*/
public static Optional<Resource<@NonNull Path>> getLocalPath(@NonNull URL url, boolean copyIfNeeded) {
return lookupServiceList(URLResolver.class).stream().filter(r -> r.test(url)).findFirst().map(r -> Optional.of(Resource.createResource(r.resolveToLocalPath(url)))).orElseGet(() -> copyIfNeeded ? ExExecutor.executeSupplier(() -> Util.copyToTempFile(url), "Unable to copy resource") //$NON-NLS-1$
: Optional.empty());
}
/**
* Convert an URL to a path on the local filesystem
*
* @param url
* the url
* @return the path
* @since 2.2.0
*/
public static Optional<URL> getLocalURL(@NonNull URL url) {
return lookupServiceList(URLResolver.class).stream().filter(r -> r.test(url)).findFirst().map(r -> r.resolveToLocalURL(url));
}
private static Resource<@NonNull Path> copyToTempFile(@NonNull URL url) throws IOException {
Path path = Files.createTempFile("tmp", Paths.get(url.getPath()).getFileName().toString()); //$NON-NLS-1$
try (InputStream stream = url.openStream()) {
Files.copy(stream, path);
}
if (path == null) {
return null;
}
return Resource.createTempResource(path);
}
/**
* Create a new URL instance from the provide value
*
* @param url
* the url
* @return the url instance
* @throws IllegalArgumentException
* if something wrong with the URL provided
* @since 2.3.0
*/
public static URL createUrl(String url) {
try {
return new URL(url);
} catch (MalformedURLException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Create a new URL instance who provides an optional of the creation fails
*
* @param url
* the url
* @param log
* <code>true</code> if you want the exception to be logged
* @return the url wrapped in an optional
* @since 2.4.0
*/
public static Optional<URL> createUrl(String url, boolean log) {
try {
return Optional.of(new URL(url));
} catch (Throwable e) {
if (log) {
LoggerCreator.createLogger(Util.class).error("Failed to create url from '" + url + "'", e); //$NON-NLS-1$//$NON-NLS-2$
}
return Optional.empty();
}
}
/**
* Create a string of the same char
*
* @param c
* the character
* @param length
* the length
* @return the created string
* @since 2.4.0
*/
public static String createRepeatedString(char c, int length) {
char[] vals = new char[length];
Arrays.fill(vals, ' ');
return String.valueOf(vals);
}
}