I'm looking to create a Java 'library' (JAR) that can be used within other projects, but I'd like my library to be extensible. I'm after something OSGi-esque, where my library has 'extension points' that other JARs can hook into. The thinking is that my library will have a core set of methods that will be called by the projects it's used in, but the exact implementation of these methods might vary based on the project/context.
I've looked into OSGi (e.g. Equinox), but I'm not sure it can be used in the way I'm after. It seems to be geared towards standalone apps rather than creating a library.
What would be the best way of achieving this? Can OSGi be used in this way, and if not are there frameworks out there that will do this?
I hope all that's clear - I have a clear idea of what I want, but it's hard to articulate.
OSGi is great, but I don't think that this is what you need. By using OSGi (-Services), you force the user of your library to use an OSGi environment, too.
I think as #Peter stated, you can do this by simply extending classes of your library in the specific project / context.
But in case you want to use OSGi, there is a simple way to achieve this. It's called Bundle Fragments. This way you can create a bundle and extend a so-called Host-Bundle", i.e. your library, without altering the original library. A popular use case for this is if you have platform specific code in your bundles.
What you are naming a Java library is named "Bundle" in OSGi context.
OSGi Bundle is a JAR file with some special Meta-Information in its MANIFEST.MF file. Now, every OSGi Bundle have either Exported-Packages or Imported-Packages.
Through Export-Packages Manifest header, you can show what all packages you are exporting.. And your other project can simply add the package it wants to use from them to its Import-Packages..
Here's an example: -
Bundle A Manifest: -
Export-Packages: com.demo.exported;
Bundle B Manifest: -
Import-Packages: com.demo.exported;version=(1.0.0, 2.0.0]
This way your bundle B (A different project) can call the methods from the class in the package that it imported from Bundle A..
Now, the version you see in the import-package, is just to show what all package version can it accept.. You can have 2 bundles with two different implementation of some interfaces and provide this package in two different version.. Both will be available..
Till now, I was talking about Static data-types..
You can also have your services exposed dynamically through Declarative Service.. In this case you will have to define one XML file (Component Definition) where you show what all services your Bundle will expose.. And in the other bundle, you can again define another XML, to show what all services it requires..
These are called, Provided Services and Referenced Services..
I think this will give you a little idea about what can be done.
And if I am wrong somewhere in interpreting your problem please specify the same..
*NOTE: - And of course OSGi is used for creating independent Bundles, that can be re-used in other projects.. They bring Modularity to your project..
As others have mentioned, you don't need OSGi or any framework for this. You can do this my employing patterns like the template method pattern or the strategy pattern. There are several other patterns for dynamically modifying/extending functionality, but these seem to fit your description most. They do not require any framework.
The benefit you would get from a framework like OSGi would be that it would manage the wiring for you. Normally, you'll have to write some code that glues your libraries and the extensions together - with a framework like OSGi, this will not be automated with minimal overhead (in case of OSGi, the overhead is some entries in the JAR-manifest).
Related
When I first started looking at OSGi I was under the impression that you could just build a JAR and as-long as it had a manifest file, you could deploy it in a OSGi container. I imagined building my modules in a classic way (maven), and maybe use some plugin or something of the sort to write the manifest, I could then have my module that would basically be a standalone application communicating with other modules through OSGi.
Further reading about OSGi, I'm beginning to see more examples of it being used at a more low-level and basically replacing dependency injection and providing cross-cutting concern services like logging. And seems that using things like hibernate or others, is a problem... (or maybe I'm just missing something).
At least for me, I don't really see the point of having a such fine-gained level of modularity and integration to OSGi, I would much rather have a separate modules, each one of them having its own set of technologies and frameworks, and possibly a web resources and persistence layer. Is this achievable with OSGi? If yes, can you point me in the right direction, examples etc.?
edit, added some more details of how I'm trying to use OSGi:
I'm just envisioning the possibility of having a more than one-class module, that might have a more higher-level responsibility.
Like say agenda module. In this case I want to have things like, persistence of the events, add events, list events with filters, etc...
This agenda might have several internal classes, and might even need a persistence layer. So I would like to use something like Guice to DI those classes, and some JPA to persist my data.
I can understand that some X-cutting concerns like server or logging can have a bundle, but the data model is specific to the agenda bundle. So I think my question was at the end What is and what is not possible to do inside a bundle? And what should and shouldn't be done inside as a general practice?
Thanks!
Mauricio
You can use OSGi without forcing any dependencies on OSGi on the application code. However, since OSGi provides modularity, the middleware (your layers) need to have some knowledge of OSGi. The problem is that in a modular world you want to hide implementation details, that is the whole purpose. However, things like Spring and Hibernate tend to assume the classpath has no boundaries and they run head on into the fences. Fortunately, more and more middleware is becoming prepared for this, I heard Hibernate now has an effort and JPA is also available in OSGi.
OSGi is many things to many people, and you can almost pick and choose what parts of it you want to use:
Do you have a plain library that doesn't use any other dependencies? Sweet, just put up a minimal MANIFEST.MF listing the public packages, use maven to build your JAR and you're done.
Do you have dependencies? Same as (1), you just add the imported packages in your manifest.
Do you need to perform some initialization? Write an Activator, and mention it in your manifest.
Services? Just put the dependencies and descriptions of those in XML files and add them in the manifest.
And so on - just use the level where you are comfortable.
On the other hand, if you want to do web applications you really need to consider the architectural interplay between OSGi, the libraries you use, your application manager and the servlet/jee/whatever container. At what level will OSGi reside? In a general sense, there are OSGi->container->app, container->OSGi->app and container->app->OSGi solutions, and each has their own idiosyncrasies.
Concerning building with maven, you can use the Maven-Bundle-Plugin it helps you to build OSGi bundles without having to write the manifest on your own. All the required meta information will be in your POM.
Dependency injection can be achieved on top of the module layer. One possible solution would be Declarative Services which enables you to inject via an XML description or code annotations. It strongly reflects the dynamic nature of OSGi Services (dynamic binding unbinding of services).
The alternative is Blueprint which is based upon spring and features a very similar syntax. One key feature is that it can abstract the nature of binding and unbinding of services. If you think about using Spring, use Blueprint.
OSGi only implies how you structure your modules. You get a well defined graph of module interactions (who imports/exports a package? Who exports Services and who uses it?)
therefore you can build an enterprise architecture on top of it by building cohesive bundles for every task.
OSGi is sometimes referred to as a service-oriented architecture for the JVM. Looking at bundles as modular units that provide services helps define the right granularity: you'll usually have API bundles which are just here to provide java packages that define APIs, service bundles that provide implementations of these APIs, and utility/auxiliary bundles that provide the cross-cutting services that you mention.
You can use some dependency injection frameworks on top of OSGi, but from my experience (with Apache Sling and Adobe CQ5) keeping things simple is often better. The OSGi Service Component Runtime and Configuration Admin provide all I need to manage services, dependencies and configurations, especially if you design your system for that from the beginning.
You can find a bit more about our experience with OSGi in designing Adobe CQ5 in my "tales from the OSGi trenches" slides at http://www.slideshare.net/bdelacretaz/tales-from-the-osgi-trenches-2012-short-form-edition - that might help get a better feel for how OSGi is used in building complex systems.
I see many Java packages have api, impl and bundle jars (name-api.jar, name-impl.jar, name-bundle.jar). Could someone explain what those mean? Are all three needed by the app?
The idea is that you can separate the dependencies of the application; in an attempt to make applications more portable. The idea is that you can make the application dependent on the api.jar when compiling. Then when you want to run the program you can then switch in the appropriate implementation jar (impl.jar) and the appropriate resource bundle jar (bundle.jar).
As an example suppose the library does some database interaction. You write your code so that it references the api.jar. Now suppose you need it to work with a specific type of database e.g. MySQL - you would then add the impl.jar that is specific to MySQL databases to the classpath to get it to work (if you need a different database later - you only need to switch that jar in the classpath).
The bundle.jar is a bit more obscure and not as common. This could be used to supply configuration setting for the library. For example it could be used to supply language specific settings, or some more specific config. In the case of the database library it might be that the implementation is designed for all versions of MySQL, and the resource bundle jar provides config files that allow it to work for a specific MySQL version.
Often :
name-api.jar contains only the interface of the API.
name-impl.jar provides an implementation of all interfaces in the name-api.jar
name-bundle.jar bundles everything with all the needed classes to run a Java application.
api.jar contains API interfaces. These are interfaces as a contract that the implementation of the API should follow.
impl.jar is the implementation of the api.jar. You can't just have the impl.jar without the api.jar.
bundle.jar is the resources (if I'm not mistaken). Those are resources needed for the implementation code necessary to run.
I've never seen such an arrangement.
If the designer packaged the app into three JARs, then I'd say all three are needed.
But you should recognize that it's just a choice made by the designer. It's possible that s/he could have just created a single JAR with everything in it and you'd be none the wiser.
I'm guessing now, but if you were to open those JARs you'd see only interfaces in the API JAR, implementations of those interfaces in the impl JAR, and resource bundles and other .properties files in the bundle JAR. Try it and see. You'll learn something.
I have a Java project that expects external modules to be registered with it. These modules:
Implement a particular interface in the main project
Are packaged into a uni-jar (along with any dependencies)
Contain some human-readable meta-information (like the module name).
My main project needs to be able to load at runtime (e.g. using its own classloader) any of these external modules. My question is: what's the best way of registering these modules with the main project (I'd prefer to keep this vanilla Java, and not use any third-party frameworks/libraries for this isolated issue)?
My current solution is to keep a single .properties file in the main project with key=name, value=class |delimiter| human-readable-name (or coordinate two .properties files in order to avoid the delimiter parsing). At runtime, the main project loads in the .properties file and uses any entries it finds to drive the classloader.
This feels hokey to me. Is there a better way to this?
The standard approach in Java is to define a Service Provider.
Let all module express their metadata via a standard xml file. Call it "my-module-data.xml".
On your main container startup it looks for a classpath*:my-module-data.xml" (which can have a FrontController class) and delegates to the individual modules FrontController class to do whatever it wants :)
Also google for Spring-OSGI and their doco can be helpful here.
Expanding on #ZZ Coder...
The Service Provider pattern mentioned, and used internally within the JDK is now a little more formalized in JDK 6 with ServiceLoader. The concept is further expanded up by the Netbeans Lookup API.
The underlying infrastructure is identical. That is, both API use the same artifacts, the same way. The NetBeans version is just a more flexible and robust API (allowing alternative lookup services, for example, as well as the default one).
Of course, it would be remiss to not mention the dominant, more "heavyweight" standards of EJB, Spring, and OSGi.
I have successfully managed to start Apache Felix from code and register an own Bundle.
Following relation between OSGI-projects is needed:
[OsgiInterface] -- provides interfaces.
[OsgiModuleA] -- (bundle) provides an implementation of those interfaces.
knows [OsgiInterface]
[OsgiUsage] -- makes use of one or more bundle.
knows [OsgiInterface] and [OsgiModuleA]
Now I have problems registering a service which implements an interface.
I would guess that my entries in manifest.mf files are wrong.
Additional information
It would be very kind, if someone could look at the code in my previous question
Let me refer to this question:
I tried to create a third project OsgiInterfaces, which provides an interface SomeInterface in the package interfaces. This project is known by both OsgiModuleA and OsgiUsage.
OsgiModuleA: manifest.mf has now an additional value interfaces for the entry Import-Package:. Furthermore, there is an instance of SomeInterface provided to the activator.
When the bundle is started, an NoClassDefFoundError occurs: the interface SomeInterface is not known.
EDIT:
Now, that the error is fixed, I can tell, that the most important part was:
map.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA,
"my.interfaces; version=1.0.0");
Without this, I got ClassCastException.
In the most basic form, services are registered in Java code, not using manifest or any other file. This usually happens in your BundleActivator.
Long i = new Long(20); // the service implementation
Hashtable props = new Hashtable();
props.put("description", "This an long value");
bundleContext.registerService(Long.class.getName(), i, props);
I suggest you read a tutorial, like the one at Knopflerfish
An alternative is using Declarative Services, or the new Blueprint facility. Using either of these (or other non-standardized systems) you will declare your services in a (usually XML) file, instead of writing code to interact with the services registry.
But you should probably figure out the fundamentals manually first.
[OsgiUsage] -- makes use of one or more bundle.
knows [OsgiInterface] and [OsgiModuleA]
It should not be necessary for the bundle that uses a service to know about the bundle that provides it. Both of them just need to know the service interface. In fact, bundles should not need to know about other bundles at all. They only need to import packages, and consume or provide services.
I understand that you have SomeInterface in another bundle, right? Then you must also export that package in that bundle's manifest, eg.
Export-Bundle: interfaces
But you really should have a look at the bnd tool mentioned in another answer. This generates standard OSGi manifests.
I suggest you look at the iPOJO project. This make using Felix much easier.
https://felix.apache.org/documentation/subprojects/apache-felix-ipojo.html
I would say use bnd directly or maven-bundle-plugin to create OSGI enabled jars.
It's easier than writing the OSGI manifest yourself(typos, mistakes, missing imports/exports)
Trying wrapping the jars with bnd as a start.
I've been thinking some about "good practice" regarding package structure within osgi bundles. Currently, on average, we have like 8-12 classes per bundle. One of my initiative/proposal has been to have two packages; com.company_name.osgi.services.api (for api-related classes/interfaces (which is exported externally) and one package com.company_name.osgi.services.impl for implementation (not exported)). What are the pros cons of this? Any other suggestions?
You might also consider puting the interfaces in com.company_name.subsystem, and the implementation in com.company_name.subsystem.impl, the OSGI specific code, if there is any, could be in com.company_name.subsystem.osgi.
Sometime you might have multiple implementation of the same interfaces. In this case you could consider - com.company_name.subsystem.impl1 and com.company_name.subsystem.impl2, for example:
com.company.scm // the scm api
com.company.scm.git // its git implementaton
com.company.scm.svn // its subversion implementation
com.company.scm.osgi // the place to put an OSGI Activator
In this sense package structure could be OSGi agnostic, if you later on move to a different container, you just put an additional
com.company.scm.sca // or whatever component model you might think of
Always having api and impl in your package name could be annoying. If in doubt use impl but not api.
It's not the number of classes that is important but the concepts. In my opinion you should have one conceptual entity in a bundle. In some cases this might be just a few classes in other several packages with 100s of classes.
What it important is that you separate the API and the implementation. One bundle contains the API of your concept and the other the implementation. Like this you can provide different implementations for a well defined API. In some cases this might be even necessary if you want to access the services from a bundle remotely (using e.g. R-OGSi)
The API bundles are then used by code sharing and the services from the implementation bundles by service sharing. Best way to explore those possibilities is to look at the ServiceTrackers.
In your case you could have the implementation in the same package, but all of its classes "package protected". This way, you can export the package and the implementation would not be visible to the outside, even when not using OSGi (but as a regular jar file).