KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > cache > ReleaseStrategy


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.cache;
11
12 import java.util.*;
13
14 import org.mmbase.core.event.*;
15 import org.mmbase.module.core.MMObjectBuilder;
16 import org.mmbase.module.core.MMBase;
17 import org.mmbase.storage.search.*;
18 import org.mmbase.storage.search.implementation.BasicCompositeConstraint;
19 import org.mmbase.util.logging.Logger;
20 import org.mmbase.util.logging.Logging;
21
22 /**
23  * <p>
24  * This class is the base for all cache release strategies. You should extend
25  * this to create your own. It will contain a number of usefull utility methods
26  * to analyze query objecs and cached search results. Feel free to add those In
27  * case you miss one developing your own strategies.
28  * </p>
29  *
30  * @author Ernst Bunders
31  * @since MMBase-1.8
32  * @version $Id: ReleaseStrategy.java,v 1.19 2006/07/28 09:23:07 michiel Exp $
33  */

34
35 public abstract class ReleaseStrategy {
36
37     private int totalEvaluated = 0;
38     private int totalPreserved = 0;
39
40     private long totalEvaluationTimeInMillis = 0;
41
42     private boolean isActive = true;
43
44     private static final Logger log = Logging.getLoggerInstance(ReleaseStrategy.class);
45
46     public ReleaseStrategy() {
47     }
48
49     public abstract String JavaDoc getName();
50
51     public abstract String JavaDoc getDescription();
52
53     /*
54      * (non-Javadoc)
55      *
56      * @see org.mmbase.cache.QueryResultCacheReleaseStrategy#avgEvaluationTimeInMilis()
57      */

58     public int getAvgEvaluationTimeInMilis() {
59         return (int) (totalEvaluationTimeInMillis / totalEvaluated);
60     }
61
62     public long getTotalEvaluationTimeMillis() {
63         return totalEvaluationTimeInMillis;
64     }
65
66     /**
67      * This method checks if evaluation should happen (active), keeps the time
68      * of the operation and updates the statistics. To implement you own
69      * strategy override
70      * {@link #doEvaluate(NodeEvent event, SearchQuery query, List cachedResult)}.
71      *
72      */

73     public final StrategyResult evaluate(final NodeEvent event, final SearchQuery query, final List cachedResult) {
74         final Timer timer = new Timer();
75         if (isActive) {
76             boolean shouldRelease = doEvaluate(event, query, cachedResult);
77             totalEvaluated++;
78             if (!shouldRelease) totalPreserved++;
79             long cost = timer.getTimeMillis();
80             totalEvaluationTimeInMillis += cost;
81             return new StrategyResult(shouldRelease, cost);
82         } else {
83             // if the cache is inactive it can not prevent the flush
84
return new StrategyResult(true, timer.getTimeMillis());
85         }
86     }
87
88     public final StrategyResult evaluate(RelationEvent event, SearchQuery query, List cachedResult) {
89         Timer timer = new Timer();
90         if (isActive) {
91             boolean shouldRelease = doEvaluate(event, query, cachedResult);
92             totalEvaluated++;
93             if (!shouldRelease) totalPreserved++;
94             long cost = timer.getTimeMillis();
95             totalEvaluationTimeInMillis += cost;
96             return new StrategyResult(shouldRelease, cost);
97         } else {
98             // if the cache is inactive it can not prevent the flush
99
return new StrategyResult(true, timer.getTimeMillis());
100         }
101     }
102
103     /*
104      * (non-Javadoc)
105      *
106      * @see org.mmbase.cache.QueryResultCacheReleaseStrategy#getTotalPreserved()
107      */

108     public int getTotalPreserved() {
109         return totalPreserved;
110     }
111
112     /*
113      * (non-Javadoc)
114      *
115      * @see org.mmbase.cache.QueryResultCacheReleaseStrategy#getTotalEvaluations()
116      */

117     public int getTotalEvaluated() {
118         return totalEvaluated;
119     }
120
121     /**
122      * implement this method to create your own strategy.
123      *
124      * @param event a node event
125      * @param query
126      * @param cachedResult
127      * @return true if the cache entry should be released
128      */

129     protected abstract boolean doEvaluate(NodeEvent event, SearchQuery query, List cachedResult);
130
131     /**
132      * implement this method to create your own strategy.
133      *
134      * @param event a relation event
135      * @param query
136      * @param cachedResult
137      * @return true if the cache entry should be released
138      */

139     protected abstract boolean doEvaluate(RelationEvent event, SearchQuery query, List cachedResult);
140
141     /*
142      * (non-Javadoc)
143      *
144      * @see org.mmbase.cache.QueryResultCacheReleaseStrategy#setEnabled(boolean)
145      */

146     public void setEnabled(boolean newStatus) {
147         if (isActive != newStatus) {
148             clear();
149             isActive = newStatus;
150         }
151     }
152
153     public boolean isEnabled(){
154        return isActive;
155     }
156
157     public void clear(){
158         totalEvaluated = 0;
159         totalPreserved = 0;
160         totalEvaluationTimeInMillis = 0;
161     }
162
163     public boolean equals(Object JavaDoc ob){
164         return ob instanceof ReleaseStrategy && this.getName().equals(((ReleaseStrategy)ob).getName());
165     }
166
167     public int hashCode(){
168         return getName().hashCode();
169     }
170
171     public String JavaDoc toString() {
172         return getName();
173     }
174
175     /**
176      * utility for specializations: get all the constraints in the query that apply to
177      * a certain field
178      * TODO MM: This method is used like this:
179      * <code> if(getConstraintsForField(fieldName, eventBuilder, constraint, query).size() > 0){ return false;}</code>
180      * IOW, only the <em>size</em> of the return list is used, and then even wheter it is 0 or not. I think it is a waste to construct a complete new list, only for that.
181      * Perhaps the method should return an Iterator?, and can be used with only 'hasNext()', constructing a longer list then necessary is avoided then.
182      * @param fieldName
183      * @param builder
184      * @param constraint
185      * @param query
186      */

187     protected static List getConstraintsForField(String JavaDoc fieldName, final MMObjectBuilder builder, Constraint constraint, final SearchQuery query){
188         if(constraint == null) constraint = query.getConstraint();
189         if(constraint == null) return Collections.EMPTY_LIST;
190         List result = new ArrayList();
191
192         if(constraint instanceof CompositeConstraint) {
193             log.debug("constraint is composite.");
194             for (Iterator i = ((CompositeConstraint)constraint).getChilds().iterator(); i.hasNext();) {
195                 Constraint c = (Constraint) i.next();
196                 result.addAll(getConstraintsForField(fieldName, builder, c, query));
197             }
198         } else if (constraint instanceof LegacyConstraint) {
199             log.debug("constraint is legacy.");
200             if(query.getSteps().size() > 1) {
201                 // how about postfixing with numbers?
202
fieldName = builder.getTableName() + "." + fieldName;
203             }
204             if(((LegacyConstraint)constraint).getConstraint().indexOf(fieldName) > -1){
205                 result.add(constraint);
206                 return result;
207             }
208         } else if (constraint instanceof FieldConstraint) {
209             log.debug("constraint is field constraint.");
210             StepField sf = ((FieldConstraint)constraint).getField();
211             if(sf.getFieldName().equals(fieldName) && (sf.getStep().getTableName().equals(builder.getTableName()) ||
212                                                        builder.isExtensionOf(MMBase.getMMBase().getBuilder(sf.getStep().getTableName()))
213                                                        )
214                ) {
215                 result.add(constraint);
216                 return result;
217             }
218         }
219         return result;
220     }
221
222     /**
223      * utility for specializations: get all the sortorders in the query that apply to
224      * a certain field
225      * TODO MM: See remark at {@link #getConstraintsForField}
226
227      * @param fieldName
228      * @param builder
229      * @param sortOrders
230      * @param query
231      */

232     protected static List getSortordersForField(final String JavaDoc fieldName, final MMObjectBuilder builder, List sortOrders, final SearchQuery query) {
233         if(sortOrders == null) sortOrders = query.getSortOrders();
234         if(sortOrders == null) return Collections.EMPTY_LIST;
235         List result = new ArrayList();
236         for (Iterator iter = sortOrders.iterator(); iter.hasNext();) {
237             SortOrder order = (SortOrder) iter.next();
238             StepField sf = order.getField();
239             String JavaDoc stepName = sf.getStep().getTableName();
240             if(sf.getFieldName().equals(fieldName) && (stepName.equals(builder.getTableName()) ||
241                                                        builder.isExtensionOf(MMBase.getMMBase().getBuilder(stepName))
242                                                        )
243                ) {
244                 result.add(order);
245             }
246         }
247         return result;
248     }
249
250
251     /**
252      * @author Ernst Bunders This class is a bean containing shouldRelease of an
253      * event evaluation
254      */

255     public static class StrategyResult {
256         private final boolean shouldRelease;
257         private final long cost;
258
259         StrategyResult(boolean shouldRelease, long cost) {
260             this.shouldRelease = shouldRelease;
261             this.cost = cost;
262         }
263
264         /**
265          * The cost of a node event evaluation. XXX What is the cost?
266          */

267         public long getCost() {
268             return cost;
269         }
270
271         /**
272          * Whether, according to this strategy, the query must be flushed.
273          */

274         public boolean shouldRelease() {
275             return shouldRelease;
276         }
277     }
278
279     /**
280      * @author Ernst Bunders This is a utility class to help timing the
281      * evaluation. Just create an instance before the evaluation and
282      * then use it to create the StrategyResult object
283      */

284     protected final static class Timer {
285         private final long now;
286
287         Timer() {
288             now = System.currentTimeMillis();
289         }
290
291         public long getTimeMillis() {
292             return System.currentTimeMillis() - now;
293         }
294     }
295
296
297 }
298
Popular Tags