Context
I have a large OSGi-based (Equinox 3.9/Eclipse RCP 4.4) application, with a few "optional" bundles. Each of these optional bundles provide alternative user interfaces and some extra services (through SCR components) that are applicable only to a subset of our customers.
The application is always distributed as a pre-packaged installation (that is, we do not use P2 nor any other automatic provisionning mecanism). Until recently, we built a different pre-packaged installation for each customer that needed some optional bundles. The number of optional bundles is now growing up, and so does the number of custom pre-packaged installations to be built.
So we would like to build only one installation package to be delivered to all customers, containing all optional bundles, and then decide at runtime which optional bundles shall be launched. But here's the twist: the set of optional features to be enabled is known only after the user has authenticated himself with the server. That is, some end-users have access to multiple accounts, each giving access to a distinct set of optional features to be enabled. Consequently, optional bundles must remains unavailable until the user log-in, and then, only allowed optional bundles should be loaded. Since these optional bundles make contributions through various extenders (Eclipse's Plugin registry, SCR and Blueprints), it means that optional bundles must not be allowed to reach the RESOLVED state until it has been determined that they are indeed authorized to launch. It must also be possible to load and unload those optional bundles, as the user log-in and log-out of a specific server account.
Potential solutions and questions
I have identified a few potential solutions, but have unresolved questions to each of them. So I only really need proper positive answers to all questions of any of the following scenario.
Have optional bundles require some "enabling" capability. That would be, I think, the cleanest approach. Optional bundles would add something like "Require-capability: com.acme.optionalfeatures; identifier=my-custom-feature-identifier". At runtime, the capability would remains unresolved until the user is authentified, so extenders would automaticlay ignore that bundle. The bundle would automaticaly change state once the enabling capability is registered. That's great. But here are the missing parts: a) How can I register new capabilities namespace? b) Can I dynamically alter a bundle's provided capability, and if so, how can I do so? c) (if (b) is not possible) Can I dynamically register a new "Resource" with new capabilities, and if so, how can I do so?
Have optional bundles import some "enabling" package. That is a variant on the previous scenario, which might be easier to manage than custom capability namespaces... Those "enabling packages" could then come into existance through "dynamicaly created" packages. That is, some manager bundle would call BundleContext#installBundle(String, InputStream), with a ByteArrayInputStream, returning a dynamically generated bundle archive containing a Manifest.MF which export appropriate "enabling packages". Sounds simple enough, but several components along the toolchain (the IDE, PDE, P2, Product Export...) will complain about the fact that these required packages doesn't exist. To avoid those issues, the require-package header would need to be added dynamically at the time is is installed into the framework. But is there any mechanism that allow a bundle's headers to be altered that early (that is as soon as the bundle is installed into the framework)? Class Weaving is not applicable here.
Have optional bundles all require a single enabling package (all the same), which indeed exists. Then a Resolve Hook would filter out the bundle exporting that package from potential wiring candidates when the optional bundle has not yet been authorized. But how can I later request that all bundles be reconsidered for resolving when the user log-in or log-out?
Excluded solutions
The following solutions have already been excluded:
Putting optional bundles in distinct directories, then use BundleContext#installBundle(...) to enable thse bundles. Though this solution does indeed work at deploy time, it impose a significant burden on development (because bundles are then at some hard-to-predict folder, relative to the workspace, local git configuration, test environment and so one, making it impossible to properly build the location to be provided to #installBundle). The packaging procedure also become much more complex, as we need first to move apart those optional bundles, and then, to update several Equinox/P2 configuration files to prevent them to locate these now missing bundles.
Prevent optional bundles from being activated by conditionaly throwing an exception form their activator. This would simply not solve our problem, since option bundles would still be allowed to reach the RESOLVED state, and therefore be able to make contributions by the intermediate of extenders.
Use P2 to install new features at runtime. The problem here is that changes to the list of bundles made through P2 1) are inherently persistant (which means that optional features will automatically be reanabled at the next launch) and 2) require a framwork restart to be properly accomplished.
Note: We have no "security"-related concerns about the fact that those extra bundles are actualy distributed to users that do not require them. I know that users might easily hack the installation in order to force the launch of some optional bundles. This pose no significant issue.
You can create and install a bundle which provides the capability or package which the optional bundles require. This will enable them to be resolved.
But I don't understand how your model would work when multiple users access the server with varying rights. A more privileged user would cause the optional bundles to "activate", so then these features would be available to lesser privileged users accessing the server at the same time.
Related
I have implemented 2 services A,B in my bundle. I would like to change the code of service A by building a new jar file and do update command but keep the service B running without start it again.
Sounds like you have 2 services in 1 bundle. The unit of deployment is a bundle, so my recommendation is to split the two services into two bundles. Otherwise, undeploying your existing bundle will naturally also tear down Service B.
Alternatively, in case the API/interface resides in a separate bundle, you could deploy a new service-implementation for A in a separate bundle, with a higher priority, and rewire all uses of the service. Which typically is rather confusing, so it's a distant second place recommendation.
Edit: You comment that you are combining services in a bundle to minimize the number of jars, but you want to update the services independently. Specifically for minimizing the number of jars: Are you trying to solve a problem that you indeed had? I'm mainly working with Liferay, which is fully OSGi, and a plain vanilla installation comes with more than 1000 bundles - the runtime handles it just fine. Make sure you're not preemptively optimizing something that doesn't need optimization.
If your components have different maintenance intervals, then deploy them in different bundles. Period. No use working against the system, which has no problem with the number of bundles at all.
I need to provide pluggable functionality to a Go program.
The idea is that a 3rd party can add functionality for a given path, i.e.
/alive maps to http://localhost:9876, or
/branding maps to http://localhost:9877 and so on.
I first tried to think of it as adding a JSON config file, where each such plugin would have an entry, e.g.:
{
"Uri": "alive",
"Address":"http://localhost:9876",
"Handler":"github.com/user/repo/path/to/implementation"
},
This though blatantly reveals Java thinking - and feels like utterly inadequate for Go - there is no notion of Class loaders in Go, and loading this would mean to have to use the loader package from golang's tools.
Proposals on how to do this in a more Go- idiosyncratic way? In the end I just need to be able to map a URI to a port and to an implementation.
Compile-time configuration
If you can live with compile-time configuration, then there is no need for a JSON (or any other) configuration file.
Your main package can import all the involved "plugins", and map their handler to the appropriate path. There is also no need to create multiple servers, although you may do so if that fits better your (or the modules') needs.
Run-time configuration
Run-time configuration and plugging in a new module requires code to be loaded at run-time. This is supported by the plugin package, but currently only under linux.
For this you may use a JSON config file, where you would list the compiled plugins (path to the compiled plugins) along with the paths you need to map them.
In the main package you can read the config file, and load the plugins, which should expose a variable or a function that returns you the handler that handles the traffic (requests). This is preferred to the plugins themselves firing up an http server for performance reasons, but both can work (plugins returning a handler for you to register, and the plugins launching their servers).
Note that there is also no need to make the configuration "static", the main app could receive and load new modules at runtime too (e.g. via a dedicated handler, which could receive the (file) path to the new module and the path to map it to, optionally maybe even the binary plugin code too; but don't forget about security!).
Note that while you can load plugins at runtime, there is no way to "unload" them. Once a plugin is loaded, it will stay in memory until the app exists.
Separate, multi-apps
There is a third solution, in which your main app would act as a proxy. Here you may start the additional "modules" as separate apps, listening on localhost at specific ports, and the main app would act as a proxy, forwarding requests coming in to the other independent apps listening on different ports #localhost (or even on other hosts).
The standard library provides you the httputil.ReverseProxy doing just this.
This does not require runtime code loading, as the "modules" are separate apps which can be launched separately. Still, this gives runtime configuration flexibility, and this solution also works on all platforms. Moreover this setup supports taking down modules at runtime, as you can just as easily un-map / close the apps of the independent modules.
The separate apps can also be launched separately, or from / by the main app, both solutions are viable.
I am working in the logical architecture of a project that receives some info from users and processes it. One of the requirements is to expose an interface for external developers to add further functionalities. So far I have proposed a MVC 2-tier architecture, where the View and Controller run in the user's machine, and the Model is hosted in an Application server and remotely invoked. The requirement on functionalities suggests me to use a plugin pattern.
Additional steps selected by the user might be executed when processing the information, so I wanted to model them as plugins that will already exist when the application is released. This means that this plugins would affect the same resource (the processing flow), and I am uncertain about how to deal with this when both plugins are enabled.
Since I am not as familiar with the plugin pattern as with other patterns, the reading I did before asking made me try something similar to the Abstract Factory pattern. The problem is that, when two or more plugins are enabled, I would need mutiple inheritance. I also thought of the Builder pattern to model steps of the processing separately, but then an order among plugins would have to be defined and this would affect the independence of plugin's developers.
If I understand correctly, you want to be able to extend the same variation point with multiple independent plugins. If so, the pipes and filters pattern is an appropriate mechanism.
With this approach, plugins represent filters and you can design a plugin container that loads and then chains them. If no plugin is loaded for a given variation point, then you either short-circuit the variation point or provide some form of default filter.
Also, giving the plugins a mechanism to specify their position in the filter chain will be helpful, so think about that when designing the plugin-interface.
R-Osgi provides us a way to call service from a remote OGSi container. WebSite: http://r-osgi.sourceforge.net.
I'm new to R-OSGi and now I want to split my OSGi container into small ones and interact each other by R-Osgi because it's too huge. But it seems R-OSGi only provides a way for Registered Service. We know that the most popular way to interaction between 2 bundles besides Service, "exported-package" is also widely used.
So, is there anyone familiar with R-OSGi and know how to use "exported-package" from remote OSGi container?
Thanks for any response.
If you think about it, attempting to handle the remote importing/exporting of packages is very complex, fragile and prone to error; you'd need to send all bundle lifecycle events over the wire, and honour them in the importing system (which would require caching).
Additionally the framework would need to know ahead of time to use these class definitions (you cannot instantiate a class that references classes that aren't available to your classloader). A remote bundle's classloader may depend on classes from another classloader, this chain could go round and round a network making classloading take ages.
Put another way; your local bundles will never resolve without the class definitions they depend on, and considering there could be thousands+ of potential remote exporters on a network/hardware with very poor SLA, this wouldn't scale well or be very robust considering the fallacies of distributed computing.
If we tried to do remote packages, the framework would need to import all exported packages from all available remote nodes and then select just one to import each bundle export from (this would be arbitrary and if the select node goes down, the whole import remote package process would have to triggered again).
What you need to do is separate you api/interfaces from your implementation, you then distribute the api bundle to all nodes that need it and then use dOSGi to import services.
Apologies if this unclear or waffly but it should explain why it's simply not practical to have remote exported packages.
On a side note; I'm not sure if r-osgi is being actively maintained or is up-to-date with the latest Remote Services Admin spec, from looking at the last commit to SVN trunk was 14/02/2011. There's some alternative dOSGi implementations listed here (but avoid CXF).
EDIT: In terms of deployment, distributing your bundles (and configuration) can be done from an OBR (there are number of public ones and several implementations Felix/Eclipse), or a maven repository can be reappropriated with pax url handler.
We are developing a web-application (lets call it an image bank) for which we have identified the following needs:
The application caters customers which consist of a set of users.
A new customer can be created dynamically and a customer manages it's users
Customers have different feature sets which can be changed dynamically
Customers can develop their own features and have them deployed.
The application is homogeneous and has a current version, but version lifting of customers can still be handled individually.
The application should be managed as a whole and customers share the resources which should be easy to scale.
Question: Should we build this on a standard OSGi framework or would we be better of using one of the emerging application frameworks (Virgo, Aries or upcoming OSGi standard)?
More background and some initial thoughts:
We're building a web-app which we envision will soon have hundreds of customers (companies) with hundreds of users each (employees), otherwise why bother ;). We want to make it modular hence OSGi. In the future customers themselves might develop and plugin components to their application so we need customer isolation. We also might want different customers to get different feature sets.
What's the "correct" way to provide different service implementations to different clients of an application when different clients share the same bundles?
We could use the app-server approach (we've looked at Virgo) and load each bundle once for each customer into their own "app". However it doesn't feel like embracing OSGi. We're not hosting a multitude of applications, 99% of the services will share the same impl. for all customers. Also we want to manage (configure, monitor etc.) the application as one.
Each service could be registered (properly configured) once for each customer along with some "customer-token" property. It's a bit messy and would have to be handled with an extender pattern or perhaps a ManagedServiceFactory? Also before registering a service for customer A one will need to acquire the A-version of each of it's dependencies.
The "current" customer will be known to each request and can be bound to the thread. It's a bit of a mess having to supply a customer-token each time you search for a service. It makes it hard to use component frameworks like blueprint. To get around the problem we could use service hooks to proxy each registered service type and let the proxy dispatch to the right instance according to current customer (thread).
Beginning our whole OSGi experience by implementing the workaround (hack?) above really feels like an indication we're on the wrong path. So what should we do? Go back to Virgo? Try something similar to what's outlined above? Something completely different?!
ps. Thanks for reading all the way down here! ;)
There are a couple of aspects to a solution:
First of all, you need to find a way to configure the different customers you have. Building a solution on top of ConfigurationAdmin makes sense here, because then you can leverage the existing OSGi standard as much as possible. The reason you might want to build something on top is that ConfigurationAdmin allows you to configure each individual service, but you might want to add a layer on top so you can more conveniently configure your whole application (the assembly of bundles) in one go. Such a configuration can then be translated into the individual configurations of the services.
Adding a property to services that have customer specific implementations makes a lot of sense. You can set them up using a ManagedServiceFactory, and the property makes it easy to lookup the service for the right customer using a filter. You can even define a fallback scenario where you either look for a customer specific service, or a generic one (because not all services will probably be customer specific). Since you need to explicitly add such filters to your dependencies, I'd recommend taking an existing dependency management solution and extending it for your specific use case so dependencies automatically add the right customer specific filters without you having to specify that by hand. I realize I might have to go into more detail here, just let me know...
The next question then is, how to keep track of the customer "context" within your application. Traditionally there are only a few options here, with a thread local context being the most used one. Binding threads to customers does tend to limit you in terms of implementation options though, as in general it probably means you have to prohibit developers from creating threads themselves, and it's hard to off-load certain tasks to pools of worker threads. It gets even worse if you ever decide to use Remote Services as that means you will completely loose the context.
So, for passing on the customer identification from one component to another, I personally prefer a solution where:
As soon as the request comes in (for example in your HTTP servlet) somehow determine the customer ID.
Explicitly pass on that ID down the chain of service dependencies.
Only use solutions like the use of thread locals within the borders of a single bundle, if for example you're using a third party library inside your bundle that needs this to keep track of the customer.
I've been thinking about this same issue (I think) for some time now, and would like your opinions on the following analogy.
Consider a series of web application where you provide access control using a single sign-on (SSO) infrastructure. The user authenticates once using the SSO-server, and - when a request comes in - the target web application asks the SSO server whether the user is (still) authenticated and determines itself if the user is authorized. The authorization information might also be provided by the SSO server as well.
Now think of your application bundles as mini-applications. Although they're not web applications, would it still not make sense to have some sort of SSO bundle using SSO techniques to do authentication and to provide authorization information? Every application bundle would have to be developed or configured to use the SSO bundle to validate the authentication (SSO token), and validate authorization by asking the SSO bundle if the user is allowed to access this application bundle.
The SSO bundle maintains some sort of session repository, and also provides user properties, e.g. information to identify the data repository (of some sort) of this user. This way you also wouldn't pass trough a (meaningful) "customer service token", but rather a cryptic SSO-token that is supplied and managed by the SSO bundle.
Please not that Virgo is an OSGi container based on Equinox, so if you don't want to use some Virgo-specific feature, you don't have to. However, you'll get lots of benefits if you do use Virgo, even for a basic OSGi application. It sounds, though, like you want web support, which comes out of the box with Virgo web server and will save you the trouble of cobbling it together yourself.
Full disclosure: I lead the Virgo project.