Runs code that lives outside an OSGi container inside of it. Works just like JavaExecable. Make sure the code you execute only uses classes which are available to the OSGi runtime you're using. If you'd like to call some code which is only available inside the OSGi container, use a {@link
| 71 | * ``` |
| 72 | */ |
| 73 | public interface OsgiExecable extends Serializable, Runnable { |
| 74 | /** Executes the given {@link OsgiExecable} within an embedded OSGi runtime. */ |
| 75 | public static <T extends OsgiExecable> T exec(BundleContext context, T input) throws Exception { |
| 76 | // find OsgiExecImp.execInternal within the OSGi runtime |
| 77 | Bundle bundle = OsgiExecImp.loadBundle(context); |
| 78 | bundle.start(); |
| 79 | Class<?> clazz = bundle.loadClass(OsgiExecImp.class.getName()); |
| 80 | Method execInternal = clazz.getMethod("execInternal", File.class); |
| 81 | // write the input to a tempfile |
| 82 | File tempFile = File.createTempFile("OsgiExec", ".temp"); |
| 83 | try { |
| 84 | SerializableMisc.write(tempFile, input); |
| 85 | // call it within the OSGi runtime |
| 86 | execInternal.setAccessible(true); |
| 87 | execInternal.invoke(null, tempFile); |
| 88 | // get the result, and return it |
| 89 | return SerializableMisc.read(tempFile); |
| 90 | } finally { |
| 91 | FileMisc.forceDelete(tempFile); |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | /** |
| 96 | * Defines data which will be passed via reflection to code within the OSGi runtime - the reflection |
| 97 | * allows us to call code for which we don't have the necessary dependencies to resolve its imports |
| 98 | * unless it is only instantiated within the OSGi container. |
| 99 | */ |
| 100 | @SuppressWarnings("serial") |
| 101 | public static abstract class ReflectionHost implements OsgiExecable { |
| 102 | private final String delegate; |
| 103 | |
| 104 | protected ReflectionHost(String delegate) { |
| 105 | this.delegate = Objects.requireNonNull(delegate); |
| 106 | } |
| 107 | |
| 108 | @Override |
| 109 | public void run() { |
| 110 | try { |
| 111 | Bundle bundle = FrameworkUtil.getBundle(OsgiExecable.class); |
| 112 | Class<?> clazz = bundle.loadClass(delegate); |
| 113 | Constructor<?>[] constructors = clazz.getDeclaredConstructors(); |
| 114 | if (constructors.length != 1) { |
| 115 | throw new IllegalArgumentException(delegate + " must have only one constructor, this had " + constructors.length); |
| 116 | } |
| 117 | if (constructors[0].getParameterCount() != 1) { |
| 118 | throw new IllegalArgumentException(delegate + "'s constructor must take one argument, this took " + constructors[0].getParameterCount()); |
| 119 | } |
| 120 | constructors[0].setAccessible(true); |
| 121 | ReflectionClient<?> client = (ReflectionClient<?>) (Object) constructors[0].newInstance(this); |
| 122 | client.run(); |
| 123 | } catch (SecurityException | ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { |
| 124 | throw new RuntimeException(e); |
| 125 | } |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | /** Client code which gets called within the OSGi runtime. */ |
| 130 | public static abstract class ReflectionClient<Host extends ReflectionHost> implements Runnable { |
no outgoing calls
no test coverage detected