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);
}
Related
BackGround
After reading from 1 2 3 4 5 6 Links I reached the following conclusion-
As Spring mvc designed over standered servlets,and facilitate same functionality of servlet context and application context.In spring there is two type of context ApplicationContext and WebApplicationContext-
ApplicationContext initialise by ContextLoaderListener,single instanse per application.
WebApplicationContext loaded by per DispatcherServlet.
We can understand above like this ApplicationContext extends by WebApplicationContext so what ever stuff associated with ApplicationContext at the end this is part of WebApplicationContext.
Doubts
ApplicationContextAware offers which context object.
public class SomeThing implements ApplicationContextAware {
#Override
public void setApplicationContext(ApplicationContext ctx) throws BeanException {
//this context object is `ApplicationContext` or `WebApplicationContext`?
}
}
context and container seems synonyms to most of us,I want to
give an example.Let say we have two dispatcher servlet one for
rest and other for mvc.
First Dispatcher-
public class RestInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected String[] getServletMappings() {
return new String[] { "/rest/*" };
}
}
Second Dispatcher-
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected String[] getServletMappings() {
return new String[] {
"/mvc/*"
};
}
}
than here there is two instance of WebApplicationContext,those
common part is loaded by ContextLoaderListner as define in
rootContext.
I am not sure, but there must not be 2 IocContainer in a single SpringApplication.
BeanFactory ie SpringIocContainer is,where all the bean object
lives,what ever objects we associates with WebApplicationContext is
part of Spring container,how does this container initialised by
WebApplicationContext?I want to want to know how does they both
associated with each other?
And whenever we did ctx.getBean()- this returns object from spring
container,how does this communication between context and container
happens?
There is a similar answer that denies the both are same,it says
Spring comes with several container implementations,Both load bean definitions, wire beans together, and dispense beans upon request,but an ApplicationContext offers much more.
So my point is why Both load bean definitions, wire beans together,this is kind of rework?
One more thing even though web-app is spring driven or not, there must be a context which standard servlet provides and used in Http communication......
Spring follows this or spring handles this in some other manner.And in spring context means a just IOC container, of which some part is loaded by DispacherServlet and some part is loaded by ContextLoaderListner and can facilitate much more such as I18N,access to static resource etc..
Basically, in a spring MVC application the spring contexts are registered in the servlet context of the web application. You can do that in the web.xml file setting the spring ContextLoaderListener or with java configuration. In the comments I pointed out this link where it explains how this is done via java configuration classes:
spring: where does `#autowired` look for beans?
There you can see how the 'connection' is done. Then, you asked in the comments what this achieves:
WebApplicationContextUtils.getWebApplicationContext(myServlet.getServletContext())
If you check the code of that class you can see it gets the WebApplicationContext from the attributes of the ServletContext. These attributes are set in the initialization of the web application. If you notice, in the ContextLoader class (parent of ContextLoaderListener), in the initWebApplicationContext method it sets these attributes to the servlet context:
/**
* Initialize Spring's web application context for the given servlet context,
* using the application context provided at construction time, or creating a new one
* according to the "{#link #CONTEXT_CLASS_PARAM contextClass}" and
* "{#link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
* #param servletContext current servlet context
* #return the new WebApplicationContext
* #see #ContextLoader(WebApplicationContext)
* #see #CONTEXT_CLASS_PARAM
* #see #CONFIG_LOCATION_PARAM
*/
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!");
}
Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();
try {
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}
if (logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}
return this.context;
}
catch (RuntimeException ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
catch (Error err) {
logger.error("Context initialization failed", err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
throw err;
}
}
That is done in this line:
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
As you can see, it is stored in the same place where you are trying to get it with the WebApplicationContextUtils.getWebApplicationContext(myServlet.getServletContext()) :
/**
* Find the root {#code WebApplicationContext} for this web app, typically
* loaded via {#link org.springframework.web.context.ContextLoaderListener}.
* <p>Will rethrow an exception that happened on root context startup,
* to differentiate between a failed context startup and no context at all.
* #param sc ServletContext to find the web application context for
* #return the root WebApplicationContext for this web app, or {#code null} if none
* #see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
*/
public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
}
So as you can see all the answers to your doubts are in the code that spring executes during the startup of the web application.
Hope I answered your question.
For Your Doubt 1
In an spring application there is a single instance of context Which is WebAplicationCntext per DispatcherServlet.Which can be refer by a super Interface ApplicationContext-
public class SomeThing implements ApplicationContextAware{
#Override
public void setApplicationContext(ApplicationContext ctx) throws BeanException{
//this context object is `WebApplicationContext` which is refer by `ApplicationContext`.
}
}
In spring , context means a just IOC container, of which some part is loaded by DispacherServlet and some part is loaded by ContextLoaderListner and can facilitate much more such as I18N,access to static resource etc
Your above understanding is almost correct.In Spring All the WebApplicationContext object shares some common reference which is rootContext.
This answer desn't include answer of doubt2, doubt3 ,and why all context perform same task.
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 ?
I am using EJB 3.0 and CDI to develop a java ee application which will be deployed in Websphere application server.
I have a requirement to have a property file from which i read certain configuration parameters and this property file should reside in the filesystem of the host system where my code will be deployed.
The base path ( directory where the property file will be placed ) for the property file is configured as a Name space binding String resource in Websphere application server.
Currently i have coded a Utility class to retrieve and use the property file which looks as below.
#Singleton
public class AppPropertyUtil {
private static Hashtable apppProperties;
#Resource(name="jndi/basePath",lookup="jndi/basePath")
private static String basePath;
private static final Logger LOGGER = LoggerFactory.getLogger(AppPropertyUtil.class);
protected void loadPropertyBundleFromFileSystem(String path)
{
InputStream inputStream = null;
Properties properties = null;
try {String fullPath=basePath+"/"+path+".properties";
LOGGER.info("Property file path : "+fullPath);
inputStream = new FileInputStream(new File(fullPath));
if (inputStream != null) {
properties = new Properties();
properties.load(inputStream);
LOGGER.info("Properties loaded");
apppProperties = (Hashtable)properties;
}
} catch (FileNotFoundException exception) {
LOGGER.error("Cannot read property bundle ",exception);
}
catch (IOException | IllegalArgumentException exception) {
LOGGER.error("Unable to loadproperties ",
exception);
}
}
public String getProperty(String key)
{
if(apppProperties == null)
{
loadPropertyBundleFromFileSystem("AppProps");
}
Object value = apppProperties.get(key);
if(value != null){
return (String) value;
}
return null;
}
}
But having the #Resource annotation will mandate that the AppPropertyUtil class be injected inside any class that wishes to use it. So, I will not be able to use this in any POJO classes which are not managed.
Please help me understand whether this is the best approach to go with for the above requirement or could this be improved. I would also like to make the getProperty method and loadPropertyBundleFromFileSystem method static to have it being used from a static context, but it is not possible as the class should be injected to be used.
Thanks in advance
Ideally, you shouldn't need to access to your class from any POJO. Use design patterns and separate your concerns. Use your class as a service to load up your property file and serve out a Map or Set of it's contents. POJO Models shouldn't care, but your other classes can read that map/set of properties and pass them to your pojo's or other classes which need it but don't have direct access to it.
The other option is to remove the #Resource and make this just a plain old util class that you pass in the filename to read in it's constructor, then when you call getProperty, you do what you do to check to see if it's been loaded already, if not, load it.
Wrap that in a factory that supplies the #Resource parts and it keeps your EE code from bleeding into your other jars (utils).
I have seen many class loader questions, but still was not able to figure why, the error here.
I am writing a program which uses 2 versions of jars. One is needed to get content from older storage, and another to store content in new storage.
Since, I need either of the jar to be loaded at a time, I used JarClassLoader to create a proxy for adding one jar and loading its classes. But I face ClassNotFoundException.
public class HbaseMigrator implements Runnable {
public void run() {
JarClassLoader jcl = new JarClassLoader();
jcl.add("hadoop-0.13.0-core-modified-1.jar");
Object obj1 = JclObjectFactory.getInstance().create(jcl, "UserMigThreadImpl", toProcessQueue,threadName, latch,DBUtil,lock);
MigThread mig = JclUtils.cast(obj1, MigThread.class, jcl);
Thread.currentThread().setContextClassLoader(jcl);
try {
Method method = MigThread.class.getMethod("callthis", new Class[]{});
method.invoke(mig, new Object[]{});
// mig.callthis();
} catch( Exception e) {
e.printStackTrace();
} catch(Error er) {
er.printStackTrace();
}
}
}
Method called is:
public void callthis() {
DFSUtil = new DFSAccessAPIImpl();
.........
}
This class instantiation internally uses hadoop modified jar, which is not picked up from my classloader and it throws ClassNotFoundException.
What is that I am doing wrong ?
JarClassLoader used here is jcloader :
org.xeustechnologies.jcl.JarClassLoader
I experienced this problem with loading plugins to my application, so I decided to try to load all .class files from all jars in path. Maybe this code snipped from my app will help you.
https://bitbucket.org/rsohlich/plagdetector/src/432b52f252ff7647221b7e91b08731bd9cbe2a70/PlagDetectorSpring/src/main/java/cz/sohlich/app/service/impl/PluginHolderImpl.java
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.