I have a plugin A which exports the package foo.bar. In the package foo.bar there is a abstract class FooBar with default scope members. In a plugin B I like to extend the FooBar within the same package and access the default scoped fields.
Plugin A manifest:
.
Bundle-SymbolicName: A
Export-Package: foo.bar
.
Plugin B manifest:
.
Bundle-SymbolicName: B
Require-Bundle: A
.
Class FooBar in Plugin A:
package foo.bar;
public abstract class FooBar{
int min = -1;
}
Class MyFooBar in Plugin B:
package foo.bar;
public class MyFooBar extends FooBar{
public void setMin(int min){
this.min = min;
}
}
The result:
..Caused by: java.lang.IllegalAccessError: tried to access field foo.bar.FooBar.min from class foo.bar.MyFooBar
In a normal java environment I can access package-scoped members if I define my class in the same package. Apparently this is not so in OSGI-Environment, is it??
Try to make the bundle B a fragment for A (if it is possible in your case). Than B can access package-private classes because there is the same package name and class loader.
Read the following article Split Packages – An OSGi nightmare - it explains the problem in clear way.
You are correct, OSGI plugins aren't the same as java packages. If you truly want to share the same min value in both plugins, the best option is to share it through extension points. Extension points are the OSGI way to share data and code between plugins. This leads to a solution that doesnt cause a tight coupling between the plugins.
If plugin B truly must access the min value in plugin A that might be an indication that those two classes should be in the same plugin.
Also see this question
More information about extension points can be found here
Eclipse plug-ins / OSGi bundles each have their own separate classloaders (and thus namespaces). Package private means same package and classloader.
Related
I added dependencies to my profile class:
public class MyModelMappingProfile : Profile
{
public MyModelMappingProfile(
IDependency1 dependencyOne, IDependencyTwo dependencyTwo)
When I start the service it complains System.MissingMethodException: No parameterless constructor defined for type 'MyModelMappingProfile'.
Found this solution, which solves the problem, but is very manual. Is there something more generic? Haven't found an answer in the docs
https://jimmybogard.com/automapper-usage-guidelines/
X DO NOT inject dependencies into profiles
Profiles are static configuration, and injecting dependencies into them can cause unknown behavior at runtime. If you need to use a dependency, resolve it as part of your mapping operation. You can also have your extension classes (resolvers, type converters, etc.) take dependencies directly.
I am coding my project with golang. I want to design my project like plugin programming but I have confused with golang. My project have data analysis task, I purpose make a folder that contain modules analysis, if I have new modules after, I just need copy it to folder and main application will pass data to the new modules without modified.
Can you help me? Thanks for watching!
Go with it's interfaces is a good choice to build something pluggable.
Interfaces
Interface in Go is a way of types abstraction.
Interfaces in Go provide a way to specify the behavior of an object: if something can do this, then it can be used here.
It means a simple but very powerful thing - you can use different composite literals as an interface type if they implement the interface. This is already a pluggable system and if are looking for something simple it is possible to build with minimal effort.
Simplest implementation
Let's say you have such a primitive architecture:
▾ pluggable/
▾ app/
pusher.go
▾ plugins/
green_button.go
plugin_interface.go
red_button.go
main.go
plugins/plugin_interface.go
An interface which will be used as a type abstraction for plugins.
package plugins
type Button interface {
Push()
}
plugins/green_button.go
Now it is possible to extend your application with plugins implement the interface.
package plugins
import (
"fmt"
)
type GreenButton struct {
Msg string
}
func (b GreenButton) Push() {
fmt.Println(b.Msg)
}
plugins/red_button.go
One more plugin...
package plugins
import (
"fmt"
)
type RedButton struct {
Err error
}
func (b RedButton) Push() {
fmt.Println(b.Err)
}
app/pusher.go
An interface type embedded in the composite literal. Any cl implementing the interface could be used in the Pusher instance. Pusher doesn't care about particular plugin implementation it just pushes. It is well abstracted and encapsulated.
package app
import (
"github.com/I159/pluggable/plugins"
)
type Pusher struct {
plugins.Button
}
main.go
Usage of all the stuff.
package main
import (
"errors"
"github.com/I159/pluggable/app"
"github.com/I159/pluggable/plugins"
)
func main() {
alert_pusher := app.Pusher{plugins.RedButton{Err: errors.New("Alert!")}}
success_pusher := app.Pusher{plugins.GreenButton{Msg: "Well done!"}}
alert_pusher.Push()
success_pusher.Push()
}
You can add more sugar, for example one more level of isolation to use a single button configured to be a one or another particular implementation and so on.
Plugins as libraries
Same trick with plugin-libraries. A composite literals declared in a plugin-libraries must implement a plugin interface of the main application. But in this case you will need a register a function and a file with libs imports, so it already looks like a nano plugin framework.
Go 1.8 has support for plugins: https://beta.golang.org/pkg/plugin/. If you can wait a couple months you could use that (or just use the beta 1.8).
I'm in a situation where the implementation of a library we are using is newer than the implementation one of our dependencies was coded against. E.g. Dependency uses MyLibrary-1.0 and we're using MyLibrary-2.0.
In the newer implementation a deprecated method has been removed, which causes run-time errors for us.
I'm trying to use AOP (Spring-AOP to be specific) to intercept calls made to the missing method, and proxy them into an existing method... but I can't seem to get the Aspect right.
It feels like Java is raising the 'java.lang.NoSuchMethodError' exception before my Aspect has an opportunity to intercept. Is there some trick I'm missing, or is this just not feasible (e.g. the method must exist in order to aspect it)?
#Before("execution(* com.mylibrary.SomeClass.*(..))")
Fails with java.lang.NoSuchMethodError
#Around("target(com.mylibrary.SomeClass) && execution(* missingMethod(..))")
Fails with java.lang.NoSuchMethodError
Assuming that your are talking about a 3rd party library which is independent of Spring, you cannot use Spring AOP with its proxy-based "AOP lite" approach which only works for public, non-static methods of Spring components. Please use the more powerful AspectJ instead. The Spring manual explains how to integrate full AspectJ with load-time weaving (LTW) into Spring applications. If your application is not based on Spring so far and you just wanted to use the framework because of Spring AOP, you can skip the whole Spring stuff altogether and use plain AspectJ.
The feature you want to use is an inter-type declaration (ITD), more specifically AspectJ's ability to declare methods for existing classes. Here is some sample code:
3rd party library:
package org.library;
public class Utility {
public String toHex(int number) {
return Integer.toHexString(number);
}
// Let us assume that this method was removed from the new library version
/*
#Deprecated
public String toOct(int number) {
return Integer.toOctalString(number);
}
*/
}
Let us assume that the method I commented out was just removed from the latest version your own project depends on, but you know how to re-implement it.
Project dependency depending on old version of 3rd party library:
package com.dependency;
import org.library.Utility;
public class MyDependency {
public void doSomethingWith(int number) {
System.out.println(number + " in octal = " + new Utility().toOct(number));
}
}
Because the previously deprecated method Utility.toOct does not exist anymore in the version used by your own project, you will get NoSuchMethodError during runtime when calling MyDependency.doSomethingWith.
Your own application:
package de.scrum_master.app;
import org.library.Utility;
import com.dependency.MyDependency;
public class Application {
public static void main(String[] args) {
System.out.println("3333 in hexadecimal = " + new Utility().toHex(3333));
new MyDependency().doSomethingWith(987);
}
}
As you can see, the application also uses the same library, but a different method which still exists in the current version. Unfortunately, it also uses the dependency which relies on the existence of the removed method. So how should we repair this?
Aspect using ITD:
AspectJ to the rescue! We just add the missing method to the 3rd party library.
package de.scrum_master.aspect;
import org.library.Utility;
public aspect DeprecatedMethodProvider {
public String Utility.toOct(int number) {
return Integer.toOctalString(number);
}
}
If you compile this project with the AspectJ compiler Ajc, it just works. In your real life scenario, compile the aspect into its own aspect library, put the weaving agent aspectjweaver.jar on the JVM command line in order to activate LTW and enjoy how it weaves the method into the library class via byte code instrumentation during class-loading.
Log output:
3333 in hexadecimal = d05
987 in octal = 1733
Et voilà! Enjoy. :-)
When the JVM load a class, it resolves all dependencies in a "linker" phase : external classes, properties and method. You can't pass this phase in your case, because methods are missing.
There are two modes on (Spring-)AOP: Proxy, and weaving.
Proxy create... a proxy around a class: the targeted class must exist and be loaded
Weaving can happen before a class is loaded: when a classloader load a class, an array of byte[] is passed to the weaver, which can manipulate the class bytecode before the class is really reified. This type of aop can work in your case. However, it will not be an easy task.
I coded a bundle that uses Apache Felix Dependency management. It's Activator extends
DependencyActivatorBase. But Plugin my plugin activator extends AbstractUIPlugin. How can I get services from the felix dependency manager from within the eclipse plugin?
DependencyManager has a getDepenencyManagers method but it is a list, not sure how I would know the right manager in the list.
Yes you can use Dependency Manager in any OSGi framework, including Equinox (on which Eclipse is based).
Why does your bundle activator need to extend AbstractUIPlugin?? Are you actually using AbstractUIPlugin, or was this just generated for you because you used Eclipse PDE to generate the initial code? The project templates in PDE are basically junk, most bundles do not need activators at all, and very very few really need to extend AbstractUIPlugin.
So, just change your activator to extend DependencyActivatorBase instead of AbstractUIPlugin.
The DependencyActivatorBase class is just a base class that is there for your convenience. If, for some reason, you cannot use it (like, arguably, in your case), you can always instantiate an instance of DependencyManager yourself from your own class. All it needs is a reference to the BundleContext (which you can get from the start() method of BundleActivator, assuming you do implement that yourself). Then just do something like this:
DependencyManager dm = new DependencyManager(bundleContext);
dm.add(dm.createComponent()
.setImplementation(YourComponent.class)
.add(dm.createServiceDependency()
.setService(LogService.class)
)
);
I am using Rhino to script an Eclipse (RCP) application. The problem is that from Javascript I only have access to classes available to the plugin that provides Rhino, and not to all the classes available to the plugin that runs the scripts.
The obvious answer would be to put Rhino in the scripting plugin, but this doesn't work because it's already provided by one of the application's own plugins (which also provides things I need to script) and Eclipse always uses this version instead of the version closer to hand.
Is there a way to change the classloader used by Rhino
or is it possible to ensure that Eclipse loads the Rhino classes from one plugin rather than another?
Thanks to Thilo's answer I used this:
import net.weissmann.tom.rhino.Activator; // Plugin activator class
import org.mozilla.javascript.tools.shell.Main;
public class JSServer extends Thread {
//[...]
public void run() {
// recent versions of the Main class kindly export
// the context factory
Main.shellContextFactory.initApplicationClassLoader(
Activator.class.getClassLoader()
) ;
//[...]
}
Is there a way to change the classloader used by Rhino
Rhino should be using the current Thread's ContextClassLoader. Try Thread.setContextClassLoader (don't forget to restore it).
If that does not work, maybe you can create your own Rhino ContextFactory:
public final void initApplicationClassLoader(java.lang.ClassLoader loader)
Set explicit class loader to use when searching for Java classes.
I don't know Rhino specifics, but you could consider using Eclipse "buddy classloading" with the "registered" policy.
Rhino's plug-in (net.weissmann.tom.rhino, say) would declare itself "open to extension" by specifying Eclipse-BuddyPolicy: registered in its MANIFEST.MF. Plug-ins with classes that Rhino should be able to see would specify Eclipse-RegisterBuddy: net.weissmann.tom.rhino and would need a bundle-level dependency on net.weissmann.tom.rhino.
http://www.eclipsezone.com/articles/eclipse-vms/
http://wiki.eclipse.org/index.php/Context_Class_Loader_Enhancements#Technical_Solution