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 any library licensed under the Apache Software License,
22 * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23 * (or with modified versions of the above that use the same license as the above),
24 * and distribute linked combinations including the two. You must obey the
25 * GNU General Public License in all respects for all of the code used other than
26 * the above mentioned libraries. If you modify this file, you may extend this
27 * exception to your version of the file, but you are not obligated to do so.
28 * If you do not wish to do so, delete this exception statement from your version.
32 import mir.entity.adapter.EntityAdapterModel;
33 import mir.entity.adapter.EntityIteratorAdapter;
34 import mir.util.ParameterExpander;
35 import mir.util.StringRoutines;
40 * This producer makes it possible to show articles in batches, like on archive pages.
41 * <emph> The order by clause should lead to a result set in <b>reverse order</b>:
42 * the first row will be the last entity in the last batch </emph>
45 public class EntityBatchingProducerNode implements ProducerNode {
46 private String batchInfoKey;
47 private String batchDataKey;
48 private EntityAdapterModel model;
49 private String mainTablePrefix;
50 private String extraTables;
51 private String definition;
52 private String whereClause;
53 private String orderByClause;
54 private String nrEntitiesToSkipExpression;
55 private String nrEntitiesPerBatchExpression;
56 private String minNrEntitiesInFirstBatchExpression;
57 private String nrBatchesToProcessExpression;
58 private ProducerNode batchSubNode;
59 private ProducerNode batchListSubNode;
61 public EntityBatchingProducerNode(
64 EntityAdapterModel aModel,
65 String aMainTablePrefix,
66 String someExtraTables,
69 String anOrderByClause,
70 String anrEntitiesPerBatchExpression,
71 String aminNrEntitiesInFirstBatchExpression,
72 String anrEntitiesToSkipExpression,
73 String aNrBatchesToProcessExpression,
74 ProducerNode aBatchSubNode,
75 ProducerNode aBatchListSubNode) {
77 batchSubNode = aBatchSubNode;
78 batchListSubNode = aBatchListSubNode;
80 batchDataKey = aBatchDataKey;
81 batchInfoKey = aBatchInfoKey;
83 mainTablePrefix = aMainTablePrefix;
84 extraTables = someExtraTables;
85 definition = aDefinition;
86 whereClause = aWhereClause;
87 orderByClause = anOrderByClause;
88 nrEntitiesToSkipExpression = anrEntitiesToSkipExpression;
89 nrEntitiesPerBatchExpression = anrEntitiesPerBatchExpression;
90 minNrEntitiesInFirstBatchExpression = aminNrEntitiesInFirstBatchExpression;
91 nrBatchesToProcessExpression = aNrBatchesToProcessExpression;
94 protected boolean isAborted(Map aValueMap) {
95 Object producerValue = aValueMap.get(NodedProducer.PRODUCER_KEY);
97 (producerValue instanceof NodedProducer) &&
98 ((NodedProducer) producerValue).getIsAborted());
101 public void produce(ProductionContext aProducerContext) throws ProducerExc, ProducerFailure {
103 int nrBatchesAfterFirst;
104 int nrEntitiesInFirstBatch;
105 int nrBatchesToProcess;
109 String expandedWhereClause;
110 String expandedOrderByClause;
113 BatchLocation location;
115 int nrEntitiesToSkip;
116 int nrEntitiesPerBatch;
117 int minNrEntitiesInFirstBatch;
120 nrBatchesToProcess = ParameterExpander.evaluateIntegerExpressionWithDefault(aProducerContext.getValueSet(), nrBatchesToProcessExpression, -1);
122 expandedWhereClause = ParameterExpander.expandExpression( aProducerContext.getValueSet(), whereClause );
123 expandedOrderByClause = ParameterExpander.expandExpression( aProducerContext.getValueSet(), orderByClause );
125 nrEntitiesToSkip = ParameterExpander.evaluateIntegerExpression( aProducerContext.getValueSet(), nrEntitiesToSkipExpression);
126 nrEntitiesPerBatch = ParameterExpander.evaluateIntegerExpression( aProducerContext.getValueSet(), nrEntitiesPerBatchExpression);
127 minNrEntitiesInFirstBatch = ParameterExpander.evaluateIntegerExpression( aProducerContext.getValueSet(), minNrEntitiesInFirstBatchExpression);
128 List extraTableList = StringRoutines.splitString(ParameterExpander.expandExpression( aProducerContext.getValueSet(), extraTables).trim(), ",");
130 batchesData = new ArrayList();
131 batchLocations = new ArrayList();
133 nrEntities = model.getMappingForName(definition).getDatabase().getSize(
134 mainTablePrefix, extraTableList, expandedWhereClause)-nrEntitiesToSkip;
135 nrEntitiesInFirstBatch = nrEntities % nrEntitiesPerBatch;
136 while (nrEntitiesInFirstBatch<minNrEntitiesInFirstBatch && nrEntities-nrEntitiesInFirstBatch>=nrEntitiesPerBatch)
137 nrEntitiesInFirstBatch = nrEntitiesInFirstBatch + nrEntitiesPerBatch;
138 nrBatchesAfterFirst = (nrEntities-nrEntitiesInFirstBatch)/nrEntitiesPerBatch;
140 batchLocations.add(new BatchLocation(nrBatchesAfterFirst*nrEntitiesPerBatch, nrEntitiesInFirstBatch));
141 batchData = new HashMap();
142 batchData.put("identifier", "");
143 batchData.put("index", new Integer(nrBatchesAfterFirst+1));
144 batchData.put("size", new Integer(nrEntitiesInFirstBatch));
145 batchesData.add(batchData);
147 for (i=0; i<nrBatchesAfterFirst; i++) {
148 batchLocations.add(1, new BatchLocation(i*nrEntitiesPerBatch, nrEntitiesPerBatch));
149 batchData = new HashMap();
150 batchData.put("identifier", new Integer(i));
151 batchData.put("index", new Integer(i+1));
152 batchData.put("size", new Integer(nrEntitiesPerBatch));
153 batchesData.add(1, batchData);
156 batchData = new HashMap();
157 ParameterExpander.setValueForKey(aProducerContext.getValueSet(), batchInfoKey, batchData);
158 batchData.put("all", batchesData);
159 batchData.put("first", batchesData.get(0));
160 batchData.put("last", batchesData.get(batchesData.size()-1));
161 batchData.put("count", new Integer(batchesData.size()));
163 if (batchListSubNode!=null && (!isAborted(aProducerContext.getValueSet()))) {
164 batchListSubNode.produce(aProducerContext);
167 if (nrBatchesToProcess<0 || nrBatchesToProcess>nrBatchesAfterFirst+1) {
168 nrBatchesToProcess = nrBatchesAfterFirst+1;
171 if (batchSubNode!=null) {
172 for (i=0; i<nrBatchesToProcess && !isAborted(aProducerContext.getValueSet()); i++) {
173 location = (BatchLocation) batchLocations.get(i);
175 batchData.put("current", batchesData.get(i));
177 batchData.put("previous", batchesData.get(i-1));
179 batchData.put("previous", null);
181 if (i<batchesData.size()-1)
182 batchData.put("next", batchesData.get(i+1));
184 batchData.put("next", null);
186 Iterator j = new EntityIteratorAdapter(mainTablePrefix, extraTableList, expandedWhereClause, expandedOrderByClause,
187 location.nrEntities, model, definition, location.nrEntities, location.firstEntity);
188 List entities = new ArrayList();
191 entities.add(0, j.next());
193 ParameterExpander.setValueForKey(aProducerContext.getValueSet(), batchDataKey, entities );
195 batchSubNode.produce(aProducerContext);
199 catch (Throwable t) {
200 aProducerContext.getLogger().warn("EntityBatchingProducerNode caused an exception: " + t.getMessage());
204 private class BatchLocation {
208 public BatchLocation(int aFirstEntity, int aNrEntities) {
209 firstEntity = aFirstEntity;
210 nrEntities = aNrEntities;