View Javadoc

1   /*
2    * $Id: ObjectStoreCachingStrategy.java 23218 2011-10-19 14:21:25Z pablo.kraan $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.cache;
12  
13  import org.mule.api.MuleEvent;
14  import org.mule.api.MuleException;
15  import org.mule.api.ThreadSafeAccess;
16  import org.mule.api.processor.MessageProcessor;
17  import org.mule.api.routing.filter.Filter;
18  import org.mule.api.store.ObjectAlreadyExistsException;
19  import org.mule.api.store.ObjectDoesNotExistException;
20  import org.mule.api.store.ObjectStore;
21  import org.mule.api.store.ObjectStoreException;
22  import org.mule.cache.filter.ConsumableMuleMessageFilter;
23  import org.mule.cache.keygenerator.KeyGenerator;
24  import org.mule.cache.keygenerator.MD5KeyGenerator;
25  import org.mule.cache.responsegenerator.DefaultResponseGenerator;
26  import org.mule.cache.responsegenerator.ResponseGenerator;
27  import org.mule.util.store.InMemoryObjectStore;
28  
29  import java.io.Serializable;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  
34  /**
35   * Implements {@link CachingStrategy} using an {@link ObjectStore} as a cache.
36   * <p/>
37   * Object's keys are generated using a {@link KeyGenerator} and the responses
38   * are generated using a {@link ResponseGenerator}.
39   * The caching strategy will only cache the {@link MuleEvent} that have a
40   * non consumable message's payload. This check is done in both request and response
41   * events using a configurable {@link Filter}.
42   */
43  public class ObjectStoreCachingStrategy implements CachingStrategy
44  {
45  
46      protected Log logger = LogFactory.getLog(getClass());
47  
48      private ObjectStore<MuleEvent> store = new InMemoryObjectStore<MuleEvent>();
49  
50      private KeyGenerator keyGenerator = new MD5KeyGenerator();
51  
52      private ResponseGenerator responseGenerator = new DefaultResponseGenerator();
53  
54      private Filter consumableFilter = new ConsumableMuleMessageFilter();
55  
56      private String name;
57  
58      public MuleEvent process(MuleEvent request, MessageProcessor messageProcessor) throws MuleException
59      {
60          if (consumableFilter.accept(request.getMessage()))
61          {
62              Serializable key;
63              try
64              {
65                  key = keyGenerator.generateKey(request);
66              }
67              catch (Exception e)
68              {
69                  logger.warn("Message will be processed without cache: key generation error", e);
70                  return messageProcessor.process(request);
71              }
72  
73              return processMessageWithCache(key, request, messageProcessor);
74          }
75          else
76          {
77              return messageProcessor.process(request);
78          }
79      }
80  
81      private MuleEvent processMessageWithCache(Serializable key, MuleEvent request, MessageProcessor messageProcessor) throws MuleException
82      {
83          MuleEvent cachedResponse = lookupEventInCache(key);
84  
85          MuleEvent response;
86  
87          if (cachedResponse != null)
88          {
89              response = responseGenerator.create(request, cachedResponse);
90          }
91          else
92          {
93              response = messageProcessor.process(request);
94  
95              if (response == null || consumableFilter.accept(response.getMessage()))
96              {
97                  MuleEvent responseCopy = response;
98                  if (response instanceof ThreadSafeAccess)
99                  {
100                     responseCopy = (MuleEvent) ((ThreadSafeAccess) response).newThreadCopy();
101                 }
102                 store(key, responseCopy);
103             }
104         }
105 
106         return response;
107     }
108 
109     private MuleEvent lookupEventInCache(Serializable key)
110     {
111         MuleEvent event = retrieve(key);
112 
113         if (logger.isDebugEnabled())
114         {
115             if (event != null)
116             {
117                 logger.debug("Cache hit for key: " + key + " Event: " + event);
118             }
119             else
120             {
121                 logger.debug("Cache miss for key: " + key);
122             }
123         }
124 
125         return event;
126     }
127 
128     protected void store(Serializable key, MuleEvent value)
129     {
130         try
131         {
132             store.store(key, value);
133         }
134         catch (ObjectAlreadyExistsException e)
135         {
136             if (logger.isInfoEnabled())
137             {
138                 logger.info("An object with the specified key already exists in the object store (" + key + ")");
139             }
140         }
141         catch (ObjectStoreException e)
142         {
143             // Logs a warning to indicate that there is an error accessing the
144             // object store, but does not re-throw the exception to avoid
145             // affecting the current event being processed, which can continue with
146             // out caching.
147             logger.warn("Unable to store event in cache", e);
148         }
149     }
150 
151     protected MuleEvent retrieve(Serializable key)
152     {
153         try
154         {
155             return store.retrieve(key);
156         }
157         catch (ObjectDoesNotExistException e)
158         {
159             // Nothing to do
160         }
161         catch (ObjectStoreException e)
162         {
163             // Logs a warning to indicate that there is an error accessing the
164             // object store, but does not re-throw the exception to avoid
165             // affecting the current event being processed, which can continue with
166             // out caching.
167             logger.warn("Unable to retrieve object from cache", e);
168         }
169 
170         return null;
171     }
172 
173     public ObjectStore<MuleEvent> getStore()
174     {
175         return store;
176     }
177 
178     public void setStore(ObjectStore<MuleEvent> store)
179     {
180         this.store = store;
181     }
182 
183     public KeyGenerator getKeyGenerator()
184     {
185         return keyGenerator;
186     }
187 
188     public void setKeyGenerator(KeyGenerator keyGenerator)
189     {
190         this.keyGenerator = keyGenerator;
191     }
192 
193     public ResponseGenerator getResponseGenerator()
194     {
195         return responseGenerator;
196     }
197 
198     public void setResponseGenerator(ResponseGenerator responseGenerator)
199     {
200         this.responseGenerator = responseGenerator;
201     }
202 
203     public Filter getConsumableFilter()
204     {
205         return consumableFilter;
206     }
207 
208     public void setConsumableFilter(Filter consumableFilter)
209     {
210         this.consumableFilter = consumableFilter;
211     }
212 
213     public String getName()
214     {
215         return name;
216     }
217 
218     public void setName(String name)
219     {
220         this.name = name;
221     }
222 }