log4j implemented for the producer subsystem
[mir.git] / source / mir / producer / EntityBatchingProducerNode.java
1 /*
2  * Copyright (C) 2001, 2002  The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with the com.oreilly.servlet library, any library
22  * licensed under the Apache Software License, The Sun (tm) Java Advanced
23  * Imaging library (JAI), The Sun JIMI library (or with modified versions of
24  * the above that use the same license as the above), and distribute linked
25  * combinations including the two.  You must obey the GNU General Public
26  * License in all respects for all of the code used other than the above
27  * mentioned libraries.  If you modify this file, you may extend this exception
28  * to your version of the file, but you are not obligated to do so.  If you do
29  * not wish to do so, delete this exception statement from your version.
30  */
31
32 package mir.producer;
33
34 import java.util.*;
35 import java.io.*;
36
37 import mir.entity.adapter.*;
38 import mir.entity.*;
39 import mir.storage.*;
40 import mir.util.*;
41 import mir.log.*;
42
43 public class EntityBatchingProducerNode implements ProducerNode {
44   private String batchInfoKey;
45   private String batchDataKey;
46   private EntityAdapterModel model;
47   private String definition;
48   private String whereClause;
49   private String orderByClause;
50   private String nrEntitiesToSkipExpression;
51   private String nrEntitiesPerBatchExpression;
52   private String minNrEntitiesInFirstBatchExpression;
53   private String nrBatchesToProcessExpression;
54   private ProducerNode batchSubNode;
55   private ProducerNode batchListSubNode;
56
57   public EntityBatchingProducerNode(
58         String aBatchDataKey,
59         String aBatchInfoKey,
60         EntityAdapterModel aModel,
61         String aDefinition,
62         String aWhereClause,
63         String anOrderByClause,
64         String anrEntitiesPerBatchExpression,
65         String aminNrEntitiesInFirstBatchExpression,
66         String anrEntitiesToSkipExpression,
67         String aNrBatchesToProcessExpression,
68         ProducerNode aBatchSubNode,
69         ProducerNode aBatchListSubNode) {
70
71     batchSubNode = aBatchSubNode;
72     batchListSubNode = aBatchListSubNode;
73
74     batchDataKey = aBatchDataKey;
75     batchInfoKey = aBatchInfoKey;
76     model = aModel;
77     definition = aDefinition;
78     whereClause = aWhereClause;
79     orderByClause = anOrderByClause;
80     nrEntitiesToSkipExpression = anrEntitiesToSkipExpression;
81     nrEntitiesPerBatchExpression = anrEntitiesPerBatchExpression;
82     minNrEntitiesInFirstBatchExpression = aminNrEntitiesInFirstBatchExpression;
83     nrBatchesToProcessExpression = aNrBatchesToProcessExpression;
84   }
85
86   protected boolean isAborted(Map aValueMap) {
87     Object producerValue = aValueMap.get(NodedProducer.PRODUCER_KEY);
88     return (
89        (producerValue instanceof NodedProducer) &&
90       ((NodedProducer) producerValue).getIsAborted());
91   }
92
93   public void produce(Map aValueMap, String aVerb, LoggerWrapper aLogger) throws ProducerFailure {
94     Iterator browser;
95     int nrEntities;
96     int nrBatchesAfterFirst;
97     int nrEntitiesInFirstBatch;
98     int nrBatchesToProcess;
99     List batchesData;
100     int i;
101     int position;
102     Map batchData;
103     String expandedWhereClause;
104     String expandedOrderByClause;
105
106     List batchLocations;
107     BatchLocation location;
108
109     int nrEntitiesToSkip;
110     int nrEntitiesPerBatch;
111     int minNrEntitiesInFirstBatch;
112
113 //  ML: The order by clause should lead to a result set in _reverse order_: the first row will be
114 //      the last entity presented on the last page
115
116
117     try {
118       nrBatchesToProcess = ParameterExpander.evaluateIntegerExpressionWithDefault( aValueMap, nrBatchesToProcessExpression, -1 );
119
120       expandedWhereClause = ParameterExpander.expandExpression( aValueMap, whereClause );
121       expandedOrderByClause = ParameterExpander.expandExpression( aValueMap, orderByClause );
122
123       nrEntitiesToSkip = ParameterExpander.evaluateIntegerExpression( aValueMap, nrEntitiesToSkipExpression);
124       nrEntitiesPerBatch = ParameterExpander.evaluateIntegerExpression( aValueMap, nrEntitiesPerBatchExpression);
125       minNrEntitiesInFirstBatch = ParameterExpander.evaluateIntegerExpression( aValueMap, minNrEntitiesInFirstBatchExpression);
126
127       batchesData = new Vector();
128       batchLocations = new Vector();
129
130       nrEntities = model.getMappingForName(definition).getStorage().getSize(expandedWhereClause)-nrEntitiesToSkip;
131       nrEntitiesInFirstBatch = nrEntities % nrEntitiesPerBatch;
132       while (nrEntitiesInFirstBatch<minNrEntitiesInFirstBatch && nrEntities-nrEntitiesInFirstBatch>=nrEntitiesPerBatch)
133         nrEntitiesInFirstBatch = nrEntitiesInFirstBatch + nrEntitiesPerBatch;
134       nrBatchesAfterFirst = (nrEntities-nrEntitiesInFirstBatch)/nrEntitiesPerBatch;
135
136       batchLocations.add(new BatchLocation(nrBatchesAfterFirst*nrEntitiesPerBatch, nrEntitiesInFirstBatch));
137       batchData = new HashMap();
138       batchData.put("identifier", "");
139       batchData.put("index", new Integer(nrBatchesAfterFirst+1));
140       batchData.put("size", new Integer(nrEntitiesInFirstBatch));
141       batchesData.add(batchData);
142
143       for (i=0; i<nrBatchesAfterFirst; i++) {
144         batchLocations.add(1, new BatchLocation(i*nrEntitiesPerBatch, nrEntitiesPerBatch));
145         batchData = new HashMap();
146         batchData.put("identifier", new Integer(i));
147         batchData.put("index", new Integer(i+1));
148         batchData.put("size", new Integer(nrEntitiesPerBatch));
149         batchesData.add(1, batchData);
150       }
151
152       batchData = new HashMap();
153       ParameterExpander.setValueForKey(aValueMap, batchInfoKey, batchData);
154       batchData.put("all", batchesData);
155       batchData.put("first", batchesData.get(0));
156       batchData.put("last", batchesData.get(batchesData.size()-1));
157       batchData.put("count", new Integer(batchesData.size()));
158
159       if (batchListSubNode!=null && (!isAborted(aValueMap))) {
160         batchListSubNode.produce(aValueMap, aVerb, aLogger);
161       }
162
163       if (nrBatchesToProcess<0 || nrBatchesToProcess>nrBatchesAfterFirst+1) {
164         nrBatchesToProcess = nrBatchesAfterFirst+1;
165       }
166
167       if (batchSubNode!=null) {
168         for (i=0; i<nrBatchesToProcess && !isAborted(aValueMap); i++) {
169           location = (BatchLocation) batchLocations.get(i);
170
171           batchData.put("current", batchesData.get(i));
172           if (i>0)
173             batchData.put("previous", batchesData.get(i-1));
174           else
175             batchData.put("previous", null);
176
177           if (i<batchesData.size()-1)
178             batchData.put("next", batchesData.get(i+1));
179           else
180             batchData.put("next", null);
181
182           Iterator j = new EntityIteratorAdapter(expandedWhereClause, expandedOrderByClause,
183                     location.nrEntities, model, definition, location.nrEntities, location.firstEntity);
184           List entities = new Vector();
185
186           while (j.hasNext())
187             entities.add(0, j.next());
188
189           ParameterExpander.setValueForKey(aValueMap, batchDataKey, entities );
190
191           batchSubNode.produce(aValueMap, aVerb, aLogger);
192         }
193       }
194     }
195     catch (Throwable t) {
196       aLogger.error("EntityBatchingProducerNode caused an exception: " + t.getMessage());
197     }
198   };
199
200   private class BatchLocation {
201     int nrEntities;
202     int firstEntity;
203
204     public BatchLocation(int aFirstEntity, int aNrEntities) {
205       firstEntity = aFirstEntity;
206       nrEntities = aNrEntities;
207     }
208   }
209 }
210