Expose jar resources over web - java

I have a web-service (with Spring-WS).
I have a jar with several schemas (schema1.xsd, schema2.xsd and schema3.xsd) which I include in my web service.
Is there a way to expose the schemas from the jar through a servlet somehow in my web-service wep app?
My Spring MessageDispatcherServlet is mapped to /ws/
I would like my schemas to be exposed to /schemas/schema1.xsd /schemas/schema2.xsd and so on.
I have an idea how to do it with a servlet, but it's too verbose and there has to be a nicer way.
The way I am thinking is have a servlet filter and everything that hits /schemas/ check if it is in my list of allowed resources and display it.
This has to be a server agnostic solution. (For instance http://tuckey.org/urlrewrite/ will not work).
Thanks.

Me again! Having seen the comments to your original question, I thought I'd offer an alternative solution.
If I understand your problem, it seems you have a WSDL (generated by Spring-WS) which contains references to the various schema. When a client tries to follow those schema references, it fails, because there is no such resource.
Spring-WS offers a nice way out of this, which is described in the section on WSDL exposure:
If you want to use multiple schemas,
either by includes or imports, you
might want to use the
CommonsXsdSchemaCollection, and refer
to that from the
DefaultWsdl11Definition, like so:
<bean id="schemaCollection" class="org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection">
<property name="xsds">
<list>
<value>classpath:/path/to/schema1.xsd</value>
<value>classpath:/path/to/schema2.xsd</value>
</list>
</property>
<property name="inline" value="true"/>
</bean>
When the inline property is enabled,
it follows all XSD imports and
includes, and inlines them in the
WSDL. This greatly simplifies the
deloyment of the schemas, which still
making it possible to edit them
separately.
So what you get is a generated WSDL with all of the referenced schemas inlined, so there are no references for the client to follow. It's very slick, and means you don't have to expose your schema files individually.

They only way I've found to do this in the past is the have a Spring controller (or servlet, whatever's your poison), which opens a stream to the resource in the JAR (using Class.getResourceAsStream, for example), and then "piping" it to the HTTP response (using Apache Commons IO's IOUtils.copy()).
It's not very nice, but it's a fully generic solution (just parameterise it with the classpath of the resource).
Here's my source for this:
#Controller
public class ResourceController {
private Resource resource;
#Required
public void setResource(Resource resource) {
this.resource = resource;
}
#RequestMapping
public void handleRequest(HttpServletResponse httpResponse) throws IOException {
InputStream resourceStream = resource.getInputStream();
try {
IOUtils.copy(resourceStream, httpResponse.getOutputStream());
} finally {
resourceStream.close();
}
}
}

Just package your XSD's in a war called schemas.war, put in a default web.xml, and deploy the war in whatever web container you use. Its the easiest, code-less way to solve the problem.

Sorry, this isn't exactly an "answer" but need 4 more points before I can post a comment. I wanted to get it out here though, and maybe save someone else a lot of the trouble that I just went through.
I discovered that if you only have one xsd, it will get merged into the wsdl when using just the DefaultWsdl11Definition but if you use an <sws:dynamic-wsdl> block to generate the wsdl it just creates a reference to the xsd file which may or may not be what you want. It didn't work for me when trying to use a .NET client to hit the service.

Related

REQ: Spring configured CXF ws client -- replacing hardcoded variables like 'address'

I have to contact a Web Service (WS). I'm using JDK 1.6, maven 3.04, Spring 3.20 and apache's CXF 2.7.2. Using maven I created stubs for the WS by feeding it the wsdl file. I have a spring config for the WS client and it looks something like
servlet-context.xml
<jaxws:client id="paymentClient" serviceClass="com.xxx.payment.Payment"
address="http://127.0.0:8088/mockPaymentBinding" <!-- SOAPUI mock -->
username="username"
password="secret" />
<!- username and password are for wsdl basic authentication -->
In the Java code it looks something like
#Autowired
com.xxx.payment.Payment client;
..
// Set all needed parameters.
PaymentGetBalanceResponse response = null;
PaymentGetBalance getBalance = new PaymentGetBalance();
RequestGetBalance value = new RequestGetBalance();
value.setTransactionId("transActionId");
getBalance.setRequest(value );
// Now call the WS and get the response
response = client.getBalance(getBalance); // generated by the cxf -client argument.
The "response" line is generated as an example by CXF. Then Eclipse tells me something is missing (getbalance) and optionally creates it for me above the line. Then something else is (value) missing and so on. In the end all parameters are correctly filled in. All the missing stuff/variables/objects are in the generated stubs code.
This works like a charm BUT the address is atm hardcoded in the spring config. The configuarion parameters for the application are stored in a simple database. The contents is accesible using a spring bean so I can get at the variables in the end in the code using something like config.getValue(URL);
I hoped to being able to change the 'address' (url WS) in the code above but haven't found a way to do that. Can't find setters in the generated stub code. An alternative would be to use variables in the spring servlet-context.xml file BUT those variables have to come from the database. Second alternative. I probably/hopefully get away with starting at the bottom and using the Objectfactorys (in the stubs) to create objects. Then setting the correct parameter (either in the 'new' or a setter) and then work my way to the top. A colleguee has done this (not for 'address') and this seems to work but the code is suboptimal/'messy' at best. ALSO I would like to able to have the username and password configurable, NOT static. Did quite a bit of RTM at the CXF sites but to no avail.
Read something about JaxWsProxyFactoryBean but can't figure out how to apply it here as I use Springs #autowire functionality.
I've been breaking my brains about this issue but it seems my neurons are running in circles. ANY help/pointers is really appreciated.
From CXF User Guide: How to override the service address?.
If I've inferred the spring config correctly, I think this will do:
#Autowired
com.xxx.payment.Payment client;
// ...
BindingProvider provider = (BindingProvider)client.getServicePort();
// You can set the address per request here
provider.getRequestContext().put(
BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"http://my/new/url/to/the/service");

Spring MVC Request mapping, can this be dynamic/configurable?

With Spring MVC, I know how you set the RequestMapping in every controller and method/action.
But what if I wanted this to be configurable, so for example I the following controllers:
BlogController
- with methods for listing blogs entries, single entry, new, update, etc.
ArticleController
- with methods for listing articles entries, single entry, new, update, etc.
Now in my application, the administrator can setup 2 blogs for the webiste, and 1 article section so the urls would be like:
www.example.com/article_section1/ - uses ArticleController
www.example.com/blog1/ - uses BlogController
www.example.com/blog2/ - uses BlogController
Maybe after a while the administrator wants another article section, so they just configure that with a new section like:
www.example.com/article_section2/
This has to work dynamically/on-the-fly without having to restart the application of course.
My question is only concerned with how I will handle url mappings to my controllers.
How would this be possible with Spring MVC?
I only know how to map urls to controllers using #RequestMapping("/helloWorld") at the controller or method level, but this makes the url mappings fixed and not configurable like how I want it.
Update:
I will be storing the paths in the database, and with the mapping to the type of controller so like:
path controller
/article_section1/ article
/blog1/ blog
/blog2/ blog
..
With the above information, how could I dispatch the request to the correct controller?
Again, not looking to reload/redeploy, and I realize this will require more work but its in the spec :)
Would this sort of URL mapping work for you?
www.example.com/blog/1/
www.example.com/blog/2/
If yes, then that's easy: Spring 3 supports path variables: http://static.springsource.org/spring/docs/3.0.x/reference/mvc.html#mvc-ann-requestmapping-advanced
Alternatively, you can create a generic request mapping and your own sub-dispatcher that reads a config file, but I think that's probably more work than it's worth.
Truly changing the request mappings at runtime might be hard (and not really recommended, since small errors can easily occur). If you still wish to do it, perhaps JRebel, and more specificly LiveRebel can be interesting for live redeployment of code and configuration.
Otherwise, like other posts suggested, RequestMappings supports wildcards, the limits of this should be clear after a quick read of the official documentation.
Try using with #RequestMapping wild cards as below:
#RequestMapping(value="/article_section*/"}
public void getArticle(....){
//TODO implementation
}
#RequestMapping(value="/blog*/"}
public void getBlog(....){
//TODO implementation
}
Hope this helps!!!
Also another solution might be to create a custom annotation that holds the already defined path on the #RequestMapping and also the new one to apply, let's say #ApiRestController.
Then, before the Spring context loads, the #Controller classes can be changed to have their annotation values changed at runtime by the new one (with the desired path). By doing this, Spring will load the enhanced request mapping and not the default one.
Created a small project to exemplify this for someone that needs this in the future https://gitlab.com/jdiasamaro/spring-api-rest-controllers.
Hope it helps.
Cheers.
doesn't this work?
#RequestMapping("/helloWorld*")

How do I get the size of a response from a Spring 2.5 HTTP remoting call?

I've been poking around the org.springframework.remoting.httpinvoker package in Spring 2.5 trying to find a way to get visibility into the size of the response, but I keep going around in circles.
Via another question I saw here, I think what I want to do is get a handle on the InputStream that represents the response from the server, and then wrap it with an Apache commons-io CountingInputStream. What's the best way to go about doing this?
For the moment, I'd be happy with just printing the size of the response to stdout, but eventually I want to store it in a well-known location in my app for optional display.
You're thinking along the right lines, it just needs fleshing out with specifics. Brace yourself, I'm going to hit you with a bunch of long class names...
The client-side factory that generates the stub that talks to the remote service is HttpInvokerProxyFactoryBean. The superclass (HttpInvokerClientInterceptor) has a property called httpInvokerRequestExecutor, which defaults to an instance of SimpleHttpInvokerRequestExecutor.
This is ripe for subclassing and extending; specifically it has a decorateInputStream method which you can use:
public class CountingHttpInvokerRequestExecutor extends SimpleHttpInvokerRequestExecutor {
#Override
protected InputStream decorateInputStream(InputStream is) throws IOException {
return new CountingInputStream(super.decorateInputStream(is));
}
}
And then inject that into the proxy factory:
<bean class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="httpInvokerRequestExecutor">
<bean class="com.mycompany.CountingHttpInvokerRequestExecutor"/>
</property>
<!-- Plus the various other properties required by HttpInvokerProxyFactoryBean -->
<!-- URL, proxy interface, etc -->
</bean>
The trick then becomes to get hold of that information, which will require some creative rewiring. You could, for example, obtain the new instances of CountingInputStream from another factory somewhere, which would then expose the byte count to your user interface.
The above was most of what I needed to do to get the Input/OutputStreams wired up. The last step to actually report the information involved overriding the commons-io CountingStreams' close() method to simply report the total bytes read/written during that session. I print that out using the log, and there we go! This has the drawback of not being able to match up the size to a particular service call, but perhaps some further overriding to the SimpleHttpInvokerRequestExecutor could add some further logging, though this would require the logging occurred synchronously, which is a dubious assumption.

Java Web Application: How to implement caching techniques?

I am developing a Java web application that bases it behavior through large XML configuration files that are loaded from a web service. As these files are not actually required until a particular section of the application is accessed, they are loaded lazily. When one of these files are required, a query is sent to the webservice to retrieve the corresponding file. As some of the configuration files are likely to be used much, much more often than others I'd like to setup some kind of caching (with maybe a 1 hour expiration time) to avoid requesting the same file over and over.
The files returned by the web service are the same for all users across all sessions. I do not use JSP, JSF or any other fancy framework, just plain servlets.
My question is, what is considered a best practice to implement such a global, static cache within a java Web application? Is a singleton class appropriate, or will there be weird behaviors due to the J2EE containers? Should I expose something somewhere through JNDI? What shall I do so that my cache doesn't get screwed in clustered environments (it's OK, but not necessary, to have one cache per clustered server)?
Given the informations above, Would it be a correct implementation to put an object responsible for caching as a ServletContext attribute?
Note: I do not want to load all of them at startup and be done with it because that would
1). overload the webservice whenever my application starts up
2). The files might change while my application is running, so I would have to requery them anyway
3). I would still need a globally accessible cache, so my question still holds
Update: Using a caching proxy (such as squid) may be a good idea, but each request to the webservice will send rather large XML query in the post Data, which may be different each time. Only the web application really knows that two different calls to the webservice are actually equivalent.
Thanks for your help
Here's an example of caching with EhCache. This code is used in several projects to implement ad hoc caching.
1) Put your cache in the global context. (Don't forget to add the listener in WEB.XML).
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
public class InitializationListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
CacheManager singletonManager = CacheManager.create();
Cache memoryOnlyCache = new Cache("dbCache", 100, false, true, 86400,86400);
singletonManager.addCache(memoryOnlyCache);
cache = singletonManager.getCache("dbCache");
ctx.setAttribute("dbCache", cache );
}
}
2) Retrieve the cache instance when you need it. i.e. from a servlet:
cache = (Cache) this.getContext().getAttribute("dbCache");
3) Query the cache just before you do an expensive operation.
Element e = getCache().get(key);
if (e != null) {
result = e.getObjectValue(); // get object from cache
} else {
// Write code to create the object you need to cache, then store it in the cache.
Element resultCacheElement = new Element(key, result);
cache.put(resultCacheElement);
}
4) Also don't forget to invalidate cached objects when appropriate.
You can find more samples here
Your question contains several separate questions together. Let's start slowly. ServletContext is good place where you can store handle to your cache. But you pay by having cache per server instance. It should be no problem. If you want to register cache in wider range consider registering it into JNDI.
The problem with caching. Basically, you are retrieving xml via webservice. If you are accesing this webservice via HTTP you can install simple HTTP proxy server on your side which handle caching of xml. The next step will be caching of resolved xml in some sort of local object cache. This cache can exists per server without any problem. In this second case the EHCache will do perfect job. In this case the chain of processing will be like this Client - http request -> servlet -> look into local cache - if not cached -> look into http proxy (xml files) -> do proxy job (http to webservice).
Pros:
Local cache per server instance, which contains only objects from requested xmls
One http proxy running on same hardware as our webapp.
Possibility to scale webapp without adding new http proxies for xml files.
Cons:
Next level of infrastructure
+1 point of failure (http proxy)
More complicated deployment
Update: don't forget to always send HTTP HEAD request into proxy to ensure that cache is up to date.
Option #1: Use an Open Source Caching Library Such as EHCache
Don't implement your own cache when there are a number of good open source alternatives that you can drop in and start using. Implementing your own cache is much more complex than most people realize and if you don't know exactly what you are doing wrt threading you'll easily start reinventing the wheel and resolving some very difficult problems.
I'd recommend EHCache it is under an Apache license. You'll want to take a look at the EHCace code samples.
Option #2: Use Squid
An even easier solution to your problem would be to use Squid... Put Squid in between the process that requests the data to be cached and the system making the request: http://www.squid-cache.org/
After doing some more looking around myself, it seems that the easiest way to achieve what I need (within the requirements and acceptable limitations described in the question), would be to add my caching object to the Servlet Context, and looking it up (or passing it around) where needed.
I'd just instantiate my configuration loader from a ServletContextListener, and within the contextInitialized() method, I'd just store it into the ServletContext using ServletContext.setAttribute(). It's then easy to look it up from the servlets themselves using request.getSession().getServletContext().getAttribute().
I suppose this is the proper way to do it without introducing spring or any other dependency injection framework.
Bref , you can use this ready spring ehcache configuration
1- ehcache.xml : show global configuration of Ehcache.
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./ehcache.xsd" updateCheck="false" monitoring="autodetect" dynamicConfig="true" name="myCacheManager">
<!--
see ehcache-core-*.jar/ehcache-fallback.xml for description of elements
Attention: most of those settings will be overwritten by hybris
-->
<diskStore path="java.io.tmpdir"/>
</ehcache>
2- ehcache-spring.xml : create EhCacheManagerFactoryBean and EhCacheFactoryBean.
<bean id="myCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
scope="singleton">
<property name="configLocation" value="ehcache.xml" />
<property name="shared" value="true" />
</bean>
<bean id="myCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean" scope="singleton">
<property name="cacheManager" ref="myCacheManager" />
<property name="cacheName" value="myCache" />
<property name="maxElementsInMemory" value="1000" />
<property name="maxElementsOnDisk" value="1000" />
<property name="eternal" value="false" />
<property name="diskPersistent" value="true" />
<property name="timeToIdle" value="600" />
<property name="timeToLive" value="1200" />
<property name="memoryStoreEvictionPolicy" value="LRU" />
<property name="statisticsEnabled" value="true" />
<property name="sampledStatisticsEnabled" value="true" />
</bean>
3- Inject "myCache" bean in your business class , see the following exemple to get started with getting and putting a object in your cache.
#Resource("myCache")
private net.sf.ehcache.Cache myCache;
#Resource("myService")
private Service myService;
public byte[] getFromCache(final String code)
{
// init Cache
final StringBuilder builder = new StringBuilder();
// key to identify a entry in cache map
final String key = code;
// get form the cache
final Element element = myCache.get(key);
if (element != null && element.getValue() != null)
{
return (byte[]) element.getValue();
}
final byte[] somethingToBeCached = myService.getBy(code);
// store in the cache
myCache.put(new Element(key, somethingToBeCached));
return somethingTobeCached;
}
I did not had any problems with putting cached object instance inside ServletContext. Do not forget other 2 options (request scope, session scope) with setAttributes methods of this objects. Anything that is supported natively inside webcontainers and j2ee serveers is good (by good I mean it's vendor independed, and without heavy j2ee librarires like Spring). My biggest requirements is that servers gets up and running in 5-10 seconds.
I really dislike all caching solution, beacuse it's so easy to get it working on local machine, and hard to get it working on production machines. EHCACHE, Infinispan etc.. Unless you need cluster wide replication / distribution, tightly integrated with Java ecosystem, you can use REDIS (NOSQL datatabase) or nodejs ... Anything with HTTP interface will do. Especially
Caching can be really easy, and here is the pure java solution (no frameworks):
import java.util.*;
/*
ExpirableObject.
Abstract superclass for objects which will expire.
One interesting design choice is the decision to use
the expected duration of the object, rather than the
absolute time at which it will expire. Doing things this
way is slightly easier on the client code this way
(often, the client code can simply pass in a predefined
constant, as is done here with DEFAULT_LIFETIME).
*/
public abstract class ExpirableObject {
public static final long FIFTEEN_MINUTES = 15 * 60 * 1000;
public static final long DEFAULT_LIFETIME = FIFTEEN_MINUTES;
protected abstract void expire();
public ExpirableObject() {
this(DEFAULT_LIFETIME);
}
public ExpirableObject(long timeToLive) {
Expirer expirer = new Expirer(timeToLive);
new Thread(expirer).start();
}
private class Expirer implements Runnable {
private long _timeToSleep;
public Expirer (long timeToSleep){
_timeToSleep = timeToSleep;
}
public void run() {
long obituaryTime = System.currentTimeMillis() + _timeToSleep;
long timeLeft = _timeToSleep;
while (timeLeft > 0) {
try {
timeLeft = obituaryTime - System.currentTimeMillis();
if (timeLeft > 0) {
Thread.sleep(timeLeft);
}
}
catch (InterruptedException ignored){}
}
expire();
}
}
}
Please refer to this link for further improvements.

Java REST client without schema

Goal
Java client for Yahoo's HotJobs Resumé Search REST API.
Background
I'm used to writing web-service clients for SOAP APIs, where wsimport generates proxy stubs and you're off and running. But this is a REST API, which is new to me.
Details
REST API
No WADL
No formal XML schema (XSD or DTD files). There are example XML request/response pairs.
No example code provided
Progress
I looked at question Rest clients for Java?, but the automated solutions there assume you are providing both the server and the client, with JAXB invoked on POJOs to generate a schema and a REST API.
Using Jersey (a JAX-RS implementation), I have been able to make a manual HTTP request:
import com.sun.jersey.api.client.*;
...
ClientConfig clientConfig = new DefaultClientConfig();
Client client = Client.create(clientConfig);
WebResource webResource = client.resource("https://hj.yahooapis.com/v1/HJAuthTokens");
webResource.accept("application/xml");
// body is a hard-coded string, with replacements for the variable bits
String response = webResource.post(String.class, body);
// parse response into a org.w3c.dom.Document
// interface with Document via XPATH, or write my own POJO mappings
The response can look like:
<?xml version="1.0" encoding="utf-8"?>
<Response>
<ResponseCode>0</ResponseCode>
<ResponseMessage>Login successful</ResponseMessage>
<Token>NTlEMTdFNjk3Qjg4NUJBNDA3MkJFOTI3NzJEMTdDNDU7bG9jYWxob3N0LmVnbGJwLmNvcnAueWFob28uY29tO0pVNWpzRGRhN3VhSS4yQVRqRi4wWE5jTWl0RHVVYzQyX3luYWd1TjIxaGx6U0lhTXN3LS07NjY2MzM1OzIzNDY3NTsxMjA5MDE2OTE5OzZCM1RBMVNudHdLbl9VdFFKMFEydWctLQ==</Token>
</Response>
Or, it can look like:
<?xml version="1.0" encoding="utf-8"?>
<yahoo:error xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" xml:lang="en-US">
<yahoo:description>description</yahoo:description>
<yahoo:detail>
<ErrorCode>errorCode</ErrorCode>
</yahoo:detail>
</yahoo:error>
Questions
Is there a way to auto-generate POJOs which can be marshalled/unmarshalled without a formal schema?
Should I attempt to generate those POJOs by hand, with JAXB annotations?
Is there some tool I should be leveraging so I don't have to do all this manually?
It's interesting that they provide an HTTP URL as the namespace URI for the schema, but don't actually save their schema there. That could be an oversight on their part, which an email or discussion-list posting could correct.
One approach is to create your own schema, but this seems like a lot of work for little return. Given how simple the messages are, I wonder if you even need a POJO to wrap them? Why not just have a handler that extracts the data you need using XPath?
Edit: blast from the past, but I saw the comment, reread the question, and realized that the first sentence was hard to understand. So, clarification:
One very good habit, if you're going to write a publicly accessible web service, is to make your schema document available at the same URL that you use for the schema's namespace URI -- or better, have that URL be a link to complete documentation (the W3C XSD namespace is itself a good example: http://www.w3.org/2001/XMLSchema).
I would suggest writing beans by hand, and only annotating with JAXB annotations if you have to. For most accessors/mutators (getters/setters) you do not have to; by default all public bean accessors and fields are considered, name is derived using bean convention, and default is to use elements instead of attributes (so attributes need to be annotated).
Alternatively you can of course write schema by hand, generate beans using JAXB, if you like W3C Schema a lot. And just use resulting code, not schema, for data binding.
As to POJO: that can be very simple. Something like:
#XmlRootElement("Response")
class Response {
public int responseCode;
public String responseMessage;
public String token; // or perhaps byte[] works for automated base64?
}
and similarly for other ones. Or, use getters/setters if you like them and don't mind bit more verbosity. These are just data containers, no need to get too fancy.
And if you must auto-detect type from content, consider using Stax parser to see what the root element, and then bind using JAXB Unmarshaller, handing XMLStreamReader that points to that root element. That way you can pass different object type to bind to.
And finally: sending/receiving requests: plain old HttpURLConnection works ok for GET and POST requests (construct using, say, URL.openConnection()). Jakarta HttpClient has more features if need be. So oftentimes you don't really need a separate REST client -- they may come in handy, but generally build on simple http client pieces.
I find HTTP4E very useful for making REST calls. It is an awesome Eclipse plugin, it has tabs, syntax coloring, auto suggest, code generation, REST HTTP call replay, etc.. It does a great job of HTTP debugging, HTTP tampering, hacking. I am having so much fun with it.
http://www.ywebb.com/
Try JdkRequest from jcabi-http (I'm a developer). This is how it works:
String body = new JdkRequest("http://www.google.com")
.header("User-Agent", "it's me")
.fetch()
.body()
Check this blog post for more details: http://www.yegor256.com/2014/04/11/jcabi-http-intro.html

Categories

Resources