trouble using osgi RESTEasy 3 - java

Hello i'm trying to create a plugin with eclipse to use RESTEasy 3 in a opensource project (iDempiere ERP).
I created a plugin with eclipse, imported the RESTEsy libraries..
I writing the following class using some tutorials on web and registering this class as Activator.
public class Activator extends Application implements BundleActivator {
private volatile ServiceTracker serviceTrackerForResteasyService;
private volatile ResteasyService resteasyService;
private Set<Object> singletons = new HashSet<Object>();
public Activator()
{
}
#Override
public void start( BundleContext bundleContext ) throws Exception
{
try
{
serviceTrackerForResteasyService = new ServiceTracker( bundleContext, ResteasyService.class.getName(), null );
serviceTrackerForResteasyService.open();
resteasyService = (ResteasyService)serviceTrackerForResteasyService.getService();
if (resteasyService == null) {
System.out.println("resteasyService == null");
}
resteasyService.addSingletonResource("/rest/*", new SampleResource2());
}
catch ( Exception e )
{
e.printStackTrace();
throw e;
}
but I have this error: resteasyService is null...
I don't know how initialize correctly the class.
I have already used successfully RESTEasy with tomcat without OSGI and I used web.xml configuration files.
In OSGI I think that the web.xml is not used anymore is it correct ?

Related

How to deal with dependency conflicts using custom classloader in java properly?

I have a multimodule project called k-sdk. It has modules like
---> agent
---> core
---> api
---> integration
---> sdk
where (sdk module contains core, api, integration modules and acting as a shaded jar).
This jar can be imported as a dependency in the user application.
Here k-sdk is acting as a middleware to capture request and response of the api calls (both external and internal) and do some custom processing. And to intercept the internal calls i am using servlet-filter & for external calls, i am using ByteBuddy and wrote the required code in the premain method. The corresponding interceptors are written in integration module. User can use this k-sdk by running agent jar(present in agent module) of the k-sdk.
Now comes to the actual problem. Suppose I have written an Interceptor for OkHttp client version 4.10.0 in the integration module and the user is using the same client of version 3.14.9, now these two versions share completely same package name. And there are some uncommon apis, methods etc, which is being used in the OkHttpInterceptor which results in java.lang.NoSuchMethodError because maven only resolves that version of dependency which has the shortest path. And only 1 version of a dependency will be loaded in the classloader.
Now, To resolve this version conflict what i was thinking that i will use the below custom classloader. (ref) as i know that the solution lies in this approach only.
public class ChildFirstClassLoader extends URLClassLoader {
private final ClassLoader sysClzLoader;
public ChildFirstClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
sysClzLoader = getSystemClassLoader();
}
#Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
// has the class loaded already?
Class<?> loadedClass = findLoadedClass(name);
if (loadedClass == null) {
try {
if (sysClzLoader != null) {
loadedClass = sysClzLoader.loadClass(name);
}
} catch (ClassNotFoundException ex) {
// class not found in system class loader... silently skipping
}
try {
// find the class from given jar urls as in first constructor parameter.
if (loadedClass == null) {
loadedClass = findClass(name);
}
} catch (ClassNotFoundException e) {
// class is not found in the given urls.
// Let's try it in parent classloader.
// If class is still not found, then this method will throw class not found ex.
loadedClass = super.loadClass(name, resolve);
}
}
if (resolve) { // marked to resolve
resolveClass(loadedClass);
}
return loadedClass;
}
#Override
public Enumeration<URL> getResources(String name) throws IOException {
List<URL> allRes = new LinkedList<>();
// load resources from sys class loader
Enumeration<URL> sysResources = sysClzLoader.getResources(name);
if (sysResources != null) {
while (sysResources.hasMoreElements()) {
allRes.add(sysResources.nextElement());
}
}
// load resource from this classloader
Enumeration<URL> thisRes = findResources(name);
if (thisRes != null) {
while (thisRes.hasMoreElements()) {
allRes.add(thisRes.nextElement());
}
}
// then try finding resources from parent classloaders
Enumeration<URL> parentRes = super.findResources(name);
if (parentRes != null) {
while (parentRes.hasMoreElements()) {
allRes.add(parentRes.nextElement());
}
}
return new Enumeration<URL>() {
Iterator<URL> it = allRes.iterator();
#Override
public boolean hasMoreElements() {
return it.hasNext();
}
#Override
public URL nextElement() {
return it.next();
}
};
}
#Override
public URL getResource(String name) {
URL res = null;
if (sysClzLoader != null) {
res = sysClzLoader.getResource(name);
}
if (res == null) {
res = findResource(name);
}
if (res == null) {
res = super.getResource(name);
}
return res;
}
}
And to improve the user experience, i have to make changes only in the premain method. Now i don't know how to use this classloader to resolve this conflicting issue.
The above classloader is extending URLClassLoader, and the application class loader is no longer an instance of java.net.URLClassLoader in java 9+.
I am very new to this complex solution, Please! help me out.
Before this solution, i tried to repackage classes using maven-shade-plugin but that solution was not working because in premain method using ByteBuddy i was targeting a class of actual package and was using different package in the interceptor so the flow was not going to the interceptor as the class was not matching.

Updating Dropwizard config at runtime

Is it possible to have my app update the config settings at runtime? I can easily expose the settings I want in my UI but is there a way to allow the user to update settings and make them permanent ie save them to the config.yaml file? The only way I can see it to update the file by hand then restart the server which seems a bit limiting.
Yes. It is possible to reload the service classes at runtime.
Dropwizard by itself does not have the way to reload the app, but jersey has.
Jersey uses a container object internally to maintain the running application. Dropwizard uses the ServletContainer class of Jersey to run the application.
How to reload the app without restarting it -
Get a handle to the container used internally by jersey
You can do this by registering a AbstractContainerLifeCycleListener in Dropwizard Environment before starting the app. and implement its onStartup method as below -
In your main method where you start the app -
//getting the container instance
environment.jersey().register(new AbstractContainerLifecycleListener() {
#Override
public void onStartup(Container container) {
//initializing container - which will be used to reload the app
_container = container;
}
});
Add a method to your app to reload the app. It will take in the list of string which are the names of the service classes you want to reload. This method will call the reload method of the container with the new custom DropWizardConfiguration instance.
In your Application class
public static synchronized void reloadApp(List<String> reloadClasses) {
DropwizardResourceConfig dropwizardResourceConfig = new DropwizardResourceConfig();
for (String className : reloadClasses) {
try {
Class<?> serviceClass = Class.forName(className);
dropwizardResourceConfig.registerClasses(serviceClass);
System.out.printf(" + loaded class %s.\n", className);
} catch (ClassNotFoundException ex) {
System.out.printf(" ! class %s not found.\n", className);
}
}
_container.reload(dropwizardResourceConfig);
}
For more details see the example documentation of jersey - jersey example for reload
Consider going through the code and documentation of following files in Dropwizard/Jersey for a better understanding -
Container.java
ContainerLifeCycleListener.java
ServletContainer.java
AbstractContainerLifeCycleListener.java
DropWizardResourceConfig.java
ResourceConfig.java
No.
Yaml file is parsed at startup and given to the application as Configuration object once and for all. I believe you can change the file after that but it wouldn't affect your application until you restart it.
Possible follow up question: Can one restart the service programmatically?
AFAIK, no. I've researched and read the code somewhat for that but couldn't find a way to do that yet. If there is, I'd love to hear that :).
I made a task that reloads the main yaml file (it would be useful if something in the file changes). However, it is not reloading the environment. After researching this, Dropwizard uses a lot of final variables and it's quite hard to reload these on the go, without restarting the app.
class ReloadYAMLTask extends Task {
private String yamlFileName;
ReloadYAMLTask(String yamlFileName) {
super("reloadYaml");
this.yamlFileName = yamlFileName;
}
#Override
public void execute(ImmutableMultimap<String, String> parameters, PrintWriter output) throws Exception {
if (yamlFileName != null) {
ConfigurationFactoryFactory configurationFactoryFactory = new DefaultConfigurationFactoryFactory<ReportingServiceConfiguration>();
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();
ObjectMapper objectMapper = Jackson.newObjectMapper();
final ConfigurationFactory<ServiceConfiguration> configurationFactory = configurationFactoryFactory.create(ServiceConfiguration.class, validator, objectMapper, "dw");
File confFile = new File(yamlFileName);
configurationFactory.build(new File(confFile.toURI()));
}
}
}
You can change the configuration in the YAML and read it while your application is running. This will not however restart the server or change any server configurations. You will be able to read any changed custom configurations and use them. For example, you can change the logging level at runtime or reload other custom settings.
My solution -
Define a custom server command. You should use this command to start your application instead of the "server" command.
ArgsServerCommand.java
public class ArgsServerCommand<WC extends WebConfiguration> extends EnvironmentCommand<WC> {
private static final Logger LOGGER = LoggerFactory.getLogger(ArgsServerCommand.class);
private final Class<WC> configurationClass;
private Namespace _namespace;
public static String COMMAND_NAME = "args-server";
public ArgsServerCommand(Application<WC> application) {
super(application, "args-server", "Runs the Dropwizard application as an HTTP server specific to my settings");
this.configurationClass = application.getConfigurationClass();
}
/*
* Since we don't subclass ServerCommand, we need a concrete reference to the configuration
* class.
*/
#Override
protected Class<WC> getConfigurationClass() {
return configurationClass;
}
public Namespace getNamespace() {
return _namespace;
}
#Override
protected void run(Environment environment, Namespace namespace, WC configuration) throws Exception {
_namespace = namespace;
final Server server = configuration.getServerFactory().build(environment);
try {
server.addLifeCycleListener(new LifeCycleListener());
cleanupAsynchronously();
server.start();
} catch (Exception e) {
LOGGER.error("Unable to start server, shutting down", e);
server.stop();
cleanup();
throw e;
}
}
private class LifeCycleListener extends AbstractLifeCycle.AbstractLifeCycleListener {
#Override
public void lifeCycleStopped(LifeCycle event) {
cleanup();
}
}
}
Method to reload in your Application -
_ymlFilePath = null; //class variable
public static boolean reloadConfiguration() throws IOException, ConfigurationException {
boolean reloaded = false;
if (_ymlFilePath == null) {
List<Command> commands = _configurationBootstrap.getCommands();
for (Command command : commands) {
String commandName = command.getName();
if (commandName.equals(ArgsServerCommand.COMMAND_NAME)) {
Namespace namespace = ((ArgsServerCommand) command).getNamespace();
if (namespace != null) {
_ymlFilePath = namespace.getString("file");
}
}
}
}
ConfigurationFactoryFactory configurationFactoryFactory = _configurationBootstrap.getConfigurationFactoryFactory();
ValidatorFactory validatorFactory = _configurationBootstrap.getValidatorFactory();
Validator validator = validatorFactory.getValidator();
ObjectMapper objectMapper = _configurationBootstrap.getObjectMapper();
ConfigurationSourceProvider provider = _configurationBootstrap.getConfigurationSourceProvider();
final ConfigurationFactory<CustomWebConfiguration> configurationFactory = configurationFactoryFactory.create(CustomWebConfiguration.class, validator, objectMapper, "dw");
if (_ymlFilePath != null) {
// Refresh logging level.
CustomWebConfiguration webConfiguration = configurationFactory.build(provider, _ymlFilePath);
LoggingFactory loggingFactory = webConfiguration.getLoggingFactory();
loggingFactory.configure(_configurationBootstrap.getMetricRegistry(), _configurationBootstrap.getApplication().getName());
// Get my defined custom settings
CustomSettings customSettings = webConfiguration.getCustomSettings();
reloaded = true;
}
return reloaded;
}
Although this feature isn't supported out of the box by dropwizard, you're able to accomplish this fairly easy with the tools they give you.
Before I get started, note that this isn't a complete solution for the question asked as it doesn't persist the updated config values to the config.yml. However, this would be easy enough to implement yourself simply by writing to the config file from the application. If anyone would like to write this implementation feel free to open a PR on the example project I've linked below.
Code
Start off with a minimal config:
config.yml
myConfigValue: "hello"
And it's corresponding configuration file:
ExampleConfiguration.java
public class ExampleConfiguration extends Configuration {
private String myConfigValue;
public String getMyConfigValue() {
return myConfigValue;
}
public void setMyConfigValue(String value) {
myConfigValue = value;
}
}
Then create a task which updates the config:
UpdateConfigTask.java
public class UpdateConfigTask extends Task {
ExampleConfiguration config;
public UpdateConfigTask(ExampleConfiguration config) {
super("updateconfig");
this.config = config;
}
#Override
public void execute(Map<String, List<String>> parameters, PrintWriter output) {
config.setMyConfigValue("goodbye");
}
}
Also for demonstration purposes, create a resource which allows you to get the config value:
ConfigResource.java
#Path("/config")
public class ConfigResource {
private final ExampleConfiguration config;
public ConfigResource(ExampleConfiguration config) {
this.config = config;
}
#GET
public Response handleGet() {
return Response.ok().entity(config.getMyConfigValue()).build();
}
}
Finally wire everything up in your application:
ExampleApplication.java (exerpt)
environment.jersey().register(new ConfigResource(configuration));
environment.admin().addTask(new UpdateConfigTask(configuration));
Usage
Start up the application then run:
$ curl 'http://localhost:8080/config'
hello
$ curl -X POST 'http://localhost:8081/tasks/updateconfig'
$ curl 'http://localhost:8080/config'
goodbye
How it works
This works simply by passing the same reference to the constructor of ConfigResource.java and UpdateConfigTask.java. If you aren't familiar with the concept see here:
Is Java "pass-by-reference" or "pass-by-value"?
The linked classes above are to a project I've created which demonstrates this as a complete solution. Here's a link to the project:
scottg489/dropwizard-runtime-config-example
Footnote: I haven't verified this works with the built in configuration. However, the dropwizard Configuration class which you need to extend for your own configuration does have various "setters" for internal configuration, but it may not be safe to update those outside of run().
Disclaimer: The project I've linked here was created by me.

How to load Class in an OSGI E4 Environment while using Shiro?

I'm trying to build a Desktop Application using E4 with his OSGi(Equinox) Environment. For my User Security im using Shiro. But i can load class from my OSGi but shiro cant!
In my Bundle i try this :
InitActivator.java :
public class InitActivator implements BundleActivator {
private static BundleContext context;
static BundleContext getContext() {
return context;
}
#Override
public void start(BundleContext context) throws Exception {
//1. OSGi loadClass function
System.err.println(context.getBundle().loadClass("com.firm.demo.MyCustomClass")
.getName());
//2. Using Apache Shiro ClassUtils
System.err.println("Shiro : " + ClassUtils.forName("com.firm.demo.MyCustomClass"));
}
}
The 1. system.err return the right class with his qualified name.
The 2. system.err return a org.apache.shiro.util.UnknownClassException: Unable to load class named
How can i use Shiro into OSGi to find Class with Name?
If you look at the source of ClassUtils, you will see how it tries to load the classes: http://grepcode.com/file/repo1.maven.org/maven2/org.apache.shiro/shiro-core/1.0.0-incubating/org/apache/shiro/util/ClassUtils.java#ClassUtils.forName%28java.lang.String%29
The first thing it tries is to load the class with the help of the ClassLoader attached to the thread. If it fails, it tries to load with the ClassLoader that loaded ClassUtils. If it fails, it tries to load the class with the system ClassLoader.
You can trick the first one, the thread context classloader. I must mention that this is only a workaround, not a solution that is nice in the OSGi world:
BundleWiring bundleWiring = context.getBundle().adapt(BundleWiring.class);
ClassLoader bundleClassLoader = bundleWiring.getClassLoader();
Thread currentThread = Thread.currentThread();
ClassLoader originalCl = currentThread.getContextClassLoader()
currentThread.setContectClassLoader(bundleClassLoader);
try {
System.err.println("Shiro : " + ClassUtils.forName("com.firm.demo.MyCustomClass"));
} finally {
currentThread.setContextClassLoader(originalCl);
}

Spring IoC and Java EE

In Spring through the ApplicationContext class I can utilise IoC features and get a reference to a bean as follows
public class Driver {
public static void main(String args[])
{
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-config.xml");
MyClass myClass = (MyClass)applicationContext.getBean("myClass");
}
I would like to be able to do the same with Java EE, but I don't seem to be able to outside of an application server.
I'm trying the following
public class Driver {
public static void main(String args[])
{
InitialContext ic;
try {
ic = new InitialContext();
// JNDI lookup
MyClass myClass = (MyClass)ic.lookup("java:module/MyClass");
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
So far with this approach I get a javax.naming.NoInitialContextException.
My question is how can load up IoC features in a standalone application using Java EE?
EDIT Thanks for the help guys...I went with the OpenWebBeans CDI implementation... Thanks for the help.
Currently you are working with JNDI, not an IoC.
If you want JNDI worked in standalone application to locate remote data google for "jndi client".
If you want to use IoC in your Java EE application - check CDI
If you need to get JNDI resource outside web-container or application server, then before lookup you need to bind resource. But before binding you need to implement and register javax.naming.spi.InitialContextFactory implementation.
In the easiest way I would suggest to keep all bindings in the global java.util.concurrent.ConcurrentHashMap.
So it should look like the following (please keep in mind that this is easiest solution, and it might not work properly in some cases, but it satisfies your particular request):
public class Driver {
//static initializtion
static {
//registering you custom InitialContextFactory
//note, that you can register it in some other way, check http://docs.oracle.com/javase/jndi/tutorial/beyond/env/source.html
System.setProperty("java.naming.factory.initial", SimpleInitialContextFactory.class.getName());
bindMyClass();
}
private static void bindMyClass(){
try {
InitialContext context = new InitialContext();
context.bind("java:module/MyClass", new MyClass());
} catch (NamingException ignored) {}
}
public static void main(String args[]) throws Exception {
InitialContext ic = new InitialContext();
// JNDI lookup
MyClass myClass = (MyClass)ic.lookup("java:module/MyClass");//should find it
}
}
class SimpleInitialContextFactory implements InitialContextFactory {
#Override
public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
return new MapBasedContext(environment);
}
}
public class MapBasedContext implements Context {
//actual holder of context
private static Map values = new ConcurrentHashMap();
public MapBasedContext() {
}
public MapBasedContext(Hashtable<?, ?> environment) {
values.putAll(environment);
}
#Override
public void bind(String name, Object obj) throws NamingException {
values.put(name, obj);
}
#Override
public Object lookup(String name) throws NamingException {
return values.get(name); //you may throw an exception in case if name is absent
}
//TODO everything else should be implemented, but actual methods bodies aren't required
}
CDI is the spring "equivalent" in java EE 6 (in fact it is not equivalent cause it covers only Context and DI features, the others one are covered by other JSR implementation like EJB or JPA but if your problem is only to use DI then it will fit perfectly. You won't be able however to use others spring / Java EE features like Container managed transaction for example)
If you want to run it in a standalone application, go on Jboss WELD CDI implementation.
Personally i think that's it's farly better than spring for Context and DI management, but here's not the place to troll

Detecting when a handler couldn't be started when embedding Jetty

I'm embedding Jetty in a similar manner as described here. When the RequestLogHandler can't open the specified logfile, it throws an exception which is unfortunately caught by org.eclipse.jetty.server.Server and swallowed (but logged first, at least). This means that there's no obvious way for me to tell if the log handler was started correctly.
Is there a way that I'm missing to detect when a handler couldn't start?
This idea is based on the implementation of WebAppContext where you can use WebAppContext.getUnavailableException() to determine whether the context was initialized successfully.
Simply replace the default implementation of Server and Context with your own:
public static class MyContext extends Context {
private Exception _exception;
#Override
protected void doStart() throws Exception {
try {
super.doStart();
} catch (final Exception e) {
_exception = e;
}
}
#Override
protected void doStop() throws Exception {
try {
super.doStop();
} finally {
_exception = null;
}
}
public Exception getException() {
return _exception;
}
}
public static class MyServer extends Server implements InitializingBean {
public void afterPropertiesSet() throws Exception {
start();
for (final Handler h : getHandlers()) {
if (h instanceof MyContext) {
final MyContext c = (MyContext) h;
if (c.getException() != null) {
throw new RuntimeException("failed to init context " + c.getDisplayName(),
c.getException());
}
}
}
}
}
In your beans.xml, simply replace org.mortbay.jetty.Server (and remove init-method="start") and org.mortbay.jetty.servlet.Context with your own implementations.
This code is for Jetty 6 though (as is the example you linked to), as that's what I have around. I didn't test it though, but it's pretty much the same as we are successfully using in conjunction with WebAppContext. In order to extend this to RequestLogHandler, you could either do the same for just any handler you are using or create a decorator to wrap any handler. You may want to look at org.mortbay.jetty.handler.HandlerWrapper for this purpose.
How about modifying the jetty code? You could add some simple println statements in strategic places in the RequestLogHandler which would indicate to you whether or not the handler was started.

Categories

Resources