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