-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
28 changed files
with
991 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,23 @@ | ||
import org.cryptomator.integrations.tray.TrayMenuController; | ||
import org.cryptomator.integrations.autostart.AutoStartProvider; | ||
import org.cryptomator.integrations.keychain.KeychainAccessProvider; | ||
import org.cryptomator.integrations.tray.TrayIntegrationProvider; | ||
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider; | ||
|
||
|
||
module org.cryptomator.integrations.api { | ||
requires static org.jetbrains.annotations; | ||
requires org.slf4j; | ||
|
||
exports org.cryptomator.integrations.autostart; | ||
exports org.cryptomator.integrations.common; | ||
exports org.cryptomator.integrations.keychain; | ||
exports org.cryptomator.integrations.tray; | ||
exports org.cryptomator.integrations.uiappearance; | ||
|
||
uses AutoStartProvider; | ||
uses KeychainAccessProvider; | ||
uses TrayIntegrationProvider; | ||
uses TrayMenuController; | ||
uses UiAppearanceProvider; | ||
} |
17 changes: 17 additions & 0 deletions
17
src/main/java/org/cryptomator/integrations/autostart/AutoStartProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
src/main/java/org/cryptomator/integrations/common/CheckAvailability.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package org.cryptomator.integrations.common; | ||
|
||
import org.jetbrains.annotations.ApiStatus; | ||
|
||
import java.lang.annotation.Documented; | ||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Inherited; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* Identifies 0..n public methods to check preconditions for the integration to work. These are the rules: | ||
* | ||
* <ul> | ||
* <li>Both the type and the method(s) must be annotated with {@code @CheckAvailability}</li> | ||
* <li>Only public no-arg boolean methods are considered</li> | ||
* <li>Methods <em>may</em> be {@code static}, in which case they get invoked before instantiating the service</li> | ||
* <li>Should the method throw an exception, it has the same effect as returning {@code false}</li> | ||
* <li>No specific execution order is guaranteed in case of multiple annotated methods</li> | ||
* <li>Annotations must be present on classes or ancestor classes, not on interfaces</li> | ||
* </ul> | ||
* | ||
* Example: | ||
* <pre> | ||
* {@code | ||
* @CheckAvailability | ||
* public class Foo { | ||
* @CheckAvailability | ||
* public static boolean isSupported() { | ||
* return "enabled".equals(System.getProperty("plugin.status")); | ||
* } | ||
* } | ||
* } | ||
* </pre> | ||
* <p> | ||
* Annotations are discovered at runtime using reflection, so make sure to make relevant classes accessible to this | ||
* module ({@code opens X to org.cryptomator.integrations.api}). | ||
* | ||
* @since 1.1.0 | ||
*/ | ||
@Documented | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target({ElementType.TYPE, ElementType.METHOD}) | ||
@Inherited | ||
@ApiStatus.Experimental | ||
public @interface CheckAvailability { | ||
} |
76 changes: 76 additions & 0 deletions
76
src/main/java/org/cryptomator/integrations/common/ClassLoaderFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package org.cryptomator.integrations.common; | ||
|
||
import org.jetbrains.annotations.Contract; | ||
import org.jetbrains.annotations.VisibleForTesting; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.IOException; | ||
import java.io.UncheckedIOException; | ||
import java.net.MalformedURLException; | ||
import java.net.URL; | ||
import java.net.URLClassLoader; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.util.Arrays; | ||
import java.util.stream.Collectors; | ||
|
||
class ClassLoaderFactory { | ||
|
||
private static final Logger LOG = LoggerFactory.getLogger(ClassLoaderFactory.class); | ||
private static final String USER_HOME = System.getProperty("user.home"); | ||
private static final String PLUGIN_DIR_KEY = "cryptomator.pluginDir"; | ||
private static final String JAR_SUFFIX = ".jar"; | ||
|
||
/** | ||
* Attempts to find {@code .jar} files in the path specified in {@value #PLUGIN_DIR_KEY} system property. | ||
* A new class loader instance is returned that loads classes from the given classes. | ||
* | ||
* @return A new URLClassLoader that is aware of all {@code .jar} files in the plugin dir | ||
*/ | ||
@Contract(value = "-> new", pure = true) | ||
public static URLClassLoader forPluginDir() { | ||
String val = System.getProperty(PLUGIN_DIR_KEY, ""); | ||
final Path p; | ||
if (val.startsWith("~/")) { | ||
p = Path.of(USER_HOME).resolve(val.substring(2)); | ||
} else { | ||
p = Path.of(val); | ||
} | ||
return forPluginDirWithPath(p); | ||
} | ||
|
||
@VisibleForTesting | ||
@Contract(value = "_ -> new", pure = true) | ||
static URLClassLoader forPluginDirWithPath(Path path) throws UncheckedIOException { | ||
var jars = findJars(path); | ||
if (LOG.isDebugEnabled()) { | ||
String jarList = Arrays.stream(jars).map(URL::getPath).collect(Collectors.joining(", ")); | ||
LOG.debug("Found jars in cryptomator.pluginDir: {}", jarList); | ||
} | ||
return URLClassLoader.newInstance(jars); | ||
} | ||
|
||
@VisibleForTesting | ||
static URL[] findJars(Path path) { | ||
try (var stream = Files.walk(path)) { | ||
return stream.filter(ClassLoaderFactory::isJarFile).map(ClassLoaderFactory::toUrl).toArray(URL[]::new); | ||
} catch (IOException | UncheckedIOException e) { | ||
// unable to locate any jars // TODO: log a warning? | ||
return new URL[0]; | ||
} | ||
} | ||
|
||
private static URL toUrl(Path path) throws UncheckedIOException { | ||
try { | ||
return path.toUri().toURL(); | ||
} catch (MalformedURLException e) { | ||
throw new UncheckedIOException(e); | ||
} | ||
} | ||
|
||
private static boolean isJarFile(Path path) { | ||
return Files.isRegularFile(path) && path.getFileName().toString().toLowerCase().endsWith(JAR_SUFFIX); | ||
} | ||
|
||
} |
Oops, something went wrong.