From 50e4c44bfa83f03e6df38373558cedf599844917 Mon Sep 17 00:00:00 2001 From: Simon Wimmesberger Date: Wed, 7 Oct 2020 09:52:55 +0200 Subject: [PATCH 1/2] Added bnd to project builds --- build.gradle | 23 +++++++++++++++++++++ retrofit-adapters/guava/build.gradle | 19 +++++++++++------ retrofit-adapters/java8/build.gradle | 17 +++++++++------ retrofit-adapters/rxjava/build.gradle | 17 +++++++++------ retrofit-adapters/rxjava2/build.gradle | 17 +++++++++------ retrofit-adapters/rxjava3/build.gradle | 17 +++++++++------ retrofit-adapters/scala/build.gradle | 17 +++++++++------ retrofit-converters/gson/build.gradle | 17 +++++++++------ retrofit-converters/guava/build.gradle | 17 +++++++++------ retrofit-converters/jackson/build.gradle | 17 +++++++++------ retrofit-converters/java8/build.gradle | 17 +++++++++------ retrofit-converters/jaxb/build.gradle | 17 +++++++++------ retrofit-converters/moshi/build.gradle | 17 +++++++++------ retrofit-converters/protobuf/build.gradle | 17 +++++++++------ retrofit-converters/scalars/build.gradle | 17 +++++++++------ retrofit-converters/simplexml/build.gradle | 17 +++++++++------ retrofit-converters/wire/build.gradle | 17 +++++++++------ retrofit/build.gradle | 24 ++++++++++++++++------ 18 files changed, 219 insertions(+), 102 deletions(-) diff --git a/build.gradle b/build.gradle index b4f60a94f5..bebed54b9d 100644 --- a/build.gradle +++ b/build.gradle @@ -8,6 +8,7 @@ buildscript { 'protobuf': '3.10.0', 'jaxb': '2.3.1', 'robovm': '2.3.9', + 'bnd': '5.1.2' ] ext.deps = [ 'kotlinStdLib': "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}", @@ -36,6 +37,8 @@ buildscript { 'wireRuntime': 'com.squareup.wire:wire-runtime:2.2.0', 'jsoup': 'org.jsoup:jsoup:1.12.1', 'robovm': "com.mobidevelop.robovm:robovm-rt:${versions.robovm}", + 'bnd': "biz.aQute.bnd:biz.aQute.bnd.gradle:${versions.bnd}", + 'kotlinStdlibOsgi': "org.jetbrains.kotlin:kotlin-osgi-bundle:${versions.kotlin}" ] dependencies { @@ -47,6 +50,7 @@ buildscript { classpath 'ru.vyarus:gradle-animalsniffer-plugin:1.5.0' classpath 'gradle.plugin.com.github.sherter.google-java-format:google-java-format-gradle-plugin:0.9' classpath "com.mobidevelop.robovm:robovm-gradle-plugin:${versions.robovm}" + classpath deps.bnd } repositories { mavenCentral() @@ -144,4 +148,23 @@ subprojects { jvmTarget = '1.8' } } + + ext.applyOsgi = { project -> + project.apply plugin: 'biz.aQute.bnd.builder' + + project.sourceSets { + osgi + } + + project.jar { t -> + t.setClasspath(project.sourceSets.osgi['compileClasspath'] + project.sourceSets.main['compileClasspath']) + } + + project.dependencies { dp -> + if (dp.hasProperty('osgiApi')) { + // The OSGi kotlin-stdlib lets bnd infer bundle versions. + dp.osgiApi deps.kotlinStdlibOsgi + } + } + } } diff --git a/retrofit-adapters/guava/build.gradle b/retrofit-adapters/guava/build.gradle index 080da340bf..c686e425ac 100644 --- a/retrofit-adapters/guava/build.gradle +++ b/retrofit-adapters/guava/build.gradle @@ -1,5 +1,18 @@ apply plugin: 'java-library' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit2.adapter.guava + Import-Package: \ + org.checkerframework.checker.*;resolution:=optional,\ + * + Automatic-Module-Name: retrofit2.adapter.guava + Bundle-SymbolicName: com.squareup.retrofit2.adapter.guava + ''' +} dependencies { api project(':retrofit') @@ -11,9 +24,3 @@ dependencies { testImplementation deps.assertj testImplementation deps.mockwebserver } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.adapter.guava' - } -} diff --git a/retrofit-adapters/java8/build.gradle b/retrofit-adapters/java8/build.gradle index 797c2c54bc..a805544da4 100644 --- a/retrofit-adapters/java8/build.gradle +++ b/retrofit-adapters/java8/build.gradle @@ -1,5 +1,16 @@ apply plugin: 'java-library' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit2.adapter.java8 + Import-Package: * + Automatic-Module-Name: retrofit2.adapter.java8 + Bundle-SymbolicName: com.squareup.retrofit2.adapter.java8 + ''' +} dependencies { api project(':retrofit') @@ -10,9 +21,3 @@ dependencies { testImplementation deps.guava testImplementation deps.mockwebserver } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.adapter.java8' - } -} diff --git a/retrofit-adapters/rxjava/build.gradle b/retrofit-adapters/rxjava/build.gradle index 8b7d1c3dad..3db76b4a99 100644 --- a/retrofit-adapters/rxjava/build.gradle +++ b/retrofit-adapters/rxjava/build.gradle @@ -1,5 +1,16 @@ apply plugin: 'java-library' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit2.adapter.rxjava + Import-Package: * + Automatic-Module-Name: retrofit2.adapter.rxjava + Bundle-SymbolicName: com.squareup.retrofit2.adapter.rxjava + ''' +} dependencies { api project(':retrofit') @@ -11,9 +22,3 @@ dependencies { testImplementation deps.guava testImplementation deps.mockwebserver } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.adapter.rxjava' - } -} diff --git a/retrofit-adapters/rxjava2/build.gradle b/retrofit-adapters/rxjava2/build.gradle index a62121c322..4f0f1a3b0a 100644 --- a/retrofit-adapters/rxjava2/build.gradle +++ b/retrofit-adapters/rxjava2/build.gradle @@ -1,5 +1,16 @@ apply plugin: 'java-library' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit2.adapter.rxjava2 + Import-Package: * + Automatic-Module-Name: retrofit2.adapter.rxjava2 + Bundle-SymbolicName: com.squareup.retrofit2.adapter.rxjava2 + ''' +} dependencies { api project(':retrofit') @@ -12,9 +23,3 @@ dependencies { testImplementation deps.guava testImplementation deps.mockwebserver } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.adapter.rxjava2' - } -} diff --git a/retrofit-adapters/rxjava3/build.gradle b/retrofit-adapters/rxjava3/build.gradle index 530887e0d5..b650a0d981 100644 --- a/retrofit-adapters/rxjava3/build.gradle +++ b/retrofit-adapters/rxjava3/build.gradle @@ -1,5 +1,16 @@ apply plugin: 'java-library' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit2.adapter.rxjava3 + Import-Package: * + Automatic-Module-Name: retrofit2.adapter.rxjava3 + Bundle-SymbolicName: com.squareup.retrofit2.adapter.rxjava3 + ''' +} dependencies { api project(':retrofit') @@ -12,9 +23,3 @@ dependencies { testImplementation deps.guava testImplementation deps.mockwebserver } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.adapter.rxjava3' - } -} diff --git a/retrofit-adapters/scala/build.gradle b/retrofit-adapters/scala/build.gradle index e7eac93dc4..ee5281f759 100644 --- a/retrofit-adapters/scala/build.gradle +++ b/retrofit-adapters/scala/build.gradle @@ -1,5 +1,16 @@ apply plugin: 'java-library' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit2.adapter.scala + Import-Package: * + Automatic-Module-Name: retrofit2.adapter.scala + Bundle-SymbolicName: com.squareup.retrofit2.adapter.scala + ''' +} dependencies { api project(':retrofit') @@ -11,9 +22,3 @@ dependencies { testImplementation deps.guava testImplementation deps.mockwebserver } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.adapter.scala' - } -} diff --git a/retrofit-converters/gson/build.gradle b/retrofit-converters/gson/build.gradle index e7d322049d..6ec9820eb8 100644 --- a/retrofit-converters/gson/build.gradle +++ b/retrofit-converters/gson/build.gradle @@ -1,5 +1,16 @@ apply plugin: 'java-library' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit2.converter.gson + Import-Package: * + Automatic-Module-Name: retrofit2.converter.gson + Bundle-SymbolicName: com.squareup.retrofit2.converter.gson + ''' +} dependencies { api project(':retrofit') @@ -10,9 +21,3 @@ dependencies { testImplementation deps.assertj testImplementation deps.mockwebserver } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.converter.gson' - } -} diff --git a/retrofit-converters/guava/build.gradle b/retrofit-converters/guava/build.gradle index 3b509900cf..4d520dcea2 100644 --- a/retrofit-converters/guava/build.gradle +++ b/retrofit-converters/guava/build.gradle @@ -1,5 +1,16 @@ apply plugin: 'java-library' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit.converter.guava + Import-Package: * + Automatic-Module-Name: retrofit2.converter.guava + Bundle-SymbolicName: com.squareup.retrofit2.converter.guava + ''' +} dependencies { api project(':retrofit') @@ -10,9 +21,3 @@ dependencies { testImplementation deps.assertj testImplementation deps.mockwebserver } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.converter.guava' - } -} diff --git a/retrofit-converters/jackson/build.gradle b/retrofit-converters/jackson/build.gradle index 48c6f09661..9c750a9007 100644 --- a/retrofit-converters/jackson/build.gradle +++ b/retrofit-converters/jackson/build.gradle @@ -1,5 +1,16 @@ apply plugin: 'java-library' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit2.converter.jackson + Import-Package: * + Automatic-Module-Name: retrofit2.converter.jackson + Bundle-SymbolicName: com.squareup.retrofit2.converter.jackson + ''' +} dependencies { api project(':retrofit') @@ -10,9 +21,3 @@ dependencies { testImplementation deps.assertj testImplementation deps.mockwebserver } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.converter.jackson' - } -} diff --git a/retrofit-converters/java8/build.gradle b/retrofit-converters/java8/build.gradle index 3ea5eddd61..0bf22f5c11 100644 --- a/retrofit-converters/java8/build.gradle +++ b/retrofit-converters/java8/build.gradle @@ -1,5 +1,16 @@ apply plugin: 'java-library' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit.converter.java8 + Import-Package: * + Automatic-Module-Name: retrofit2.converter.java8 + Bundle-SymbolicName: com.squareup.retrofit2.converter.java8 + ''' +} dependencies { api project(':retrofit') @@ -10,9 +21,3 @@ dependencies { testImplementation deps.mockwebserver testImplementation deps.findBugsAnnotations } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.converter.java8' - } -} diff --git a/retrofit-converters/jaxb/build.gradle b/retrofit-converters/jaxb/build.gradle index 2d30b2c758..abc1f5f721 100644 --- a/retrofit-converters/jaxb/build.gradle +++ b/retrofit-converters/jaxb/build.gradle @@ -1,5 +1,16 @@ apply plugin: 'java-library' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit2.converter.jaxb + Import-Package: * + Automatic-Module-Name: retrofit2.converter.jaxb + Bundle-SymbolicName: com.squareup.retrofit2.converter.jaxb + ''' +} dependencies { api project(':retrofit') @@ -12,9 +23,3 @@ dependencies { testImplementation deps.mockwebserver testImplementation deps.findBugsAnnotations } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.converter.jaxb' - } -} diff --git a/retrofit-converters/moshi/build.gradle b/retrofit-converters/moshi/build.gradle index d3437f806f..de2264d239 100644 --- a/retrofit-converters/moshi/build.gradle +++ b/retrofit-converters/moshi/build.gradle @@ -1,5 +1,16 @@ apply plugin: 'java-library' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit2.converter.moshi + Import-Package: * + Automatic-Module-Name: retrofit2.converter.moshi + Bundle-SymbolicName: com.squareup.retrofit2.converter.moshi + ''' +} dependencies { api project(':retrofit') @@ -10,9 +21,3 @@ dependencies { testImplementation deps.assertj testImplementation deps.mockwebserver } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.converter.moshi' - } -} diff --git a/retrofit-converters/protobuf/build.gradle b/retrofit-converters/protobuf/build.gradle index fb250d8777..1fec02ef13 100644 --- a/retrofit-converters/protobuf/build.gradle +++ b/retrofit-converters/protobuf/build.gradle @@ -1,6 +1,17 @@ apply plugin: 'java-library' apply plugin: 'com.google.protobuf' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit2.converter.protobuf + Import-Package: * + Automatic-Module-Name: retrofit2.converter.protobuf + Bundle-SymbolicName: com.squareup.retrofit2.converter.protobuf + ''' +} dependencies { api project(':retrofit') @@ -12,12 +23,6 @@ dependencies { testImplementation deps.mockwebserver } -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.converter.protobuf' - } -} - protobuf { protoc { artifact = "com.google.protobuf:protoc:${versions.protobuf}" diff --git a/retrofit-converters/scalars/build.gradle b/retrofit-converters/scalars/build.gradle index 2ba3084b02..406b188784 100644 --- a/retrofit-converters/scalars/build.gradle +++ b/retrofit-converters/scalars/build.gradle @@ -1,5 +1,16 @@ apply plugin: 'java-library' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit2.converter.scalars + Import-Package: * + Automatic-Module-Name: retrofit2.converter.scalars + Bundle-SymbolicName: com.squareup.retrofit2.converter.scalars + ''' +} dependencies { api project(':retrofit') @@ -9,9 +20,3 @@ dependencies { testImplementation deps.assertj testImplementation deps.mockwebserver } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.converter.scalars' - } -} diff --git a/retrofit-converters/simplexml/build.gradle b/retrofit-converters/simplexml/build.gradle index 3e10e34577..abb145e65c 100644 --- a/retrofit-converters/simplexml/build.gradle +++ b/retrofit-converters/simplexml/build.gradle @@ -1,5 +1,16 @@ apply plugin: 'java-library' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit2.converter.simplexml + Import-Package: * + Automatic-Module-Name: retrofit2.converter.simplexml + Bundle-SymbolicName: com.squareup.retrofit2.converter.simplexml + ''' +} dependencies { api project(':retrofit') @@ -10,9 +21,3 @@ dependencies { testImplementation deps.assertj testImplementation deps.mockwebserver } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.converter.simplexml' - } -} diff --git a/retrofit-converters/wire/build.gradle b/retrofit-converters/wire/build.gradle index bce214df2d..ee48a072a8 100644 --- a/retrofit-converters/wire/build.gradle +++ b/retrofit-converters/wire/build.gradle @@ -1,5 +1,16 @@ apply plugin: 'java-library' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + bnd ''' + Export-Package: retrofit2.converter.wire + Import-Package: * + Automatic-Module-Name: retrofit2.converter.wire + Bundle-SymbolicName: com.squareup.retrofit2.converter.wire + ''' +} dependencies { api project(':retrofit') @@ -13,9 +24,3 @@ dependencies { testImplementation deps.assertj testImplementation deps.mockwebserver } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2.converter.wire' - } -} diff --git a/retrofit/build.gradle b/retrofit/build.gradle index 57f184f28c..e73eac66bd 100644 --- a/retrofit/build.gradle +++ b/retrofit/build.gradle @@ -1,6 +1,24 @@ apply plugin: 'java-library' apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'com.vanniktech.maven.publish' +applyOsgi(this) + +jar { + // MANIFEST.MF, including OSGi bnd instructions. + // We export retrofit2.internal for our own modules use. + // The packages of all optional dependencies must be explicitly specified. + bnd ''' + Export-Package: \ + retrofit2,\ + retrofit2.http,\ + retrofit2.internal;retrofitinternal=true;mandatory:=retrofitinternal + Import-Package: \ + android.*;resolution:=optional,\ + * + Automatic-Module-Name: retrofit2 + Bundle-SymbolicName: com.squareup.retrofit2 + ''' +} dependencies { api deps.okhttp @@ -20,9 +38,3 @@ dependencies { testImplementation deps.kotlinStdLib testImplementation deps.kotlinCoroutines } - -jar { - manifest { - attributes 'Automatic-Module-Name': 'retrofit2' - } -} From db790d4ee6f4e7d8114ecef696b53f44185bee56 Mon Sep 17 00:00:00 2001 From: Simon Wimmesberger Date: Wed, 7 Oct 2020 11:54:53 +0200 Subject: [PATCH 2/2] Added OSGi test --- build.gradle | 12 +- retrofit/build.gradle | 35 ++++ .../test/java/retrofit2/osgi/OsgiTest.java | 165 ++++++++++++++++++ 3 files changed, 204 insertions(+), 8 deletions(-) create mode 100644 retrofit/src/test/java/retrofit2/osgi/OsgiTest.java diff --git a/build.gradle b/build.gradle index bebed54b9d..68088d4569 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,8 @@ buildscript { 'protobuf': '3.10.0', 'jaxb': '2.3.1', 'robovm': '2.3.9', - 'bnd': '5.1.2' + 'bnd': '5.1.2', + 'equinox': '3.16.0' ] ext.deps = [ 'kotlinStdLib': "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}", @@ -38,6 +39,8 @@ buildscript { 'jsoup': 'org.jsoup:jsoup:1.12.1', 'robovm': "com.mobidevelop.robovm:robovm-rt:${versions.robovm}", 'bnd': "biz.aQute.bnd:biz.aQute.bnd.gradle:${versions.bnd}", + 'bndResolve': "biz.aQute.bnd:biz.aQute.resolve:${versions.bnd}", + 'equinox': "org.eclipse.platform:org.eclipse.osgi:${versions.equinox}", 'kotlinStdlibOsgi': "org.jetbrains.kotlin:kotlin-osgi-bundle:${versions.kotlin}" ] @@ -159,12 +162,5 @@ subprojects { project.jar { t -> t.setClasspath(project.sourceSets.osgi['compileClasspath'] + project.sourceSets.main['compileClasspath']) } - - project.dependencies { dp -> - if (dp.hasProperty('osgiApi')) { - // The OSGi kotlin-stdlib lets bnd infer bundle versions. - dp.osgiApi deps.kotlinStdlibOsgi - } - } } } diff --git a/retrofit/build.gradle b/retrofit/build.gradle index e73eac66bd..a99fe94a3c 100644 --- a/retrofit/build.gradle +++ b/retrofit/build.gradle @@ -7,6 +7,8 @@ jar { // MANIFEST.MF, including OSGi bnd instructions. // We export retrofit2.internal for our own modules use. // The packages of all optional dependencies must be explicitly specified. + // kotlinx.coroutines is optional for now because there is no OSGi metadata available + // and it's only necessary when kotlin is used bnd ''' Export-Package: \ retrofit2,\ @@ -14,14 +16,26 @@ jar { retrofit2.internal;retrofitinternal=true;mandatory:=retrofitinternal Import-Package: \ android.*;resolution:=optional,\ + kotlinx.coroutines.*;resolution:=optional,\ * Automatic-Module-Name: retrofit2 Bundle-SymbolicName: com.squareup.retrofit2 ''' } +// Expose OSGi jars to the test environment. +configurations { + osgiTestDeploy +} +task copyOsgiTestDeployment(type: Copy) { + from configurations.osgiTestDeploy + into "${buildDir}/resources/test/retrofit2/osgi/deployments" +} +tasks.test.dependsOn(copyOsgiTestDeployment) + dependencies { api deps.okhttp + osgiApi deps.kotlinStdlibOsgi compileOnly deps.android compileOnly deps.kotlinStdLib @@ -37,4 +51,25 @@ dependencies { testImplementation deps.mockwebserver testImplementation deps.kotlinStdLib testImplementation deps.kotlinCoroutines + testImplementation deps.bndResolve + osgiTestDeploy deps.equinox + osgiTestDeploy deps.kotlinStdlibOsgi + osgiTestDeploy project(':retrofit-adapters:guava') + osgiTestDeploy project(':retrofit-adapters:java8') + osgiTestDeploy project(':retrofit-adapters:rxjava') + osgiTestDeploy project(':retrofit-adapters:rxjava2') + osgiTestDeploy project(':retrofit-adapters:rxjava3') + osgiTestDeploy project(':retrofit-adapters:scala') + // can't include those because gradle seems to get confused because of the retrofit-adapters counterpart + //osgiTestDeploy project(':retrofit-converters:guava') + //osgiTestDeploy project(':retrofit-converters:java8') + osgiTestDeploy project(':retrofit-converters:gson') + osgiTestDeploy project(':retrofit-converters:jackson') + osgiTestDeploy project(':retrofit-converters:jaxb') + osgiTestDeploy project(':retrofit-converters:protobuf') + osgiTestDeploy project(':retrofit-converters:scalars') + // those dependencies are not fully OSGi compatible yet + //osgiTestDeploy project(':retrofit-converters:moshi') + //osgiTestDeploy project(':retrofit-converters:simplexml') + //osgiTestDeploy project(':retrofit-converters:wire') } diff --git a/retrofit/src/test/java/retrofit2/osgi/OsgiTest.java b/retrofit/src/test/java/retrofit2/osgi/OsgiTest.java new file mode 100644 index 0000000000..5232d75d03 --- /dev/null +++ b/retrofit/src/test/java/retrofit2/osgi/OsgiTest.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2020 Square, Inc. + * + * 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 retrofit2.osgi; + +import aQute.bnd.build.Project; +import aQute.bnd.build.Workspace; +import aQute.bnd.build.model.BndEditModel; +import aQute.bnd.deployer.repository.LocalIndexedRepo; +import aQute.bnd.osgi.Constants; +import aQute.bnd.service.RepositoryPlugin; +import biz.aQute.resolve.Bndrun; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import okio.BufferedSource; +import okio.Okio; +import org.junit.Before; +import org.junit.Test; + +public final class OsgiTest { + /** Each is the Bundle-SymbolicName of an OkHttp module's OSGi configuration. */ + private static final List REQUIRED_BUNDLES = Arrays.asList( + "com.squareup.retrofit2", + "com.squareup.retrofit2.adapter.guava", + "com.squareup.retrofit2.adapter.java8", + "com.squareup.retrofit2.adapter.rxjava", + "com.squareup.retrofit2.adapter.rxjava2", + "com.squareup.retrofit2.adapter.rxjava3", + "com.squareup.retrofit2.adapter.scala", + "com.squareup.retrofit2.converter.gson", + "com.squareup.retrofit2.converter.jackson", + "com.squareup.retrofit2.converter.jaxb", + "com.squareup.retrofit2.converter.protobuf", + "com.squareup.retrofit2.converter.scalars" + ); + + /** Equinox must also be on the testing classpath. */ + private static final String RESOLVE_OSGI_FRAMEWORK = "org.eclipse.osgi"; + private static final String RESOLVE_JAVA_VERSION = "JavaSE-1.8"; + private static final String REPO_NAME = "OsgiTest"; + + private File testResourceDir; + private File workspaceDir; + + @Before + public void setUp() throws Exception { + testResourceDir = new File("./build/resources/test/retrofit2/osgi"); + workspaceDir = new File(testResourceDir, "workspace"); + + // Ensure we start from scratch. + deleteDirectory(workspaceDir); + workspaceDir.mkdirs(); + } + + /** + * Resolve the OSGi metadata of the all okhttp3 modules. If required modules do not have OSGi + * metadata this will fail with an exception. + */ + @Test + public void testMainModuleWithSiblings() throws Exception { + try (Workspace workspace = createWorkspace(); + Bndrun bndRun = createBndRun(workspace)) { + bndRun.resolve(false, false); + } + } + + private Workspace createWorkspace() throws Exception { + File bndDir = new File(workspaceDir, "cnf"); + File repoDir = new File(bndDir, "repo"); + repoDir.mkdirs(); + + Workspace workspace = new Workspace(workspaceDir, bndDir.getName()); + workspace.setProperty(Constants.PLUGIN + "." + REPO_NAME, "" + + LocalIndexedRepo.class.getName() + + "; " + LocalIndexedRepo.PROP_NAME + " = '" + REPO_NAME + "'" + + "; " + LocalIndexedRepo.PROP_LOCAL_DIR + " = '" + repoDir + "'"); + workspace.refresh(); + prepareWorkspace(workspace); + return workspace; + } + + private void prepareWorkspace(Workspace workspace) throws Exception { + RepositoryPlugin repositoryPlugin = workspace.getRepository(REPO_NAME); + + // Deploy the bundles in the deployments test directory. + deployDirectory(repositoryPlugin, new File(testResourceDir, "deployments")); + deployClassPath(repositoryPlugin); + } + + private Bndrun createBndRun(Workspace workspace) throws Exception { + // Creating the run require string. It will always use the latest version of each bundle + // available in the repository. + String runRequireString = REQUIRED_BUNDLES.stream() + .map(s -> "osgi.identity;filter:='(osgi.identity=" + s + ")'") + .collect(Collectors.joining(",")); + + BndEditModel bndEditModel = new BndEditModel(workspace); + // Temporary project to satisfy bnd API. + bndEditModel.setProject(new Project(workspace, workspaceDir)); + + Bndrun result = new Bndrun(bndEditModel); + result.setRunfw(RESOLVE_OSGI_FRAMEWORK); + result.setRunee(RESOLVE_JAVA_VERSION); + result.setRunRequires(runRequireString); + result.set(Constants.RUNSYSTEMPACKAGES, "sun.misc; version=1.0.0"); + return result; + } + + private void deployDirectory(RepositoryPlugin repository, File directory) throws Exception { + File[] files = directory.listFiles(); + if (files == null) return; + + for (File file : files) { + deployFile(repository, file); + } + } + + private void deployClassPath(RepositoryPlugin repositoryPlugin) throws Exception { + String classpath = System.getProperty("java.class.path"); + for (String classPathEntry : classpath.split(File.pathSeparator)) { + deployFile(repositoryPlugin, new File(classPathEntry)); + } + } + + private void deployFile(RepositoryPlugin repositoryPlugin, File file) throws Exception { + if (!file.exists() || file.isDirectory()) return; + + try (BufferedSource source = Okio.buffer(Okio.source(file))) { + repositoryPlugin.put(source.inputStream(), new RepositoryPlugin.PutOptions()); + System.out.println("Deployed " + file.getName()); + } catch (IllegalArgumentException e) { + if (e.getMessage().contains("Jar does not have a symbolic name")) { + System.out.println("Skipped non-OSGi dependency: " + file.getName()); + return; + } + throw e; + } + } + + private static void deleteDirectory(File dir) throws IOException { + if (!dir.exists()) return; + + Files.walk(dir.toPath()) + .filter(Files::isRegularFile) + .map(Path::toFile) + .forEach(File::delete); + } +}