2 * Copyright (C) 2001-2006 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 * and distribute linked combinations including the two. You must obey the
23 * GNU General Public License in all respects for all of the code used other than
24 * the above mentioned libraries. If you modify this file, you may extend this
25 * exception to your version of the file, but you are not obligated to do so.
26 * If you do not wish to do so, delete this exception statement from your version.
30 import mir.entity.adapter.EntityAdapterModel;
31 import mir.entity.adapter.EntityIteratorAdapter;
32 import mir.util.ParameterExpander;
33 import mir.util.StringRoutines;
38 * This producer makes it possible to show articles in batches, like on archive pages.
39 * <emph> The order by clause should lead to a result set in <b>reverse order</b>:
40 * the first row will be the last entity in the last batch </emph>
43 public class EntityBatchingProducerNode implements ProducerNode {
44 private String batchInfoKey;
45 private String batchDataKey;
46 private EntityAdapterModel model;
47 private String mainTablePrefix;
48 private String extraTables;
49 private String definition;
50 private String whereClause;
51 private String orderByClause;
52 private String nrEntitiesToSkipExpression;
53 private String nrEntitiesPerBatchExpression;
54 private String minNrEntitiesInFirstBatchExpression;
55 private String nrBatchesToProcessExpression;
56 private ProducerNode batchSubNode;
57 private ProducerNode batchListSubNode;
59 public EntityBatchingProducerNode(
62 EntityAdapterModel aModel,
63 String aMainTablePrefix,
64 String someExtraTables,
67 String anOrderByClause,
68 String anrEntitiesPerBatchExpression,
69 String aminNrEntitiesInFirstBatchExpression,
70 String anrEntitiesToSkipExpression,
71 String aNrBatchesToProcessExpression,
72 ProducerNode aBatchSubNode,
73 ProducerNode aBatchListSubNode) {
75 batchSubNode = aBatchSubNode;
76 batchListSubNode = aBatchListSubNode;
78 batchDataKey = aBatchDataKey;
79 batchInfoKey = aBatchInfoKey;
81 mainTablePrefix = aMainTablePrefix;
82 extraTables = someExtraTables;
83 definition = aDefinition;
84 whereClause = aWhereClause;
85 orderByClause = anOrderByClause;
86 nrEntitiesToSkipExpression = anrEntitiesToSkipExpression;
87 nrEntitiesPerBatchExpression = anrEntitiesPerBatchExpression;
88 minNrEntitiesInFirstBatchExpression = aminNrEntitiesInFirstBatchExpression;
89 nrBatchesToProcessExpression = aNrBatchesToProcessExpression;
92 protected boolean isAborted(Map aValueMap) {
93 Object producerValue = aValueMap.get(NodedProducer.PRODUCER_KEY);
95 (producerValue instanceof NodedProducer) &&
96 ((NodedProducer) producerValue).getIsAborted());
99 public void produce(ProductionContext aProducerContext) throws ProducerExc, ProducerFailure {
101 int nrBatchesAfterFirst;
102 int nrEntitiesInFirstBatch;
103 int nrBatchesToProcess;
107 String expandedWhereClause;
108 String expandedOrderByClause;
111 BatchLocation location;
113 int nrEntitiesToSkip;
114 int nrEntitiesPerBatch;
115 int minNrEntitiesInFirstBatch;
118 nrBatchesToProcess = ParameterExpander.evaluateIntegerExpressionWithDefault(aProducerContext.getValueSet(), nrBatchesToProcessExpression, -1);
120 expandedWhereClause = ParameterExpander.expandExpression( aProducerContext.getValueSet(), whereClause );
121 expandedOrderByClause = ParameterExpander.expandExpression( aProducerContext.getValueSet(), orderByClause );
123 nrEntitiesToSkip = ParameterExpander.evaluateIntegerExpression( aProducerContext.getValueSet(), nrEntitiesToSkipExpression);
124 nrEntitiesPerBatch = ParameterExpander.evaluateIntegerExpression( aProducerContext.getValueSet(), nrEntitiesPerBatchExpression);
125 minNrEntitiesInFirstBatch = ParameterExpander.evaluateIntegerExpression( aProducerContext.getValueSet(), minNrEntitiesInFirstBatchExpression);
126 List extraTableList = StringRoutines.splitString(ParameterExpander.expandExpression( aProducerContext.getValueSet(), extraTables).trim(), ",");
128 batchesData = new ArrayList();
129 batchLocations = new ArrayList();
131 nrEntities = model.getMappingForName(definition).getDatabase().getSize(
132 mainTablePrefix, extraTableList, expandedWhereClause)-nrEntitiesToSkip;
133 nrEntitiesInFirstBatch = nrEntities % nrEntitiesPerBatch;
134 while (nrEntitiesInFirstBatch<minNrEntitiesInFirstBatch && nrEntities-nrEntitiesInFirstBatch>=nrEntitiesPerBatch)
135 nrEntitiesInFirstBatch = nrEntitiesInFirstBatch + nrEntitiesPerBatch;
136 nrBatchesAfterFirst = (nrEntities-nrEntitiesInFirstBatch)/nrEntitiesPerBatch;
138 batchLocations.add(new BatchLocation(nrBatchesAfterFirst*nrEntitiesPerBatch, nrEntitiesInFirstBatch));
139 batchData = new HashMap();
140 batchData.put("identifier", "");
141 batchData.put("index", new Integer(nrBatchesAfterFirst+1));
142 batchData.put("size", new Integer(nrEntitiesInFirstBatch));
143 batchesData.add(batchData);
145 for (i=0; i<nrBatchesAfterFirst; i++) {
146 batchLocations.add(1, new BatchLocation(i*nrEntitiesPerBatch, nrEntitiesPerBatch));
147 batchData = new HashMap();
148 batchData.put("identifier", new Integer(i));
149 batchData.put("index", new Integer(i+1));
150 batchData.put("size", new Integer(nrEntitiesPerBatch));
151 batchesData.add(1, batchData);
154 batchData = new HashMap();
155 ParameterExpander.setValueForKey(aProducerContext.getValueSet(), batchInfoKey, batchData);
156 batchData.put("all", batchesData);
157 batchData.put("first", batchesData.get(0));
158 batchData.put("last", batchesData.get(batchesData.size()-1));
159 batchData.put("count", new Integer(batchesData.size()));
161 if (batchListSubNode!=null && (!isAborted(aProducerContext.getValueSet()))) {
162 batchListSubNode.produce(aProducerContext);
165 if (nrBatchesToProcess<0 || nrBatchesToProcess>nrBatchesAfterFirst+1) {
166 nrBatchesToProcess = nrBatchesAfterFirst+1;
169 if (batchSubNode!=null) {
170 for (i=0; i<nrBatchesToProcess && !isAborted(aProducerContext.getValueSet()); i++) {
171 location = (BatchLocation) batchLocations.get(i);
173 batchData.put("current", batchesData.get(i));
175 batchData.put("previous", batchesData.get(i-1));
177 batchData.put("previous", null);
179 if (i<batchesData.size()-1)
180 batchData.put("next", batchesData.get(i+1));
182 batchData.put("next", null);
184 Iterator j = new EntityIteratorAdapter(mainTablePrefix, extraTableList, expandedWhereClause, expandedOrderByClause,
185 location.nrEntities, model, definition, location.nrEntities, location.firstEntity);
186 List entities = new ArrayList();
189 entities.add(0, j.next());
191 ParameterExpander.setValueForKey(aProducerContext.getValueSet(), batchDataKey, entities );
193 batchSubNode.produce(aProducerContext);
197 catch (Throwable t) {
198 aProducerContext.getLogger().warn("EntityBatchingProducerNode caused an exception: " + t.getMessage());
202 private class BatchLocation {
206 public BatchLocation(int aFirstEntity, int aNrEntities) {
207 firstEntity = aFirstEntity;
208 nrEntities = aNrEntities;