- producer links are moved to an "advanced" page, not intended for normal
[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 import mir.entity.adapter.*;
37 import mir.entity.*;
38 import mir.storage.*;
39 import mir.util.*;
40
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;
54
55   public EntityBatchingProducerNode(
56         String aBatchDataKey,
57         String aBatchInfoKey,
58         EntityAdapterModel aModel,
59         String aDefinition,
60         String aWhereClause,
61         String anOrderByClause,
62         String anrEntitiesPerBatchExpression,
63         String aminNrEntitiesInFirstBatchExpression,
64         String anrEntitiesToSkipExpression,
65         String aNrBatchesToProcessExpression,
66         ProducerNode aBatchSubNode,
67         ProducerNode aBatchListSubNode) {
68
69     batchSubNode = aBatchSubNode;
70     batchListSubNode = aBatchListSubNode;
71
72     batchDataKey = aBatchDataKey;
73     batchInfoKey = aBatchInfoKey;
74     model = aModel;
75     definition = aDefinition;
76     whereClause = aWhereClause;
77     orderByClause = anOrderByClause;
78     nrEntitiesToSkipExpression = anrEntitiesToSkipExpression;
79     nrEntitiesPerBatchExpression = anrEntitiesPerBatchExpression;
80     minNrEntitiesInFirstBatchExpression = aminNrEntitiesInFirstBatchExpression;
81     nrBatchesToProcessExpression = aNrBatchesToProcessExpression;
82   }
83
84   protected boolean isAborted(Map aValueMap) {
85     Object producerValue = aValueMap.get(NodedProducer.PRODUCER_KEY);
86     return (
87        (producerValue instanceof NodedProducer) &&
88       ((NodedProducer) producerValue).getIsAborted());
89   }
90
91   public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
92     Iterator browser;
93     int nrEntities;
94     int nrBatchesAfterFirst;
95     int nrEntitiesInFirstBatch;
96     int nrBatchesToProcess;
97     List batchesData;
98     int i;
99     int position;
100     Map batchData;
101     String expandedWhereClause;
102     String expandedOrderByClause;
103
104     List batchLocations;
105     BatchLocation location;
106
107     int nrEntitiesToSkip;
108     int nrEntitiesPerBatch;
109     int minNrEntitiesInFirstBatch;
110
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
113
114
115     try {
116       nrBatchesToProcess = ParameterExpander.evaluateIntegerExpressionWithDefault( aValueMap, nrBatchesToProcessExpression, -1 );
117
118       expandedWhereClause = ParameterExpander.expandExpression( aValueMap, whereClause );
119       expandedOrderByClause = ParameterExpander.expandExpression( aValueMap, orderByClause );
120
121       nrEntitiesToSkip = ParameterExpander.evaluateIntegerExpression( aValueMap, nrEntitiesToSkipExpression);
122       nrEntitiesPerBatch = ParameterExpander.evaluateIntegerExpression( aValueMap, nrEntitiesPerBatchExpression);
123       minNrEntitiesInFirstBatch = ParameterExpander.evaluateIntegerExpression( aValueMap, minNrEntitiesInFirstBatchExpression);
124
125       batchesData = new Vector();
126       batchLocations = new Vector();
127
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;
133
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);
140
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);
148       }
149
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()));
156
157       if (batchListSubNode!=null && (!isAborted(aValueMap))) {
158         batchListSubNode.produce(aValueMap, aVerb, aLogger);
159       }
160
161       if (nrBatchesToProcess<0 || nrBatchesToProcess>nrBatchesAfterFirst+1) {
162         nrBatchesToProcess = nrBatchesAfterFirst+1;
163       }
164
165       if (batchSubNode!=null) {
166         for (i=0; i<nrBatchesToProcess && !isAborted(aValueMap); i++) {
167           location = (BatchLocation) batchLocations.get(i);
168
169           batchData.put("current", batchesData.get(i));
170           if (i>0)
171             batchData.put("previous", batchesData.get(i-1));
172           else
173             batchData.put("previous", null);
174
175           if (i<batchesData.size()-1)
176             batchData.put("next", batchesData.get(i+1));
177           else
178             batchData.put("next", null);
179
180           Iterator j = new EntityIteratorAdapter(expandedWhereClause, expandedOrderByClause,
181                     location.nrEntities, model, definition, location.nrEntities, location.firstEntity);
182           List entities = new Vector();
183
184           while (j.hasNext())
185             entities.add(0, j.next());
186
187           ParameterExpander.setValueForKey(aValueMap, batchDataKey, entities );
188
189           batchSubNode.produce(aValueMap, aVerb, aLogger);
190         }
191       }
192     }
193     catch (Throwable t) {
194       throw new ProducerFailure(t.getMessage(), t);
195     }
196   };
197
198   private class BatchLocation {
199     int nrEntities;
200     int firstEntity;
201
202     public BatchLocation(int aFirstEntity, int aNrEntities) {
203       firstEntity = aFirstEntity;
204       nrEntities = aNrEntities;
205     }
206   }
207 }
208