Java Web Application: How to implement caching techniques? - java

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.

Related

spring integration jms channel setting concurrent-consumers is causing data corruption

I'm using spring integration jms channel to consume messages from the queue and process it.
Here is my inbound-channel-config.xml
<jms:message-driven-channel-adapter id="jmsIn"
destination="requestQueue"
channel="routingChannel"
connection-factory="cachingConnectionFactory"
error-channel="errorChannel"
concurrent-consumers="${jms_adapter_concurrent_consumers}" />
Here when i set concurrent-consumers to a value greater than 1, the messages that i consume gets corrupted while processing. I'm consuming XML and Json messages from the queue and while parsing the data, i could see that some of its contents are changed and set to some random value.
The above config works fine only when concurrent-consumers value is set to 1.
My question is, do i have to manually Synchronize (make thread safe) my code when i set concurrent-consumers to a value greater than 1?
Yes, your code must be thread safe. That's the case for any multi threaded code.
However, synchronizing the whole thing will effectively defeat concurrency. It's better to use stateless code (no fields), or use thread-safe variables (AtomicInteger and friends), or limit synchronization to small blocks.
If you synchronize the whole listener code, only one container thread can process at a time.
Vishal and I work together.
I have to mention that the caching connection factory is being used, and I noticed that in this post you discouraged its use.
<bean id="cachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="MQConnectionFactory" />
<property name="sessionCacheSize" value="10"/>
</bean>
#Bean(name="MQConnectionFactory")
public ConnectionFactory connectionFactory() {
if (factory == null) {
factory = new MQConnectionFactory();
try {
factory.setHostName(env.getRequiredProperty(HOST));
factory.setPort(Integer.parseInt(env.getRequiredProperty(PORT)));
factory.setQueueManager(env.getRequiredProperty(QUEUE_MANAGER));
factory.setChannel(env.getRequiredProperty(CHANNEL));
factory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
} catch (JMSException e) {
throw new RuntimeException(e);
}
}
return factory;
}
Could this be causing the issues? It seems so far that the issue happens in Spring Integration's default message convertors, as in some cases parts of the payload is "".
Cheers
Kris

How to query CAS for all logged in users?

I am putting together an SSO system for all of our internal apps and will be using CAS. I have been asked to make a simple web app whose sole purpose in life is to monitor CAS and display a page containing the usernames of all the currently logged-in users.
I am trying to figure out the best way to query CAS for this kind of information.
I know that CAS has a concept of a TicketRegistry that keeps a list of all active/valid tickets; where each ticket has user information (I believe in the form of an IPersonAttributeDao). Perhaps there is a why to query CAS for the contents of its ticket registry, and obtain each person attribute's username info somehow?
If not the ticket registry, what would be a good way to access this info?
There's nothing in CAS protocol that allows to query a server for the list of the currently active tickets.
I assume you are using Jasig CAS as your server. I think you could add a view, controller and domain object injected with current ticket registry and simply call TicketRegistry.getTickets() to have all Tickets (including expired ones). You will still have to call getAuthentication for the implementation of Ticket (it exists in both ServiceTicket and ServiceGrantingTicket but I could not find it in any superclass or interface), and then Authentication.getPrincipal().
I do not know if the list of PrincipalS that you will get will contains duplicates, but if I were you I would test for such duplicates.
CAS is a Spring application so the first place to look for adding this stuff should be cas-server-webapp/src/main/webapp/WEB-INF/cas-servlet.xml.
I'm afraid I can't do more without knowing the exact implementation of CAS you will use.
cas-server-webapp is a spring-mvc app, so you should find a lot of information in Spring documentation - please note that as CAS 3.1 uses version 2 of Spring you should look at http://docs.spring.io/spring-framework/docs/2.5.3/reference/ .
The following is only a skeleton of what could be done and is untested stuff that may contains typo or other mistakes. Also, there are no interfaces, and view name is hardcoded what are not recommended practices in real world. It must be taken for what it is : a simplified skeletal example of a possible implementation.
Domain object (optional)
private TicketRegistry ticketRegistry;
public class LoggedUsersService {
public List<what_you_want> getLoggedInUsers() {
List<Principal> userList; // or List<Authentication> or ...
// extract pricipal list from ticketRegistry
...
return userList;
}
public void setTicketRegistry(TicketRegistry ticketRegistry) {
this.ticketRegistry = ticketRegistry);
}
}
It should be declared in deployerConfigContext.xml
<bean id="loggedUserService" class="path_to/LoggerUserService">
<property name="ticketRegistry" ref="ticketRegistry"/>
</bean>
It is optional because you could do that stuff directly in controller ... but separation makes tests easier.
Controller
private LoggedUsersService loggedUsersService;
public class LoggedUserController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mav = new ModelAndView();
// set view name and optionaly whant you need to do
mav.setViewName("loggedusers")
mav.addObject("userList", loggedUserService.getLoggedInUsers());
return mav;
}
public void setLoggedUsersService(LoggedUserService loggedUsersService) {
this.loggedUsersService = loggedUsersService;
}
}
It should be declared in cas-servlet.xml and included in a handler mapping
<bean id="loggedUserController" class="path_to/LoggerUserService">
<property name="ticketRegistry" ref="ticketRegistry"/>
</bean>
<bean id="handlerMappingC"
...
<props>
...
<prop key="/loggedUsers">loggedUsersController</prop>
</props>
...
</bean>
View
Then in your loggedusers.jsp, you can access to the list of users under bean name "userList" in request scope
<jsp:useBean id="userList" scope="request"/>

How to Connect to Oracle Database Through Alfresco Javascript API

So I have been working with Alfresco for a project I'm currently working on, and one of the newest requirements for the project is that I pull a sequence number from our Oracle database and populate a custom property within a space in Alfresco.
var conObj = new ActiveXObject('ADODB.Connection');
var connectionString = "Provider=OraOLEDB.Oracle;Data Source=(DESCRIPTION=(CID=GTU_APP)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=IP ADDRESS)(PORT=XXXX)))(CONNECT_DATA=(SID=your_SID)(SERVER=DEDICATED)));User Id=username;Password=pwd;"
conObj.Open(connectionString);
var rs = new ActiveXObject("ADODB.Recordset");
var caseID;
sql = "INSERT INTO case(mod_dt,mod_user) values(sysdate,’user’) RETURNING id"
rs.Open(sql, conObj);
caseID = rs(0);
logger.log("The new case id is: " + caseID);
rs.close;
However, this returned saying:
Caused by: org.mozilla.javascript.EcmaError: ReferenceError: "ActiveXObject" is not defined. (workspace://SpacesStore/b3145512-e54d-4d9e-9655-0b6ae678e39b#141)
Which made me realize Alfresco's Javascript API doesn't have the full functionality of Javascript. I had read something about creating your own java class and calling them from within the Alfresco javascript, but I had not seen any good examples. Does anyone have experience with this or could they demonstrate a simple example of creating a java class to call from within Alfresco Javascript?
ActiveXObject is an IE specific thing, it's not available in non-IE browsers so it's hardly surprising that it isn't available in server-side JavaScript!
As I understand it, you're writing your JavaScript to be run as a rule, so it'll be executed in the Alfresco Repository tier. That makes life slightly easier. What you'll probably want to do is write some Java code that handles the connection and querying of Oracle, using Oracle's Java APIs (JDBC or similar).
When running in the repository, your JavaScript already has access to a large number of "root" objects, which can be used to perform a variety of operations on the repository. What you'll want to do is inject your new Java class as an additional one, so it's available for your rule script to use when it runs.
(If you were writing a webscript, then you could just arrange to have the java object made available to the JavaScript model of your webscript. However, as you're doing a rule, that's not an option)
To do that, have your new class extend BaseScopableProcessorExtension. Then, when you define a spring bean for it, set the extensionName property to control the name it appears in JavaScript as. There are quite a few examples in Alfresco itself you can look at for this, ScriptSiteSevice (bean id siteScriptService) is one that springs to mind.
In case you're new to spring and Alfresco, I'd suggest you either wrap your whole thing up as a module (AMP), or cheat a little and just drop the context file in a new alfresco/extensions directory under your tomcat shared classes. Your file would look something like:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<bean id="myOracleQueryBean" parent="baseJavaScriptExtension"
class="com.my.comany.namespace.alfresco.OracleScriptQuery">
<!-- What it should be called in JS -->
<property name="extensionName">
<value>oracleQuery</value>
</property>
<!-- Inject any other things that your bean needs here -->
<!-- eg some Oracle stuff from Spring -->
</bean>

Expose jar resources over web

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.

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.

Categories

Resources