Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Software AG Application Modularity - OSGi and JPMS (Jigsaw)

120 views

Published on

Presentation from Software AG delivered at the BGJUG meetup in April 2018.

Published in: Technology
  • Be the first to comment

Software AG Application Modularity - OSGi and JPMS (Jigsaw)

  1. 1. © 2018 Software AG. All rights reserved. For internal use only OSGi AND JPMS (JIGSAW) Todor Boev Common Runtime Project APPLICATION MODULARITY
  2. 2. © 2018 Software AG. All rights reserved. For internal use only2 AGENDA • Use Case • Module Layer • Runtime Layer • JPMS (Jigsaw) • OSGi • Conclusion • Q & A
  3. 3. © 2018 Software AG. All rights reserved. For internal use only3 
 TRIED HARD TO BE UNBIASED • Requirements 1. Defined generic use case 2. Defined common sense measure of quality 3. Requirements maximize quality • Evaluation – Implemented the same simple greenfield applications on both – No frameworks – But evaluated how well frameworks can be supported • JPMS / Jigsaw – Applied the best practices recommended by Oracle
  4. 4. | © 2018 Software AG. All rights reserved. For internal use only4 USE CASE
  5. 5. © 2018 Software AG. All rights reserved. For internal use only5 • Modules are consumed – In large numbers – From multiple release streams – The release streams are uncoordinated – The release streams are independent USE CASE COMPOSE APPLICATIONS FROM MODULES
  6. 6. © 2018 Software AG. All rights reserved. For internal use only6 USE CASE COORDINATED RELEASE Lib 1.0 Lib 1.1 Lib 2.0 Log4j 2.0 Log4J 2.1 Log4J 3.0 App 1.1App 1.0 App 2.0
  7. 7. © 2018 Software AG. All rights reserved. For internal use only7 USE CASE UNCOORDINATED RELEASE Lib 1.0 Lib 1.1 Lib 2.0 Log4j 2.0 Log4J 2.1 Log4J 3.0 Log4J 3.1 App 1.2App1.0 App 1.3
  8. 8. © 2018 Software AG. All rights reserved. For internal use only8 
 USE CASE • Measures resilience to change • Where change are the differences between – The environment at compile time – VS the environment at runtime MEASURE MODULARITY A module’s usefulness increases - with the number of environments where it can run - without requiring a rebuild
  9. 9. © 2018 Software AG. All rights reserved. For internal use only9 USE CASE • Resilience to change over time (current modules) – Functionality – Refactoring • Resilience to change of scale (add modules) – Complexity REQUIREMENTS
  10. 10. © 2018 Software AG. All rights reserved. For internal use only10 USE CASE • Module Layer – Handles time – Module artifact – Dependency model (sharing of classes) • Runtime Layer – Handles scale – Module lifecycle (runtime state) – Service Model (sharing of objects) MODULAR SYSTEM STRUCTURE Modular Layer (Classes) Runtime Layer (Objects)
  11. 11. | © 2018 Software AG. All rights reserved. For internal use only11 MODULE LAYER
  12. 12. © 2018 Software AG. All rights reserved. For internal use only12 MODULE LAYER VERSION CHANGES Modules that execute the application meet for the first time at runtime Lib 1.0 Lib 1.1 Lib 2.0 Log4j 2.0 Log4J 2.1 Log4J 3.0 Log4J 3.1 App 1.2App1.0 compile run
  13. 13. © 2018 Software AG. All rights reserved. For internal use only13 MODULE LAYER VERSION CHANGES Lib 1.0 Lib 1.1 Lib 2.0 Log4j 2.0 Log4J 2.1 Log4J 3.0 Log4J 3.1 App 1.2App1.0 App 1.3 compile run Tolerate functionality changes - for as long as possible (1.1.0 → 1.2.0 → 1.3.0) - and then no more (2.0.0)
  14. 14. © 2018 Software AG. All rights reserved. For internal use only14 MODULE LAYER • Refactoring - Improves quality of implementation - Does not affect consumers • Modules should tolerate changes to dependency – IDs • Improve structure: add, remove, rename, merge, split modules – Dependencies • Internal: improve structure • Transitive: e.g. reduce codebase VERSION CHANGES Tolerate refactoring forever (1.0.0 → 1.0.1 → 1.0.2 → 1.0.3 …)
  15. 15. | © 2018 Software AG. All rights reserved. For internal use only15 RUNTIME LAYER
  16. 16. © 2018 Software AG. All rights reserved. For internal use only16 RUNTIME LAYER Consumer API Provider compile run compile • A shared API module exports the interface • A consumer module imports the API in order to call it • A provider module imports the API in order to implement it DISTRIBUTE COMPLEXITY Modules should bind to interfaces not to other modules
  17. 17. © 2018 Software AG. All rights reserved. For internal use only17 RUNTIME LAYER • The Consumer has to obtain objects • … that implement the interface • ... without importing the implementation classes from the Provider Consumer API Provider load interface load interface get impl object? DISTRIBUTE COMPLEXITY
  18. 18. © 2018 Software AG. All rights reserved. For internal use only18 RUNTIME LAYER 1. Publish: provider advertises implementation 2. Find: consumer selects implementation 3. Bind: consumer gets implementation object Consumer ProviderService (1) publish(3) bind (2) find DISTRIBUTE COMPLEXITY Service – communication mechanism provided by the modular system
  19. 19. © 2018 Software AG. All rights reserved. For internal use only19 RUNTIME LAYER DISTRIBUTE COMPLEXITY Library Library Library Application Library factory factory factory factory object object object • At the end of the exchange who owns the object? • Consumer – Complexity is Concentrated – Libraries
  20. 20. © 2018 Software AG. All rights reserved. For internal use only20 • At the end of the exchange who owns the object? • Provider – Complexity is Distributed – Dependency Injection – Services Module Module Module Module Module object object object object RUNTIME LAYER DISTRIBUTE COMPLEXITY
  21. 21. | © 2018 Software AG. All rights reserved. For internal use only21 JPMS / JIGSAW
  22. 22. © 2018 Software AG. All rights reserved. For internal use only22 JPMS • Minimal – Define features required to boot • Familiar – Quickly transition to Java Code – Use traditional patterns PHILOSOPHY - SIMPLICITY
  23. 23. | © 2018 Software AG. All rights reserved. For internal use only23 JPMS
 MODULE LAYER
  24. 24. © 2018 Software AG. All rights reserved. For internal use only24 JPMS MODULE LAYER • A module is – A jar – That contains additional metadata – And an optional main() method • The metadata is binary – /module-info.class • The metadata is authored by humans – Compiled from source: /module-info.java – Compiler options: --module-version 1.2.3 ARTIFACT
  25. 25. © 2018 Software AG. All rights reserved. For internal use only25 JPMS MODULE LAYER ARTIFACT import org.example.hello.HelloFactory; import org.example.hello.provider.en.EnJsonHelloFactory; module org.example.hello.provider.en { requires org.example.hello.api; provides HelloFactory with EnJsonHelloFactory; } • /module-info.java
  26. 26. © 2018 Software AG. All rights reserved. For internal use only26 JPMS MODULE LAYER • Modules provide java packages • Modules can be versioned at compile time – Versions are ordered – Version number tokens have no assigned meaning: 
 3.14.159.256.358+irrational-pi MODULES PROVIDE // May pass --module-version 1.2.3 to javac module org.example.hello.api { exports org.example.hello; }
  27. 27. © 2018 Software AG. All rights reserved. For internal use only27 JPMS MODULE LAYER • Modules require other modules by their ID – The ID becomes part of the module API • Require a module only as a compile dependency • Runtime dependencies must be handled by the build MODULES REQUIRE module org.example.hello.consumer { // May capture 1.2.3 // Can’t declare that max acceptable is 2.0.0 requires org.example.hello.api; // Can’t say I want an impl of the API //requires org.example.hello.provider.en; // Can’t say a want a framework, not packages //requires dependency.injection.fw; }
  28. 28. © 2018 Software AG. All rights reserved. For internal use only28 JPMS MODULE LAYER • Build: – Resolve dependency graph: compile, runtime – Select compatible versions • Runtime: – Check dependency graph: compile – Trust versions are compatible • Module metadata is the build script – Of arbitrary quality, artifact repository, versioning policy: • ant + /lib, make, maven + pom.xml, gradle + ivy.xml • JPMS does not enforce nor define compatibility – Nothing for builds to coordinate on FUNCTIONALITY CHANGES /module- info.java pom.xml build.gradle
  29. 29. © 2018 Software AG. All rights reserved. For internal use only29 JPMS MODULE LAYER • Improving modular structure – Adding a module is a minor change: 1.0 -> 1.1 – Removing a module is a major change: 1.0 -> 2.0 – Even if the functionality is only redistributed • Offsetting via façade is a minor change: 1.0 -> 1.1 REFACTORING CHANGES module org.example.hello.api { requires transitive refactored.one; requires transitive refactored.two; }
  30. 30. © 2018 Software AG. All rights reserved. For internal use only30 JPMS RUNTIME LAYER • Minimal – Define features required to boot • Describes class isolation boundary to JVM: • Familiar – Quickly transition to Java Code – Use traditional patterns PHILOSOPHY - SIMPLICITY requires org.example.hello.api; /module-info.java /module-info.java
  31. 31. | © 2018 Software AG. All rights reserved. For internal use only31 JPMS
 RUNTIME LAYER
  32. 32. © 2018 Software AG. All rights reserved. For internal use only32 JPMS RUNTIME LAYER • Provider publishes: • Best practice requires to publish a factory rather than the service class itself SERVICES - PUBLISH import org.example.hello.HelloFactory; import org.example.hello.provider.en.EnJsonHelloFactory; module org.example.greeter.provider.en { requires org.example.hello.api; provides HelloFactory with EnJsonHelloFactory; } (service factory interface, service factory class)
  33. 33. © 2018 Software AG. All rights reserved. For internal use only33 JPMS RUNTIME LAYER SERVICES - FIND import org.example.hello.HelloFactory; module org.example.hello.consumer { requires org.example.hello.api; uses HelloFactory; } // The factory must be very cheap to make Iterable<HelloFactory> hellos = ServiceLoader.load(HelloFactory.class); for (HelloFactory hf : hellos) { // The factory must provide info methods if ("en".equals(hf.getLanguage()) && "json".equals(hf.getFormat())) { ... } } • Matching done by best practice – Must be followed by both
 provider and consumer
  34. 34. © 2018 Software AG. All rights reserved. For internal use only34 JPMS RUNTIME LAYER SERVICES - BIND • The consumer controls the service object lifecycle HelloFactory hf = ... // Bind: create, configure, start, stop, destroy Hello greeter = hf.createHello(); greeter.setPrettyPrint(true); // Use String msg = greeter.message(“OSGi”); System.out.println(msg);
  35. 35. © 2018 Software AG. All rights reserved. For internal use only35 JPMS RUNTIME LAYER • One module can have a main() method – Control flows from there – Set by compiler option: 
 --main-class org.example.hello.consumer.Greeting LIFECYCLE
  36. 36. © 2018 Software AG. All rights reserved. For internal use only36 JPMS RUNTIME LAYER • Minimal – Define features required to boot: • Start from: • A map of interface-to-class: • Familiar – Quickly transition to Java Code • Find, Bind done by arbitrary code – Use traditional patterns • Publish class • Publish factory class PHILOSOPHY - SIMPLICITY void main(String[] args) provides HelloFactory with EnJsonHelloFactory; ServiceLoader.load(HelloFactory.clas s);
  37. 37. | © 2018 Software AG. All rights reserved. For internal use only37 JPMS
 SUMMARY
  38. 38. © 2018 Software AG. All rights reserved. For internal use only38 JPMS SUMMARY PHILOSOPHY Library Library Library Application Library factory factory factory factory object object object An application is composed of user code and libraries • A library provides classes to applications • The app code composes the
 library classes • As libraries are added 
 the app code complexity
 grows unchecked
  39. 39. © 2018 Software AG. All rights reserved. For internal use only39 JPMS SUMMARY FRAMEWORKS • Standardizes publish, half of find, no bind – Hard to make code that – … can access objects from another module – … using a framework neutral mechanism • Framework fragmentation/lock in – Frameworks spread over multiple modules – Can’t consume modules that don’t use your
 framework Guice CDI
  40. 40. | © 2018 Software AG. All rights reserved. For internal use only40 OSGI
  41. 41. © 2018 Software AG. All rights reserved. For internal use only41 OSGI • Simple textual protocols (HTTP headers) – Closed format (REST verbs) – Open semantics (REST message mime type) • Public contracts (mime type registry) • Self contained (REST self descriptive messages) PHILOSOPHY – COMPOSABILITY
  42. 42. | © 2018 Software AG. All rights reserved. For internal use only42 OSGI
 MODULE LAYER
  43. 43. © 2018 Software AG. All rights reserved. For internal use only43 OSGI MODULE LAYER • A bundle (module) is – A jar – That contains additional metadata – And an optional start/stop hook • The metadata is textual – /META-INF/MANIFEST.MF • The metadata is generated (semi)automatically from the application code ARTIFACT
  44. 44. © 2018 Software AG. All rights reserved. For internal use only44 • package-info.java OSGI MODULE LAYER ARTIFACT package org.example.hello; // Guides importers: [1.2, 2) @ProviderType public interface Hello { String message(String who); } @Export @Version("1.2.3") package org.example.hello; • Hello.java
  45. 45. © 2018 Software AG. All rights reserved. For internal use only45 • Extract Modular Pattern – Namespace ← – Capability ← – Requirement ← – Resolver ← OSGI MODULE LAYER • Identity (coupled, brittle) – • Capability (decoupled, modular) – – – IDENTITY VS CAPABILITY provides HelloFactory with EnJsonHelloFactory uses HelloFactory HelloFactory hf = new EnJsonHelloFactory(); interface HelloFactory provides ... with EnJsonHelloFactory uses HelloFactory java.util.ServiceLoade r java.util.ServiceLoade r
  46. 46. © 2018 Software AG. All rights reserved. For internal use only46 OSGI MODULE LAYER • Bundles provide Capabilities – Namespace – Set of attributes (Fixed set of data types) • The Version type is semantic: – <major>.<minor>.<micro>-<qualifier> • Java package capabilities have shorthand syntax: MODULES PROVIDE osgi.wiring.package osgi.wiring.package:String = org.example.hello version:Version = 1.2.3 Export-Package: org.example.hello; version=1.2.3
  47. 47. © 2018 Software AG. All rights reserved. For internal use only47 OSGI MODULE LAYER • Bundles declare Requirements – Namespace – A filter to match the attributes of a Capability • Java package requirements have shorthand syntax: MODULES REQUIRE osgi.wiring.package (&(osgi.wiring.package = org.example.hello) (version >= 1.2) (!(version >= 2))) Import-Package: org.example.hello; version=“[1.2, 2)”
  48. 48. © 2018 Software AG. All rights reserved. For internal use only48 OSGI MODULE LAYER • Semantic version range FUNCTIONALITY CHANGES Import-Package: org.example.hello; version=“[1.2, 2)” [1.2, 2) Hello 1.2 Hello 1.5 Hello 1.9 Consumer Consumer Consumer Hello 2.0 run compile
  49. 49. © 2018 Software AG. All rights reserved. For internal use only49 OSGI MODULE LAYER • Capabilities have open semantics • Resolver resolves symbolically any dependency you care to invent • (Your) Bundles introspect the dependency graph and act – The core does the same for packages REFACTORING CHANGES Provide-Capability: osgi.service; objectClass:List<String> = "org.example.hello.Hello" Provide-Capability: osgi.extender; osgi.extender = "osgi.jpa"; version:Version = "1.1"
  50. 50. © 2018 Software AG. All rights reserved. For internal use only50 OSGI MODULE LAYER • Requirements have open semantics REFACTORING CHANGES Require-Capability: osgi.service; filter := "(objectClass=org.example.hello.Hello)" Require-Capability: osgi.extender; filter := "(&(osgi.extender=osgi.jpa)(version>=1.1))" Require-Capability: osgi.native; filter := "(& (osgi.native.osname ~= win32) (osgi.native.processor ~= x86-64) (osgi.native.language ~= en))"
  51. 51. © 2018 Software AG. All rights reserved. For internal use only51 OSGI MODULE LAYER • Simple textual protocols – Closed format • Provide: • Require: – Open semantics • references an external description • Public contracts – E.g the OSGi alliance maintains the osgi.wiring.package namespace • Defines that capabilities have a package name and a version • Defines how implementations (the OSGi core) use these to direct class loading • Self contained – A bundle describes everything it provides and everything it requires to run PHILOSOPHY - COMPOSABILITY (namespace, attributes) (namespace, filter) /META-INF/MANIFEST.MF Semantic Versioning Semantic Dependencies namespace
  52. 52. | © 2018 Software AG. All rights reserved. For internal use only52 OSGI
 RUNTIME LAYER
  53. 53. © 2018 Software AG. All rights reserved. For internal use only53 OSGI RUNTIME LAYER • Provider publishes: • Provider manages the service object’s lifecycle – I.e. this is a service architecture SERVICES - PUBLISH public void start(BundleContext bc) { // Arbitrary code. Inject with other services and configuration Hello service = new HelloImpl(); // Impl description Dictionary<String, Object> props = new Hashtable<>(); props.put("lang", "en"); props.put("format", "json"); // Publish under the service interface. Impl is private. bc.registerService(Hello.class, service, props); } (service interface, service object, attributes)
  54. 54. © 2018 Software AG. All rights reserved. For internal use only54 OSGI RUNTIME LAYER • Consumer searches by: SERVICES - FIND // Ask directly for a business object // Filter matched against business object publication attributes // The ServiceLoader of OSGi ServiceTracker<Hello,Hello> greeters = new ServiceTracker<>( bc, Hello.class, "(&(lang=en)(format=json))"); (service interface, filter)
  55. 55. © 2018 Software AG. All rights reserved. For internal use only55 OSGI RUNTIME LAYER • Since the provider manages it’s published object • The consumer binds directly to a business object – I.e. this is a service architecture SERVICES - BIND // Find ServiceTracker<Hello,Hello> greeters = new ServiceTracker<>( bc, Hello.class, "(&(lang=en)(format=json))"); // Bind: No further setup needed Hello greeter = greeters.getService(); // Use String msg = greeter.message(“OSGi”); System.out.println(msg);
  56. 56. © 2018 Software AG. All rights reserved. For internal use only56 OSGI RUNTIME LAYER • Each bundle has an independent lifecycle – Creates, configures, activates, deactivates, destroys – … it’s own internal structure – … so it can publish objects rather than classes • The application behavior emerges from the combined activity of peer bundles LIFECYCLE
  57. 57. © 2018 Software AG. All rights reserved. For internal use only57 OSGI RUNTIME LAYER • Simple (semi)textual protocols – Closed format • Publish (Provide): • Find (Require): – Open semantics • The (namespace) can represent anything • Public contracts – The provider defines the API: packages, classes, allowed attributes • Self contained – Each bundle has a dedicated lifecycle PHILOSOPHY - COMPOSABILITY (service interface, service object, attributes) (service interface, filter) service interface
  58. 58. | © 2018 Software AG. All rights reserved. For internal use only58 OSGI
 SUMMARY
  59. 59. © 2018 Software AG. All rights reserved. For internal use only59 OSGI SUMMARY • Each bundle manages part of the
 total state and lifecycle • Initial bundle complexity is higher
 then a library • As bundles are added the
 individual bundle complexity remains
 constant PHILOSOPHY A complex application is composed of simple collaborating applications Module Module Module Module Module object object object object
  60. 60. © 2018 Software AG. All rights reserved. For internal use only60 OSGI SUMMARY FRAMEWORKS • Standardizes publish, find, bind – Possible to make code that – … can access objects from another module – … using a framework neutral mechanism • Enables framework interoperation – Multiple frameworks within one application – Even multiple JVM languages CDI CDI Guice
  61. 61. © 2018 Software AG. All rights reserved. For internal use only61 OSGI SUMMARY FRAMEWORKS – DECLARATIVE SERVICES // Publish @Lang("en") // Part of hello API @Format("text") // Part of hello API @Component public class HelloImpl implements Hello { @Override public String message(String who) { return "Hello " + who; } } // Find + Bind @Component(immediate = true) public class Greeter { @Activate public void activate(@Reference Hello hello) { System.out.println(hello.message("OSGi")); } } • Frameworks dramatically lower bundle complexity
  62. 62. | © 2018 Software AG. All rights reserved. For internal use only62 CONCLUSION
  63. 63. © 2018 Software AG. All rights reserved. For internal use only63 CONCLUSION PIVOTAL DECISIONS Decision OSGi JPMS Philosophy Composability Simplicity Module Style Self-Contained Library Module Layer Compatibility Semantic Versions Require Capability Identity Runtime Layer Share Services / Objects Factories / Classes Lifecycle Module Application
  64. 64. © 2018 Software AG. All rights reserved. For internal use only64 Module (Dependency Injection) object object object object Process (OSGi) module module module module System (Micro Services) process process process process CONCLUSION SERVICES ALL THE WAY DOWN
  65. 65. © 2018 Software AG. All rights reserved. For internal use only65 CONCLUSION GOING FORWARD • Both can be a powerful combination – OSGi: efficient modular application – JPMS: efficient JRE to match the application • OSGi R7 – Enable jars to work as either a Bundle or a JPMS module – Detect the modules of the underlying JRE at runtime • Next Step – Provisioning: automatically assemble an OSGi + JPMS runtime
  66. 66. © 2018 Software AG. All rights reserved. For internal use only66 RESOURCES • OSGi – Architecture: https://www.osgi.org/developer/architecture/ – Service Layer: http://enroute.osgi.org/doc/215-sos.html • JPMS – Module Layer (Alex Buckley): https://youtu.be/gtcTftvj0d0 – Service Layer (Alex Buckley): https://youtu.be/RjVjm4uuMvc • OSGi interop with JPMS – http://blog.osgi.org/2018/02/osgi-r7-highlights-java-9-support.html – http://blog.osgi.org/2017/09/letter-to-our-osgi-user-community-re.html • JPrime on Modularity – https://youtu.be/NKS5VU_r7Bo
  67. 67. | © 2018 Software AG. All rights reserved. For internal use only67 Q & A

×