Spring Boot classpath: vs relative path - spring

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

Related

Deploying BEAN in OSGi plugin

I am currently deploying my custom controls as OSGi plugins and I wanted to do the same thing with my beans. I have tried putting them into the OSGi plugin and it works fine but the only problem I have is the faces-config.
It seems it has to be called faces-config in the OSGi plugin to work but that means i can't use beans in the NSF anymore because it seems to ignore the local faces-config.
Is there a way to change the name of the faces-config in the OSGi plugin?
Something like FEATURE-faces-config.xml?
In the class in your plugin that extends AbstractXspLibrary, you can override "getFacesConfigFiles", which should return an array of strings representing paths within the plugin to additional files of any name to load as faces-config additions. For example:
#Override
public String[] getFacesConfigFiles() {
return new String[] {
"com/example/config/beans.xml"
};
}
Then you can put the config file in that path within your Java source folder (or another folder that is included in build.properties) and it will be loaded in addition to your app's normal faces-config, beans and all.
The NSFs are running as separate, distinct Java applications. The OSGi plugin is running in the OSGi layer, above all those distinct Java applications, as a single code base. Consequently, the faces-config is only at that level.
It's possible to load them dynamically, by using an ImplicitObjectFactory, loaded from an XspContributor. That's what is done in OpenNTF Domino API for e.g. userScope (which is a bean stored in applicationScope of an NSF). See org.openntf.domino.xsp.helpers.OpenntfDominoImplicitObjectFactory, which is referenced in OpenntfDominoXspContributor, loaded via the extension point of type "com.ibm.xsp.library.Contributor".
A few caveats:
You have no control over what happens if you try to register your bean with a name the developer also uses for a different variable in that scope.
Unless you add code to check if the library is enabled, as we do, you'll be adding the bean to every database on the server.
You still need to add the library to the NSF. Unless you also provide a component that those databases will all use, there's no way you can programmatically add it, as far as I know.
It might be easier to skip the bean approach and just add an instance of the Java class in beforePageLoad, page controller class, or however you're managing the backing to the relevant XPage (if viewScope) or application (if sessionScope / applicationScope).

What is difference between class path , file system?

I know that:
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
loads context definition from an XML file located in the classpath, treating context definitions as classpath resources.
ApplicationContext context = new FileSystemXmlApplicationContext("bean.xml");
loads context definition from an XML file in the filesystem.
XmlWebApplicationContext
loads context definition from an XML file contained within a web application.
But, what does it exactly mean??
Thanks :)
ClassPathXmlApplicationContext will read files from your classpath. They must be in classes folder of your web application or in a jar in your libfolder.
FileSystemXmlApplicationContext can access all your file system, for example c:/config/applicationContext.xml.
XmlWebApplicationContext certainly can access to files contained in your web application, but this is not the most important thing. It implements WebApplicationContext and this means that it will detect ServletContextAware beans, register custom scopes (request, session, ...) among other things.
FileSystemXmlApplicationContext- You need to provide complete full path of xml bean
ClassPathXmlApplicationContext - In this case you DONOT need to set full path, as long as classpath is set
I think above opinion may have something wrong, FileSystemXmlApplicationContext can not access your whole file system, what it can only scan is your whole project folder.In order to prove my conclusion i make a example, first using ClasspathXmlApplicationContext and everything is normal, the second time i move beans.xml file to my desktop folder, so there is no beans.xml file in the project hirachy, and change ClassPathXmlApplicationContext to FileSytemXmlApplicationContext and something goes wrong, error trace below:
INFO: Loading XML bean definitions from file [/Users/crabime/Development/IdeaProjects/springInterview/Users/crabime/Desktop/beans.xml]
Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from file [/Users/crabime/Development/IdeaProjects/springInterview/Users/crabime/Desktop/beans.xml]; nested exception is java.io.FileNotFoundException: Users/crabime/Desktop/beans.xml (No such file or directory)
So FileSystemXmlApplicationContext can only detect the current project all folder. For example you make a directory which named config under the project root directory, and you can change your Main Class code like below:
ApplicationContext atx = new FileSystemXmlApplicationContext("/config/beans.xml");
And everything will ok again. So if all like sinuhepop said i think there should something need to be changed.

Springframework application context resource resolver

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.

how to inject webapp resource using relative path in spring

I have a bean which im trying to pass a relative path at web application startup. It works for an absolute path (running tomcat within eclipse) such as (C:/dev/workspace/project/src/main/webapp/WEB-INF/resource/)
However when I try to pass it a relative path such as WEB-INF/my_resource/ it says cannot find the location C:/dev/eclipse/WEB-INF/my_resource/ probably because tomcat is running within eclipse. How can I make this path relative so that it will be always picked up from whatever webcontainer is running it no matter the location of the webapp?
Ive read in place to use the servletconfig.getRelativePath(/) but neither know how to obtain the servlet config from within my bean or even if this is the right thing to do in Spring... Please help
The source code for my bean class and bean configuration xml can be found below
public class SuggestionIndexSearcher extends IndexSearcher {
private String indexSearcherType;
public SuggestionIndexSearcher(String type, String path){
super(path);
this.indexSearcherType = type;
}
...
}
The bean is defined in teh beans xml as...
<bean id="KMSearcherBean" class="com.hp.it.km.search.web.suggestion.SuggestionIndexSearcher">
<constructor-arg index="0" value="KMSearcher" />
<constructor-arg index="1" value="WEB-INF/resource/keyword" />
</bean>
If your change your bean to take org.springframework.core.io.Resource (javadoc) instead of String, then Spring will automagically coerce your path into the appropriate type of Resource. When running inside a servlet container, Spring will generally pick ServletContextResource, in which the path becomes relative to the webapp root (so WEB-INF/my_resource/ should work as you expect).
How your code chooses to handle Resource depends what you want to do with it, obviously.
No change is required in your XML config, just keep passing the path string as before. See the Spring manual for a wider description of resources.
Change the argument type from String to Resource - spring will then do the conversion and give you the resource object which you can process. You should be using an XMLWebApplicationContext (which is the default if the context is being created by the ContextLoaderListener or DispatcherServlet).
Take a look at this page for more details.

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