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.
37 import mir.entity.adapter.*;
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;
57 public EntityBatchingProducerNode(
60 EntityAdapterModel aModel,
63 String anOrderByClause,
64 String anrEntitiesPerBatchExpression,
65 String aminNrEntitiesInFirstBatchExpression,
66 String anrEntitiesToSkipExpression,
67 String aNrBatchesToProcessExpression,
68 ProducerNode aBatchSubNode,
69 ProducerNode aBatchListSubNode) {
71 batchSubNode = aBatchSubNode;
72 batchListSubNode = aBatchListSubNode;
74 batchDataKey = aBatchDataKey;
75 batchInfoKey = aBatchInfoKey;
77 definition = aDefinition;
78 whereClause = aWhereClause;
79 orderByClause = anOrderByClause;
80 nrEntitiesToSkipExpression = anrEntitiesToSkipExpression;
81 nrEntitiesPerBatchExpression = anrEntitiesPerBatchExpression;
82 minNrEntitiesInFirstBatchExpression = aminNrEntitiesInFirstBatchExpression;
83 nrBatchesToProcessExpression = aNrBatchesToProcessExpression;
86 protected boolean isAborted(Map aValueMap) {
87 Object producerValue = aValueMap.get(NodedProducer.PRODUCER_KEY);
89 (producerValue instanceof NodedProducer) &&
90 ((NodedProducer) producerValue).getIsAborted());
93 public void produce(Map aValueMap, String aVerb, LoggerWrapper aLogger) throws ProducerFailure {
96 int nrBatchesAfterFirst;
97 int nrEntitiesInFirstBatch;
98 int nrBatchesToProcess;
103 String expandedWhereClause;
104 String expandedOrderByClause;
107 BatchLocation location;
109 int nrEntitiesToSkip;
110 int nrEntitiesPerBatch;
111 int minNrEntitiesInFirstBatch;
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
118 nrBatchesToProcess = ParameterExpander.evaluateIntegerExpressionWithDefault( aValueMap, nrBatchesToProcessExpression, -1 );
120 expandedWhereClause = ParameterExpander.expandExpression( aValueMap, whereClause );
121 expandedOrderByClause = ParameterExpander.expandExpression( aValueMap, orderByClause );
123 nrEntitiesToSkip = ParameterExpander.evaluateIntegerExpression( aValueMap, nrEntitiesToSkipExpression);
124 nrEntitiesPerBatch = ParameterExpander.evaluateIntegerExpression( aValueMap, nrEntitiesPerBatchExpression);
125 minNrEntitiesInFirstBatch = ParameterExpander.evaluateIntegerExpression( aValueMap, minNrEntitiesInFirstBatchExpression);
127 batchesData = new Vector();
128 batchLocations = new Vector();
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;
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);
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);
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()));
159 if (batchListSubNode!=null && (!isAborted(aValueMap))) {
160 batchListSubNode.produce(aValueMap, aVerb, aLogger);
163 if (nrBatchesToProcess<0 || nrBatchesToProcess>nrBatchesAfterFirst+1) {
164 nrBatchesToProcess = nrBatchesAfterFirst+1;
167 if (batchSubNode!=null) {
168 for (i=0; i<nrBatchesToProcess && !isAborted(aValueMap); i++) {
169 location = (BatchLocation) batchLocations.get(i);
171 batchData.put("current", batchesData.get(i));
173 batchData.put("previous", batchesData.get(i-1));
175 batchData.put("previous", null);
177 if (i<batchesData.size()-1)
178 batchData.put("next", batchesData.get(i+1));
180 batchData.put("next", null);
182 Iterator j = new EntityIteratorAdapter(expandedWhereClause, expandedOrderByClause,
183 location.nrEntities, model, definition, location.nrEntities, location.firstEntity);
184 List entities = new Vector();
187 entities.add(0, j.next());
189 ParameterExpander.setValueForKey(aValueMap, batchDataKey, entities );
191 batchSubNode.produce(aValueMap, aVerb, aLogger);
195 catch (Throwable t) {
196 aLogger.error("EntityBatchingProducerNode caused an exception: " + t.getMessage());
200 private class BatchLocation {
204 public BatchLocation(int aFirstEntity, int aNrEntities) {
205 firstEntity = aFirstEntity;
206 nrEntities = aNrEntities;