Thanks Peter,

I'm sure it'll take me some time before I digest this properly, multi language interop, since type systems don't translate well between languages, it makes a lot of sense to have loose coupling. Flattening out the inheritance heirarchy also makes a lot of sense.

I've attached some ascii art of what I spoke about earlier.

A little more info on JERI:

https://pfirmstone.github.io/JGDMS/doc/api/net/jini/jeri/package-summary.html

Cheers,

Peter.



On 22/02/2017 7:20 PM, Peter Kriens wrote:
Interesting. And never let me stop you from using this in OSGi!

That said, let me explain what my favorite model is today.

I use DTOs. These are simple Java objects (String, primitives and their 
wrappers), collections, maps, arrays, and objects but only public fields. No 
inheritance, limited generics (no type variables). i also support objects that 
have a string constructor and a toString() that can be used as input for the 
String constructor.

I allow the sender side and the receiver side to use different types. All the 
DTO types can easily be serialized to JSON, but loose the oh so important type 
information. The receiver type has a matching type but it does not have to be 
the same as the sender’s type. The only requirement is that the receiver’s type 
is a proper template of the incoming JSON stream. This nicely decouples the 
sender and the receiver, actually, in many cases the sender and receiver are 
written in different languages. All this without loosing the all importance 
aspect that both my sender and receiver work in type safe Java using all the 
goodies of Java with specific collection types, maps, and generics.

Clearly since there is no authority between the sender and receiver managing the same 
scheme between sender and receiver you can get mismatches. I address this with 
versions in the DTOs (normal field) and on deserialization taking advantage of a 
magic Map<String,Object>  field in the DTO (__extra). When the deserializer 
sees a field it does not recognize it puts it in __extra map. (If it does not exist 
it fails.) Since the deserializer has built in rules for converting JSON to Object 
the receiver can figure out what went wrong.

I find this a very nice balance between having the goodies of type safety when 
writing code and decoupling of the sender and receiver. I’ve worked a lot with 
Javascript and this model gives you basically the same advantages of high 
productivity and loose coupling you get in Javascript without giving up the 
goodies of Java’s type system.

Kind regards,

        Peter Kriens



On 21 Feb 2017, at 12:29, Peter<j...@zeus.net.au>  wrote:

Christian,

I will investigate it, if I can navigate a path through the serialization 
issues.  It is actually looking quite positive.

Peter,

Well, I wouldn't jump to conclusions too soon, it's still worth a look, a lot 
of the features will look familiar to OSGi devs.

The discovery protocols support IPv6 Multicast.  Preparations have been made 
for protocol extensibility (other than Java Seriailization), such as the case 
with MarshalledInstance, and you'll also notice it's get method allows a 
ClassLoader to be passed in:

https://github.com/pfirmstone/JGDMS/blob/Maven_build/modularize/JGDMS/jgdms-platform/src/main/java/net/jini/io/MarshalledInstance.java

MarshalledInstance.get(final ClassLoader defaultLoader,
              final boolean verifyCodebaseIntegrity,
              final ClassLoader verifierLoader,
              final Collection context)
    throws IOException, ClassNotFoundException

MarshalInputStream's constructor also accepts a ClassLoader to use for 
deserialization.

https://github.com/pfirmstone/JGDMS/blob/Maven_build/modularize/JGDMS/jgdms-platform/src/main/java/net/jini/io/MarshalInputStream.java

AtomicMarshalInputStream has a similar constructor.

RMI's MarshalInputStream doesn't accept a ClassLoader argument and neither does 
ObjectInputStream.

JERI, which stands for Jini Extensible Remote Invocation, is not Java RMI.  
It's been updated to support TLSv1.2, using the latest secure cyphers with 
perfect forward secrecy.  HTTPS and Kerberos are also supported transport 
protocols.  JSON over HTTPS would be an obvious future enhancement.

I've also restructured the project into bundles, and created proxy bundles so 
we've got the same bundle at each Endpoint, I'm currently working on a 
ModularExporter interface method that accepts a ClassLoader argument, allowing 
the developer to determine the ClassLoader where deserialization will occur on 
the server side.  All provided services will use this when available.

For example, if I have a service implementation, I use an exporter to create a 
proxy that implements remote interfaces and uses the underlying JERI transport, 
the ClassLoader argument allows me to direct the ClassLoader in which the 
java.lang.reflect.Proxy will be loaded to perform the back end communications, 
I can give it the ClassLoader of the Smart Proxy bundle, ensuring that the same 
bundle is loaded at each endpoint, so that all the private objects in the Smart 
Proxy bundle can be found, that will form the parameter arguments invoked on 
the service implementation back end.

Some of the warts around Entry classes (Entry extends Serializable, all fields 
are public they're the DTO's your talking about I guess) is that these are 
sensitive to change, for example adding a field to an existing Entry with a 
subclass will break the subclass, so versioning will assist greatly with these. 
 Entry's are of course used in the ServiceRegistrar and JavaSpaces.  The 
ServiceRegistrar doesn't deserialize, it matches on serial form, this could be 
changed to other protocols, but currently its java serialized form for each 
field in an Entry, the Entry itself is generally not intended to be Serialized.

However many classes aren't Serializable at all, such as this strictly RFC3986 
compliant immutable URI (where strict compliance allows bitshift operations for 
string normalization, this one is lightening fast), it also has an implies 
method that replicates the functionality of CodeSource.implies(), but 
magnitudes faster:

https://github.com/pfirmstone/JGDMS/blob/Maven_build/modularize/JGDMS/jgdms-platform/src/main/java/org/apache/river/api/net/Uri.java

Why Serialize an object when you can just send a string and parse it back at 
the other end?

Hundreds of bugs identified by findbugs have been fixed in recent years as have 
numerous race conditions, the codes a lot cleaner and maintainable than it used 
to be.

I think it's worth the experiment, it still has a few good features, and may 
provide a migration path for some.

Cheers,

Peter.

On 21/02/2017 6:04 PM, Peter Kriens wrote:
My personal expectation is that Jini is entrenched on the Java serialization 
quagmire that you probably have to work around a lot more problems than the 
myriad of discovery and transport protocols that are currently available in 
Java?

It is a pity because Jini and OSGi started in the same time and we had 
discussions together.

Kind regards,

Peter Kriens

On 21 Feb 2017, at 07:25, Christian 
Schneider<ch...@die-schneider.net<mailto:ch...@die-schneider.net>>  wrote:

Have you thought about implementing the jini support as a discovery and 
transport for Remote Service Admin?
I am not sure if it fully matches as jini is special in some aspects but I see 
many similarities.

Christian

2017-02-21 0:56 GMT+01:00 Peter<j...@zeus.net.au<mailto:j...@zeus.net.au>>:

    Sounds like you've been burnt.

    Modular or die, no hacked compromises, won't support unworkable
    complex non-modular cases, only support what works.

    For updates:
    1. Server module advises proxy's of graceful shutdown, proxy's
    unregister services with OSGi registrar (or just stop working in
    hard shut or disconnection, in which case they are discarded).
    2. Server unregisters from Jini service registrar and unexports.
    3. Server performs upgrades
    4. Server exports and reregisters with jini service registrar
    5. Service is dynamically discovered by ServiceDiscoveryManager
    in clients, smart proxy's are provisioned and registered with
    local OSGi registrar.
    6. Clients notified of service availability.

    The smart proxy bundle must be of identical version at both
    endpoints, connection must be refused if this is not the case.

    Service api bundles are separate from smart proxy bundles.

    Clients don't import packages from smart proxy.

    The smart proxy contains the api for communication between proxy
    and remote service only.  Only service implementation imports
    packages from smart proxy.  Communication method and
    communication api is a private implementation concern.

    The services smart proxy imports the service api packages, as
    does the client.  Service api is compatibility layer between
    smart proxy and client.  The smart proxy is a provider of the
    service api, the client is the consumer.

    Service api update is client responsibility, not likely to update
    often.  Prefer to add mixin interfaces or replace api (new
    service type) over breaking change.   Smart proxy needs to
    deregister when service api is updated (should listen for event
    notifications).

    Service will only be rediscovered if it is compatible.

    As the smart proxy needs to be resourced and provisioned it is
    this stage of the process where it may not be found api
    compatible with the client, in which case it will not be
    discovered by the client...

    The service can advertise its requirements (incl packages and
    versions) via the Jini service registrar, services that are not
    api compatible will be filtered out.

    The server / service remains responsible for maintaining
    compatibility.

    Discovery is dynamic.

    We've had some discussion on river-dev, one user wanted much
    wider support scope including remote objects with code download
    that are not services, also wanted to use codebase annotations
    and non osgi URLClassLoaders with bundle ClassLoaders as parents,
    using Context ClassLoader to find bundle ClassLoader.  Agree
    that's an unworkable scenario due to complexity.

    I want to keep this as simple as possible for obvious reasons.     Force 
communication method to be an implementation concern,
    allowing it to be replaced in future.

    Regards,

    Peter.

    Sent from my Samsung device.
    ---- Original message ----
    From: Peter Kriens<peter.kri...@aqute.biz
    <mailto:peter.kri...@aqute.biz>>
    Sent: 21/02/2017 12:24:39 am
    To: OSGi Developer Mail List<osgi-dev@mail.osgi.org
    <mailto:osgi-dev@mail.osgi.org>>
    Subject: Re: [osgi-dev] OSGifying an existing application

    The problem is that in all distributed I’ve been involved in
    there were rolling updates. This implies that you cannot
    guarantee that each server runs the same bundle. And clusters
    that do not do rolling updates seem kind of useless because they
    introduce a huge failure point. So I have a hard time
    understanding how you can guarantee that invariant? Yes, it works
    most of the time but when I learned to work with computers that
    tended not be good enough.

    Now I do understand ( and sympathise) that you cannot change the
    app. I’ve been there.

    You indicate you have the same bundle on both sides. So the class
    graph on both sides is equal. This implies that if you ensure
    that the API interface is in the same bundle as the
    implementation classes then you’re safe as long as you use the
    interface’s class loader as the root loader for classes you find.
    This is of course highly not modular but then you’re not anyway
    under the covers :-) You could also make the API bundle import
    the implementation bundles, that should work as well.

    As long as you make sure OSGi has the proper dependency
    information things tend to work out of the box.

    Kind regards,

    Peter Kriens


    On 20 Feb 2017, at 11:47, Peter<j...@zeus.net.au
    <mailto:j...@zeus.net.au>>  wrote:

    Thanks Pete, good to hear from you again, I must admit it's been
    too long.  We last spoke when I was refactoring a class
    dependency tool to use ASM instead of the jdk's tools.jar.  You
    once asked, how do you find a dependency for calls to Class.forName?

    The reasons you've stated are also why I've chosen to support a
    very narrow use case, in which you may have already noted that
    the serialized connection is between two identical bundles, in
    separate jvm's with compatible package imports.

    There’s no intent to support transferring any classes outside of
    the Service Now API and that includes overriding classes.  What
    you describe about data hiding reminds me of Entry's, which have
    public fields.

    I'll be the first to admit there are significant issues with the
    design of Java's Serialization's extralinguistic api.
      Ironically though the wire protocol is reasonably well thought
    out, with regards to evolution.

    As an exercise to fix security issues, I have reimplemented Java
    serialization with input validation using a public api, it has
    backward compatible serial form, but only supports a subset of
    Java serialization, it doesn't support circular object graphs
    for example as this would compromise security.   It performs
    input validation, sets resource limits and expects periodic
    stream resets to avoid DOS and gadget attacks. The problem is
    there's a lot of existing software that utilises java
    Serialization, that's going to need support for some time.
      Things like Serialization and Remote method invocation are
    damaged by attempts to implement too much functionality, when a
    more rigid subset would avoid a number of issues.  But I guess
    no one was thinking of modularity and versioning when they
    created these frameworks either.

    James Gosling said something once about why Generics weren't
    included in Java from the outset, which was because at the time
    they didn't know how to do it properly, it's better leaving it
    out until you do.

    JBoss has a nice web page with some graphics that illustrate
    some major issues with implementation hiding you've mentioned
    with Serialization and modular frameworks here:
    https://developer.jboss.org/wiki/ModularSerialization
    <https://developer.jboss.org/wiki/ModularSerialization>

    It's worth noting Service API of the smart proxy bundle doesn't
    need to be Serializable, instead it's relegated to a
    communication means between two identical bundles in different
    JVM's.   It's also important to recognise that it doesn't need
    to be the communcation mechanism either.   These bundles have an
    identical class namespace, although there may be variances in
    package import versions.

    Yes we are also looking at moving away from java serialization.

    Also over time, because this is a service interface, at some
    point down the track, serialization can be replaced, without
    impacting the public api.  So yes the underlying protocols can
    be stripped out to data and message passing if that's more
    satisfactory.

    So yes java serialization is an existing part of our application
    and it has it's warts.

    But we've also had a number of users over the years who have
    requested support for OSGi.

    This is not a greenfields project, I'm hoping that I'm not going
    to be told that no, the chasm is too wide you can't cross over
    to OSGi, rewrite or start again, there's just too many LOC.

    So you have raised some important questions.  Some of our users
    have had a lot of success with Maven (recognising there a pro's
    and cons's with module based versioning and transitive
    dependencies), where versioning on a module level allows
    codebase annotations to be utilised in remote invocation,
    avoiding class visibility issues by mapping module ClassLoader's
    directly to a URI based identity.  However with OSGi there's a
    mismatch between different jvm's and how bundles and packages
    imports will be resolved will end up being wired, so we can't
    rely on codebase annotations for OSGi.

    Jvm's using OSGi frameworks are quite likely to have different
    dependency graphs (wires) between bundles and their package imports.

    While I don't expect to solve the worlds problems or boil the
    ocean, I'm looking for the most workable compromise, one that
    doesn't promise the world and is easier to explain what users
    can and can't expect to do.  I'm relatively pragmatic.  To me it
    would seem logical that a subset where two identical bundles
    (that should have resolved similar package import versions)
    should be a good place to start.

    Hence my post on this list, as I realise many of you have
    already spent a lot of time bumping into these issues.

    Cheers,

    Peter.

    On 20/02/2017 6:38 PM, Peter Kriens wrote:
    After working in this area for too many years I’ve come to the
    conclusion that objects cannot be really transferred to other
    systems in a reliable way, only self typed data can. JPA, RMI,
    and many other systems promise heaven to the programmer that
    they can use their objects local and remote transparently. The
    consequence of this dream is a huge amount of complexity that
    far outweighs any gains in programmer friendliness. Few things
    have caused so much trauma in the software world as ORM.
    (Persistence is communications to a future process.)

    The reason objects are so complex to use in communications is
    that it is in direct violation of the goal of OO to hide your
    data. However, once you expose the internal data on the wire
    you have effectively made it public but too many people they
    can still have the advantages of abstract data types. OSGi is a
    bitch in this case because it tells you that you’re trying to
    do something wrong by refusing to cooperate. In this case, it
    balks at you because you create an invisible dependency between
    the sender and the receiver. Though this is a good thing too
    often the receivers of this message blame the messenger.

    You can handle this dependency but you’ll find out is that it
    is a hugely complex task that introduces a lot of frailty in
    the overall system. Having tried this several times I can
    assure you that any gains in programmer friendliness are
    dwarfed by the complexity of creating this facade.

    The best solution I found is to give up on data hiding. The
    fact your objects is on the wire means that that wire format is
    public. I therefore use Data Transfer Objects, in my case
    objects with public fields. On both sides I have my own objects
    to provide behavior to this data with methods and classes but
    this data record is at the core of my code. Since this data is
    public because it goes over the wire it is better to wrap you
    code around that ‘standardized public’ object than to try you
    internal object data.

    If you look at the OSGi specifications of the past 5 year then
    you will notice that all applicable APIs have been designed to
    be useful with Distributed OSGi. Calls do not pass objects but
    they pass DTOs back and forth. They do not rely that the
    receiver and sender have exactly the same type and version. In
    this model it is easy to replace an endpoint using another
    language, which is a really good sign.

    For Java developers this is often an unpleasant message, and
    quite often OSGi get the blame. However, the fact OSGi gives
    you these problems means that you’re trying to do something
    that has hidden dependencies.

    Distributed computing has 7 well known fallacies[1] but I
    strongly believe that there is an eighth: ’One can communicate
    objects over a network’.

    Now your question. Yes, you could run a resolve and load the
    proper bundles but you introduce a huge amount of error cases
    and a large amount of complexity and you won’t solve the
    fundamental problem

    Kind regards,

    Peter Kriens

    [1]:
    
https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing<https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing>


    On 20 Feb 2017, at 05:13, Peter<j...@zeus.net.au
    <mailto:j...@zeus.net.au><mailto:j...@zeus.net.au
    <mailto:j...@zeus.net.au>>>  wrote:

    Hello,

    I'm currently working on converting an existing application to
    OSGi.

    This application has a network service architecture based on
    java interfaces.  I've broken the application into modules,
    using a Maven build, which uses bnd and bndtools to create
    bundle manifests.  Some of these modules are ServiceLoader
    provider's, so I've used annotations to ensure these are
    loaded into the OSGi service registry using the Service Loader
    Mediator.

    The main issue that I face is this application is a networked
    application and has it's own Remote Invocation protocols
    (which currently utilise Java Serialization, but not Java
    RMI).  As you'll appreciate, class visiblity is a little
    different in OSGi.  :)

    The services mentioned above are remote services, these remote
    services have a proxy which implements the service interface,
    these services are discovered and installed at the client.     There are 
two types of proxy's, one, called a smart proxy,
    requires a codebase from which to retrieve a jar or jar files
    that are downloaded and installed at the cleint (traditionally
    during deserialization),  the other type of proxy is called a
    dynamic proxy (it's basically just an instance of
    java.lang.reflect.Proxy), which is dynamically generated at
    the client.

    The Service implementation is broken up into three components:

    1. The service api
    2. The smart proxy (resolved and provisioned into in client jvm).
    3. The server

    The server bundle imports packages from the smart proxy
    bundle, while the smart proxy imports packages from the
    service api as well as exporting it's own packages, as
    required by the server bundle.

    The server that provides the remote service has three bundles
    loaded; server-impl, smart-proxy&  service-api.

    The client only has the service api bundle installed at
    deployment and the smart proxy is resolved and provisioned
    before the service is made available via the local OSGi
    service registry, where the client will learn of it's
    existence using ServiceTracker.

    At first glance only the smart proxy bundle needs to be
    provisioned at the client, however for cases where a dynamic
    proxy is required to implement interfaces from different
    packages, where class visibility issues may exist, it may be
    beneficial in these cases to utilise and provision a proxy
    bundle that imports all these interfaces, one might do that by
    taking advantage of java's interface multiple inheritance;
    create a bundle that contains one interface (annotated with
    @ProviderType) which extends all interfaces, which the bundle
    doesn't export, so we ensure that the dynamic proxy has a
    proper bundle manifest with all package imports and version
    ranges correctly defined.

    The inbuilt remote invocation protocol has server and client
    endpoints, the protocol is extensible and has a number of
    implementations (for example https, http, tls, kerberos, tcp).
      Each endpoint is assigned a ClassLoader when it's created.

    For classes installed at the client, these are typically
    installed in a URLClassLoader, typically with the Application
    loader as parent loader.  In an OSGi environment however, the
    smart proxy bundle will be installed at the client, it's
    ClassLoader utilised by the client endpoint, the smart proxy
    bundle will also be installed at the server and it's
    ClassLoader utilised by the server endpoint.   In this case
    the visibility of the bundles at each endpoint will be
    utilised to resolve serializable classes.    Private smart
    proxy serializable classes will be resolvable at each end, but
    only public classes from imported packages will be
    deserializable, since the client interacts using the Service
    API, all serializable classes in the Service API packages will
    need to be exported and public and imported by the client and
    smart proxy.

    Once a bundle has been provisioned its ClassLoader will be
    given to the client endpoint and the marshalled state of the
    proxy unmarshalled into it.  At this point the service that
    the proxy provides would be registered with the OSGi service
    registry for the client to discover and consume.  The smart
    proxy communicates with it's server via an internal dynamic
    proxy (java.lang.reflect.Proxy), it's used to invoke methods
    on the server.

    While the existing protocol uses Java serialization, it
    doesn't use Java serialization's method of resolving classes
     Java Serialization walks the stack and finds the first non
    system classloader (looking for the application ClassLoader).
       The existing class resolution method isn't suitable for
    OSGi, however the mechanism is extensible, so can be replaced
    with something suitable.



    Does anyone have any advise or experience utilising the OSGi
    Enterprise Resolver Service Specification (chapter 136) and
    the OSGi Enterprise Repository Service Specification (chapter
    132) to resolve and provision a bundle for the smart proxy at
    the client?



    The intent here is the bundle manifests at each endpoint will
    be used to determine class visiblity, so the resolution and
    provisioning process will be of critical importance.

    For anyone curios, the application is a fork of Apache River /
    Jini and I'm experimenting with support for OSGi.  I'm also a
    committer and PMC member of Apache River.  This isn't the old
    Jini we all know and love however, there are some additional
    features that allow provisioning to occur using a feature
    called delayed unmarshalling, so we can avoid the need for
    codebase annotations and URLClassLoaders.

    The work in progress can be found here, for anyone who's curious:

    https://github.com/pfirmstone/JGDMS/tree/Maven_build/modularize/JGDMS
    <https://github.com/pfirmstone/JGDMS/tree/Maven_build/modularize/JGDMS>

    Regards,

    Peter.

    _______________________________________________
    OSGi Developer Mail List
    osgi-dev@mail.osgi.org<mailto:osgi-dev@mail.osgi.org>
    https://mail.osgi.org/mailman/listinfo/osgi-dev
    <https://mail.osgi.org/mailman/listinfo/osgi-dev>

    _______________________________________________
    OSGi Developer Mail List
    osgi-dev@mail.osgi.org<mailto:osgi-dev@mail.osgi.org>
    https://mail.osgi.org/mailman/listinfo/osgi-dev
    <https://mail.osgi.org/mailman/listinfo/osgi-dev>
    _______________________________________________
    OSGi Developer Mail List
    osgi-dev@mail.osgi.org<mailto:osgi-dev@mail.osgi.org>
    https://mail.osgi.org/mailman/listinfo/osgi-dev
    <https://mail.osgi.org/mailman/listinfo/osgi-dev>



    _______________________________________________
    OSGi Developer Mail List
    osgi-dev@mail.osgi.org<mailto:osgi-dev@mail.osgi.org>
    https://mail.osgi.org/mailman/listinfo/osgi-dev
    <https://mail.osgi.org/mailman/listinfo/osgi-dev>




--
--
Christian Schneider
http://www.liquid-reality.de<https://owa.talend.com/owa/redir.aspx?C=3aa4083e0c744ae1ba52bd062c5a7e46&URL=http%3a%2f%2fwww.liquid-reality.de>

Open Source Architect
http://www.talend.com<https://owa.talend.com/owa/redir.aspx?C=3aa4083e0c744ae1ba52bd062c5a7e46&URL=http%3a%2f%2fwww.talend.com>
_______________________________________________
OSGi Developer Mail List
osgi-dev@mail.osgi.org<mailto:osgi-dev@mail.osgi.org>
https://mail.osgi.org/mailman/listinfo/osgi-dev

_______________________________________________
OSGi Developer Mail List
osgi-dev@mail.osgi.org
https://mail.osgi.org/mailman/listinfo/osgi-dev
_______________________________________________
OSGi Developer Mail List
osgi-dev@mail.osgi.org
https://mail.osgi.org/mailman/listinfo/osgi-dev
_______________________________________________
OSGi Developer Mail List
osgi-dev@mail.osgi.org
https://mail.osgi.org/mailman/listinfo/osgi-dev


                          SERVER JVM
============================================================

                                            ______________
                                           |              |
                                           |  Service     |
                                           |  API Bundle  |
                                           |______________|
                                                  |
                                                  |
                                               Imports
                                                 API
                                               Packages
                                                  |
                                                  |
 ____________________                       ______|_______
|                    |   Imports packages  |              |
|   Service Bundle   |<--------------------| Proxy Bundle |---EP
|   Implements       |      from proxy     |______________|   |
|   Proxy API        |                                        |
|____________________|                                        |
                                                              |                 
                                           
============================================================  |
                                                              |
                                                              |
                                                              |
                                                              N
                                                              E
                           CLIENT JVM                         T
============================================================  W
                                                              O
                                            ______________    R
 ____________________                      |              |   K
|                    |   Imports packages  |  Service     |   |
|  Management Agent  |<--------------------|  API Bundle  |   |
|  Discovers &       |       from API      |______________|   |
|  Registers service |                            |           |
|____________________|                            |           |
                                               Imports        |
                                                 API          |
                                               Packages       |
                                                  |           |
                                                  |           |
                                            ______|_______    |
                                           |              |   |
                                           | Proxy Bundle |---EP
                                           |______________|       

============================================================

Note other package imports omitted for clarity.
_______________________________________________
OSGi Developer Mail List
osgi-dev@mail.osgi.org
https://mail.osgi.org/mailman/listinfo/osgi-dev

Reply via email to