Springframework application context resource resolver - spring

Does anyone know how to manipulate a spring application context to use a specified resource resolver. I have written an s3 resource to pull content from a security context from amazon s3, and a resource resolver to create these "resources" from s3://... type urls, and the local application context uses the right security credentials on load from the configured amazons3client. I've written an s3 ResourceLoader that preconfigure the AmazonS3 client for a newly constructed s3 resource.
It would be nice to be able to specify these resources in the context configuration as simply "s3://..." and rely on this resource resolver to create the right resource type, however, so far this requires overriding the spring ApplicationContext's getResource method inherited from DefaultResourceLoader to use my own resourceResolver implementation.
Another tack is to configure a variable resolver for resources matching the "s3://..." scheme to resolve resource types with that resource resolver.
I am hoping their is a spring guru out their that knows a better way to manipulate the infrastructure of the spring application context (ClasspathXMLAC for arguments sake) to make my S3 security needs very easy to deal with.
Other suggestions are welcome.

Use an implementation of Spring's GenericApplicationContext, which provides you with a #setResourceLoader method.
You mentioned ClassPathXmlApplicationContext, which is not a GenericApplicationContext, meaning that you're forced to take the uglier overriding route.
GenericXmlApplicationContext is a generally preferred alternative to CPXAC, and as the name suggests, is a GenericApplicationContext.
So you should be able to do the following:
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.setResourceLoader(new S3ResourceLoader());
ctx.load("s3:///some.bucket.name/path/to/my/spring.xml");
ctx.refresh();
...
Obviously, the S3ResourceLoader will need to be parameterized with keys, etc. Note that the S3ResourceLoader should probably extend DefaultResourceLoader in order to pick up all the other functionality available there, e.g. processing "classpath:" and other resource prefixes.
Order of invocation in the above example matters, i.e. the resource loader needs to be provided before #load is called with an s3: resource prefix for obvious reasons.

Related

Spring Boot classpath: vs relative path

In Spring Boot, to access a resource, say myresource.json, I can use both classpath: or a relative path, like ./myresource.json
What is the difference? Which one should I use?
When you call getResource() on a specific application context, and the location path specified doesn't have a specific prefix like ./myresource.json, you will get back a Resource type that is appropriate to that particular application context.
If getResource() was executed against a ClassPathXmlApplicationContext instance it will return a ClassPathResource.If the same method was executed against a FileSystemXmlApplicationContext instance, you'd get back a FileSystemResource. For a WebApplicationContext, you'd get back a ServletContextResource, and so on.
As such, you can load resources in a fashion appropriate to the particular application context.
On the other hand, you may also force ClassPathResource to be used, regardless of the application context type, by specifying the special classpath: prefix.
See this doc

Mule connector config needs dynamic attributes

I have develop a new Connector. This connector requires to be configured with two parameters, lets say:
default_trip_timeout_milis
default_trip_threshold
Challenge is, I want read ${myValue_a} and ${myValue_a} from an API, using an HTTP call, not from a file or inline values.
Since this is a connector, I need to make this API call somewhere before connectors are initialized.
FlowVars aren't an option, since they are initialized with the Flows, and this is happening before in the Mule app life Cycle.
My idea is to create an Spring Bean implementing Initialisable, so it will be called before Connectors are init, and here, using any java based libs (Spring RestTemplate?) , call API, get values, and store them somewhere (context? objectStore?) , so the connector can access them.
Make sense? Any other ideas?
Thanks!
mmm you could make a class that will create the properties in the startup and in this class obtain the API properties via http request. Example below:
public class PropertyInit implements InitializingBean,FactoryBean {
private Properties props = new Properties();
#Override
public Object getObject() throws Exception {
return props;
}
#Override
public Class getObjectType() {
return Properties.class;
}
}
Now you should be able to load this property class with:
<context:property-placeholder properties-ref="propertyInit"/>
Hope you like this idea. I used this approach in a previous project.
I want to give you first a strong warning on doing this. If you go down this path then you risk breaking your application in very strange ways because if any other components depend on this component you are having dynamic components on startup, you will break them, and you should think if there are other ways to achieve this behaviour instead of using properties.
That said the way to do this would be to use a proxy pattern, which is a proxy for the component you recreate whenever its properties are changed. So you will need to create a class which extends Circuit Breaker, which encapsulates and instance of Circuit Breaker which is recreated whenever its properties change. These properties must not be used outside of the proxy class as other components may read these properties at startup and then not refresh, you must keep this in mind that anything which might directly or indirectly access these properties cannot do so in their initialisation phase or your application will break.
It's worth taking a look at SpringCloudConfig which allows for you to have a properties server and then all your applications can hot-reload those properties at runtime when they change. Not sure if you can take that path in Mule if SpringCloud is supported yet but it's a nice thing to know exists.

Look up a dynamic property at run-time in Spring from PropertySourcesPlaceholderConfigurer?

Not sure of the best approach to this. We've created a jar that could be used by different projects. The other projects relying on this jar need to provide certain properties defined in one of their spring properties files. (Our jar shouldn't care what they name those property files.)
Using #Value("${some.prop}") works great for most properties, however we now have the requirement that the name of the property to look up is dynamic. For example:
int val = getSomeVal();
String propNeeded = foo.getProperty("foo."+val+".dynamic.prop");
Not sure what "foo" should be to get my access. I looked into injecting Environment, however from all my googling it looks like that will not load from an xml property-placeholder definition (even if defined as a bean def for PropertySourcesPlaceholderConfigurer.) You seem to have to use #PropertySource, yet my main config is an XML file so not sure how to get Environment to work. (I can't really go 'old skool' and look up the property file as a class path Resource either since I'm not aware of the name of the file the users defined.)
I don't mind making this particular Service class ApplicationContextAware, but if I did that how could I get access to the underlying PropertySourcesPlaceholderConfigurer ? which I would 'seem?' to need in order to get access to a property dynamically?
The other option is that I force users of the jar to declare a bean by a name that I can look up
<util:properties id="appProps" location="classpath:application.properties" />
And I then inject appProps as Properties and look up from there. I don't like this approach though since it forces the users of the library to name an file by a common id. I would think the best solution is to just get a handle in some way to the underlying PropertySourcesPlaceholderConfigurer in my service class... I'm just not sure how to do it?
Why doesn't Spring simply allow PropertySource to be defined some how via your XML config and then I could just inject Environment?
Thanks for any suggestions how to accomplish what I want.
You could have a ReloadableResourceBundleMessageSource declared to read from the same source as the PropertySourcesPlaceholderConfigurer. This way you could just #Autowire MessageSource (or make your bean implement MessageSourceAware) and use that to retrieve your properties.
Main reason for using ReloadableResourceBundleMessageSource is to retrieve I18N messages, so that would kind of hacky...

Spring environment validation

We're building a Spring-based application which will be delivered to end users as a distribution package. Users are responsible for properly configuring whatever needs to be configured (it's mostly about various filesystem locations, folder access permissions, etc). There's a good idea to make the app help users understand what is not configured or which parts of configuration are invalid.
Our current approach is a custom ApplicationContextInitializer which does all the environment validation "manually" and then registers few "low level" beans in the application context explicitly. If something is wrong, initializer throws, exception is caught somewhere in main(), interpreted (converted into plain English) and then displayed.
While this approach works fine, I'm wondering if there are any best practices to minimize hand-written code and use Spring whenever possible.
Here's an illustrative example. The application requires a folder for file uploads. This means:
There should be a configuration file
This file should be accessible by the app
This file should have no syntax errors
This file should explicitly define some specific property (let it be app.uploads.folder)
This property should describe the existing filesystem entity
This entity should be a folder
The app should have read/write access to this folder
Does Spring provide any tools to implement this sort of validation easily?
Spring Boot has a nice feature for context and external configuration validation. If you define a POJO class and declare it as #ConfigurationProperties then Spring will bind the Environment (external properties and System/OS typically) to its properties using a DataBinder. E.g.
#ConfigurationProperties(name="app.uploads")
public class FileUploadProperties {
private File folder;
// getters and setters ommitted
}
will bind to app.uploads.folder and ensure that it is a File. For extra validation you can do it manually in the setter, or you can implement Validator in your FileUploadProperties or you can use JSR-303 annotations on the fields. By default an external property in app.uploads.* that doesn't bind will throw an exception (e.g. a mis-spelled property name, or a conversion/format error).
If you use Spring Boot Autoconfigure #EnableAutoConfigure you don't have to do anything else, but if it's just vanilla Spring (Boot) you need to say #EnableConfigurationProperties in your #Configuration somewhere as well.
A bonus feature: if you also use the Spring Boot Actuator you will also get JMX and HTTP support (in a webapp) for inspecting the bindable and bound properties of #ConfigurationProperties beans. The HTTP endpoint is "/configprops".

osgi HttpService register resource from outside of the bundle ( filesystem )

I am using OSGI's HttpService to register my servlets and resources.
To register resource I am using HttpService.registerResources(java.lang.String alias, java.lang.String name, HttpContext context)
I have tested that "name" can take any relative path inside the bundle. example /resource where resource is a folder inside the bundle jar.
But I want to give "name" a value outside of the bundle example /home/user/webapps/resource.
i.e. name links to the filesystem's path.
I want to know if that's possible and how ?
I saw a similar post but it didn't conclude.
how to get the image which is outside the OSGi bundle?
An easy way to fetch objects from outside the bundle is to implement a servlet as Robert described it.
A better way, were you have much better control on what objects to return, correct MIME type handling etc. is to implement an HttpContext object and to register it with the HTTP Service. The HTTP Service then always calls method HttpContext.getResource(String name) whenever a resource is requested. And here you can serve your objects from the file system. From the specification:
public URL getResource( String name )
Called by the Http Service to map a
resource name to a URL. For servlet
registrations, Http Service will
call this method to support the
ServletContext methods getResource and
getResourceAsStream. For resource
registrations, Http Service will
call this method to locate the named
resource. The context can control from
where resources come. For example, the
resource can be mapped to a file in
the bundle’s persistent storage area
via
bundleContext.getDataFile(name).toURL()
or to a resource in the context’s
bundle via
getClass().getResource(name).
Please have a look at section 102.3, Registering Resources and following of the OSGi Service Compendium. There, the whole concept is explained in detail and with examples.
I am not familiar with the deep internals of HttpService.registerResources(..) but my work-around solution would be to implement a Servlet that delivers the resources. As it is your own implementation you can access the filesystem as well.
The only thing you have to keep in mind when implementing that Servlet is to set the correct Content-Type and may be other required response header fields.

Resources