2 * Copyright (C) 2001, 2002 The Mir-coders group
4 * This file is part of Mir.
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.
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.
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
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.
36 import mir.entity.adapter.*;
41 public class EntityBatchingProducerNode implements ProducerNode {
42 private String batchInfoKey;
43 private String batchDataKey;
44 private EntityAdapterModel model;
45 private String definition;
46 private String whereClause;
47 private String orderByClause;
48 private String nrEntitiesToSkipExpression;
49 private String nrEntitiesPerBatchExpression;
50 private String minNrEntitiesInFirstBatchExpression;
51 private String nrBatchesToProcessExpression;
52 private ProducerNode batchSubNode;
53 private ProducerNode batchListSubNode;
55 public EntityBatchingProducerNode(
58 EntityAdapterModel aModel,
61 String anOrderByClause,
62 String anrEntitiesPerBatchExpression,
63 String aminNrEntitiesInFirstBatchExpression,
64 String anrEntitiesToSkipExpression,
65 String aNrBatchesToProcessExpression,
66 ProducerNode aBatchSubNode,
67 ProducerNode aBatchListSubNode) {
69 batchSubNode = aBatchSubNode;
70 batchListSubNode = aBatchListSubNode;
72 batchDataKey = aBatchDataKey;
73 batchInfoKey = aBatchInfoKey;
75 definition = aDefinition;
76 whereClause = aWhereClause;
77 orderByClause = anOrderByClause;
78 nrEntitiesToSkipExpression = anrEntitiesToSkipExpression;
79 nrEntitiesPerBatchExpression = anrEntitiesPerBatchExpression;
80 minNrEntitiesInFirstBatchExpression = aminNrEntitiesInFirstBatchExpression;
81 nrBatchesToProcessExpression = aNrBatchesToProcessExpression;
84 protected boolean isAborted(Map aValueMap) {
85 Object producerValue = aValueMap.get(NodedProducer.PRODUCER_KEY);
87 (producerValue instanceof NodedProducer) &&
88 ((NodedProducer) producerValue).getIsAborted());
91 public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
94 int nrBatchesAfterFirst;
95 int nrEntitiesInFirstBatch;
96 int nrBatchesToProcess;
101 String expandedWhereClause;
102 String expandedOrderByClause;
105 BatchLocation location;
107 int nrEntitiesToSkip;
108 int nrEntitiesPerBatch;
109 int minNrEntitiesInFirstBatch;
111 // ML: The order by clause should lead to a result set in _reverse order_: the first row will be
112 // the last entity presented on the last page
116 nrBatchesToProcess = ParameterExpander.evaluateIntegerExpressionWithDefault( aValueMap, nrBatchesToProcessExpression, -1 );
118 expandedWhereClause = ParameterExpander.expandExpression( aValueMap, whereClause );
119 expandedOrderByClause = ParameterExpander.expandExpression( aValueMap, orderByClause );
121 nrEntitiesToSkip = ParameterExpander.evaluateIntegerExpression( aValueMap, nrEntitiesToSkipExpression);
122 nrEntitiesPerBatch = ParameterExpander.evaluateIntegerExpression( aValueMap, nrEntitiesPerBatchExpression);
123 minNrEntitiesInFirstBatch = ParameterExpander.evaluateIntegerExpression( aValueMap, minNrEntitiesInFirstBatchExpression);
125 batchesData = new Vector();
126 batchLocations = new Vector();
128 nrEntities = model.getMappingForName(definition).getStorage().getSize(expandedWhereClause)-nrEntitiesToSkip;
129 nrEntitiesInFirstBatch = nrEntities % nrEntitiesPerBatch;
130 while (nrEntitiesInFirstBatch<minNrEntitiesInFirstBatch && nrEntities-nrEntitiesInFirstBatch>=nrEntitiesPerBatch)
131 nrEntitiesInFirstBatch = nrEntitiesInFirstBatch + nrEntitiesPerBatch;
132 nrBatchesAfterFirst = (nrEntities-nrEntitiesInFirstBatch)/nrEntitiesPerBatch;
134 batchLocations.add(new BatchLocation(nrBatchesAfterFirst*nrEntitiesPerBatch, nrEntitiesInFirstBatch));
135 batchData = new HashMap();
136 batchData.put("identifier", "");
137 batchData.put("index", new Integer(nrBatchesAfterFirst+1));
138 batchData.put("size", new Integer(nrEntitiesInFirstBatch));
139 batchesData.add(batchData);
141 for (i=0; i<nrBatchesAfterFirst; i++) {
142 batchLocations.add(1, new BatchLocation(i*nrEntitiesPerBatch, nrEntitiesPerBatch));
143 batchData = new HashMap();
144 batchData.put("identifier", new Integer(i));
145 batchData.put("index", new Integer(i+1));
146 batchData.put("size", new Integer(nrEntitiesPerBatch));
147 batchesData.add(1, batchData);
150 batchData = new HashMap();
151 ParameterExpander.setValueForKey(aValueMap, batchInfoKey, batchData);
152 batchData.put("all", batchesData);
153 batchData.put("first", batchesData.get(0));
154 batchData.put("last", batchesData.get(batchesData.size()-1));
155 batchData.put("count", new Integer(batchesData.size()));
157 if (batchListSubNode!=null && (!isAborted(aValueMap))) {
158 batchListSubNode.produce(aValueMap, aVerb, aLogger);
161 if (nrBatchesToProcess<0 || nrBatchesToProcess>nrBatchesAfterFirst+1) {
162 nrBatchesToProcess = nrBatchesAfterFirst+1;
165 if (batchSubNode!=null) {
166 for (i=0; i<nrBatchesToProcess && !isAborted(aValueMap); i++) {
167 location = (BatchLocation) batchLocations.get(i);
169 batchData.put("current", batchesData.get(i));
171 batchData.put("previous", batchesData.get(i-1));
173 batchData.put("previous", null);
175 if (i<batchesData.size()-1)
176 batchData.put("next", batchesData.get(i+1));
178 batchData.put("next", null);
180 Iterator j = new EntityIteratorAdapter(expandedWhereClause, expandedOrderByClause,
181 location.nrEntities, model, definition, location.nrEntities, location.firstEntity);
182 List entities = new Vector();
185 entities.add(0, j.next());
187 ParameterExpander.setValueForKey(aValueMap, batchDataKey, entities );
189 batchSubNode.produce(aValueMap, aVerb, aLogger);
193 catch (Throwable t) {
194 throw new ProducerFailure(t.getMessage(), t);
198 private class BatchLocation {
202 public BatchLocation(int aFirstEntity, int aNrEntities) {
203 firstEntity = aFirstEntity;
204 nrEntities = aNrEntities;