Revision 1740 org.gvsig.raster.georeferencing/trunk/org.gvsig.raster.georeferencing/org.gvsig.raster.georeferencing.lib/org.gvsig.raster.georeferencing.lib.impl/src/main/java/org/gvsig/raster/georeferencing/lib/impl/GeoreferencingProcess.java

View differences:

GeoreferencingProcess.java
41 41
package org.gvsig.raster.georeferencing.lib.impl;
42 42

  
43 43
import java.awt.geom.AffineTransform;
44
import java.io.IOException;
44
import java.util.HashMap;
45 45

  
46
import javax.swing.SwingUtilities;
47

  
48
import org.gvsig.fmap.dal.coverage.RasterLocator;
49
import org.gvsig.fmap.dal.coverage.RasterManager;
46 50
import org.gvsig.fmap.dal.coverage.dataset.Buffer;
51
import org.gvsig.fmap.dal.coverage.datastruct.Extent;
47 52
import org.gvsig.fmap.dal.coverage.datastruct.GeoPointList;
48
import org.gvsig.fmap.dal.coverage.datastruct.GridExtent;
49
import org.gvsig.fmap.dal.coverage.exception.NotSupportedExtensionException;
50
import org.gvsig.fmap.dal.coverage.exception.OutOfGridException;
51
import org.gvsig.fmap.dal.coverage.exception.RasterBufferInvalidAccessException;
52
import org.gvsig.fmap.dal.coverage.exception.RasterBufferInvalidException;
53
import org.gvsig.fmap.dal.coverage.datastruct.NoData;
54
import org.gvsig.fmap.dal.coverage.datastruct.Params;
55
import org.gvsig.fmap.dal.coverage.exception.InvalidSetViewException;
56
import org.gvsig.fmap.dal.coverage.exception.ProcessInterruptedException;
53 57
import org.gvsig.fmap.dal.coverage.exception.RasterDriverException;
54
import org.gvsig.fmap.dal.coverage.grid.Grid;
58
import org.gvsig.fmap.dal.coverage.store.DataServerWriter;
55 59
import org.gvsig.fmap.dal.coverage.store.RasterDataStore;
60
import org.gvsig.fmap.dal.coverage.store.RasterQuery;
61
import org.gvsig.fmap.dal.coverage.store.RasterWriter;
56 62
import org.gvsig.i18n.Messages;
57
import org.gvsig.raster.impl.buffer.RasterBuffer;
58 63
import org.gvsig.raster.impl.grid.GridInterpolated;
59
import org.gvsig.raster.impl.process.RasterTask;
60
import org.gvsig.raster.impl.process.RasterTaskQueue;
61 64
import org.gvsig.raster.tools.algorithm.base.RasterBaseAlgorithmLibrary;
62 65
import org.gvsig.raster.tools.algorithm.base.process.IProcessActions;
66
import org.gvsig.raster.tools.algorithm.base.process.ProcessException;
63 67
import org.gvsig.raster.tools.algorithm.base.process.RasterProcess;
68
import org.gvsig.raster.tools.algorithm.base.util.Interpolation;
64 69

  
65 70
/**
66
 *  Clase que representa una proceso de georreferenciacion de un raster.
67
 *  
68
 *  @author Alejandro Mu?oz Sanchez (alejandro.munoz@uclm.es)
69
 * 	@version 10/2/2008
71
 *  Resamples a image with the georeferencing parameters
72
 *  @author Nacho Brodin (nachobrodin@gmail.com)
70 73
 **/
71 74
public class GeoreferencingProcess extends RasterProcess implements IProcessActions {
72
	public static String             STORE              = "store";
75
	public static String             RASTER_STORE       = "RasterStore";
73 76
	public static String             GCPS               = "gcps";
74 77
	public static String             ORDER              = "Order";
75 78
	public static String             TIME               = "Time";
76 79
	public static String             RESULT             = "RESULT";
77
	public static String             FILENAME           = "filename";
80
	public static String             FILENAME           = "FileName";
78 81
	public static String             METHOD             = "method";
79 82
	public static String             XCELLSIZE          = "xCellSize";
80 83
	public static String             YCELLSIZE          = "yCellSize";
84
	public static String             INTERPOLATION      = "Interpolation";
81 85
	    
82 86
	//Capa a georreferenciar
83 87
	private RasterDataStore          store  			= null;
84 88
	
85
	//Grid resultante de georreferenciacion
86
	private Grid                     imageGrid          = null;
87
	
88 89
	//Fichero de salida
89 90
	private String                   filename           = null;
90 91
	
91
	
92 92
	// Lista puntos de control
93 93
	private GeoPointList             gcps               = null;
94 94
	
95
	//Extend de imagen corregida
96
	GridExtent                       newExtend          = null;
97
	
98 95
	// Metodo de resampleado utilizado
99 96
	private int                      rMethod            = 0;
100 97
	
101 98
	//Indicador de progreso
102 99
	private int                      percent            = 0;
103 100
	
104
	// Grid resultado
105
	private Grid                     gridResult         = null;
106
	
107
	WriterBufferServer               writerBufferServer = null;
108

  
109 101
	private int                      orden              = 0;
110 102
	
111 103
	private int[]                    bands              = null;
......
115 107
	//Tama?o de celda en Y si es pasada por el usuario
116 108
	private double                   yCellSize           = 0;
117 109
	
110
	private final DataServerWriter   writerBufferServer  = null;
111
	private long                     milis               = 0;
112
	
118 113
	public static void registerParameters() {
114
		RASTER_STORE = RasterBaseAlgorithmLibrary.registerInputParameter(RASTER_STORE, RasterDataStore.class);
115
		INTERPOLATION = RasterBaseAlgorithmLibrary.registerInputParameter(INTERPOLATION, Integer.class); 
119 116
		GCPS = RasterBaseAlgorithmLibrary.registerInputParameter(GCPS, GeoPointList.class);
120 117
		ORDER = RasterBaseAlgorithmLibrary.registerInputParameter(ORDER, Integer.class);
121 118
		TIME = RasterBaseAlgorithmLibrary.registerOutputParameter(TIME, Long.class);
......
127 124
	* <LI>method: metodo de resampleo </LI>
128 125
	*/
129 126
	public void init() {
130
		store = getParam(STORE) != null ? (RasterDataStore)getParam(STORE) : null;
127
		store = getParam(RASTER_STORE) != null ? (RasterDataStore)getParam(RASTER_STORE) : null;
131 128
		gcps = getParam(GCPS) != null ? (GeoPointList) getParam(GCPS) : null;
132 129
		filename = (String)getParam(FILENAME);
133 130
		rMethod = (int)getIntParam(METHOD);
......
138 135
		
139 136
		for(int i = 0; i < store.getBandCount(); i++)
140 137
			bands[i]= i;
141
		
142
		// Inicializacion del grid correspondiente a la imagen a corregir
143
		RasterDataStore dsetCopy = null; 
144
		dsetCopy = store.cloneDataStore();
145
		BufferFactory bufferFactory = new BufferFactory(dsetCopy);
146
		bufferFactory.setReadOnly(true);	
147
		try {
148
				imageGrid = new Grid(bufferFactory);	
149
		}catch (RasterBufferInvalidException e) {
150
			e.printStackTrace();			
151
		}
152 138
	}
153 139
	
154 140

  
155
	public void process() {
156
		RasterTask task = RasterTaskQueue.get(Thread.currentThread().toString());
141
	public void process() throws ProcessInterruptedException, ProcessException {
142
		long t1 = new java.util.Date().getTime();
157 143
		
144
		RasterQuery query = RasterLocator.getManager().createQuery();
145
		query.setAllDrawableBands();
146
		query.setAreaOfInterest();
147
		query.setReadOnly(true);
148
		Buffer bufInput;
149
		try {
150
			bufInput = store.query(query);
151
		} catch (RasterDriverException e1) {
152
			throw new ProcessException("Error getting the input buffer", e1);
153
		} catch (InvalidSetViewException e1) {
154
			throw new ProcessException("Error getting the input buffer", e1);
155
		}
156
		
158 157
		GeoTransformProcess transform = new GeoTransformProcess();
159 158
		transform.setActions(this);
160 159
		transform.addParam(GCPS, gcps);
161 160
		transform.addParam(ORDER, new Integer(orden));
162
		transform.run();		
161
		transform.execute();		
163 162
		
164 163
		// Obtenida la transformacion la aplicamos a los puntos extremos de la imagen
165 164
		double p1[] = transform.getCoordMap(0, 0);		
166
		double p2[] = transform.getCoordMap(rasterSE.getPxWidth(), 0);		
167
		double p3[] = transform.getCoordMap(0, rasterSE.getPxHeight());
168
		double p4[] = transform.getCoordMap(rasterSE.getPxWidth(), rasterSE.getPxHeight());	
165
		double p2[] = transform.getCoordMap(store.getWidth(), 0);		
166
		double p3[] = transform.getCoordMap(0, store.getHeight());
167
		double p4[] = transform.getCoordMap(store.getWidth(), store.getHeight());	
169 168
				
170 169
		double xmin = Math.min(p1[0], p3[0]);
171 170
		double ymin = Math.min(p3[1], p4[1]);
172 171
		double xmax = Math.max(p2[0], p4[0]);	
173 172
		double ymax = Math.max(p1[1], p2[1]);
174 173
		
175
		if(xCellSize <= 1)
176
			xCellSize = (xmax - xmin) / (double)rasterSE.getPxWidth();
177
		if(yCellSize <= 1)
178
			yCellSize = (ymax - ymin) / (double)rasterSE.getPxHeight();
174
		Extent bbox = store.getExtent();
175
		Extent newBbox = RasterLocator.getManager().getDataStructFactory().createExtent(xmin, ymax, xmax, ymin);
176
		int w = 0;
177
		int h = 0;
178
		if(xCellSize >= 0 && yCellSize >= 0) {
179
			w = (int)(bbox.width() * xCellSize);
180
			h = (int)(bbox.height() * yCellSize);
181
		} else {
182
			double[] size = getSize(bbox, newBbox);
183
			w = (int)size[0];
184
			h = (int)size[1];
185
			xCellSize = yCellSize = size[2];
186
		}
179 187
			
180
		newExtend= new GridExtent(xmin, ymin, xmax, ymax, xCellSize);
181
		int datatype= rasterSE.getBufferFactory().getRasterBuf().getDataType();
188
		int dataType = store.getDataType()[0];
182 189
		
183
		try {
184
			gridResult = new Grid(newExtend, newExtend, datatype, bands);
185
		} catch (RasterBufferInvalidException e) {
186
			RasterToolsUtil.messageBoxError("error_grid", this, e);
187
		}
190
		Buffer bufResult = RasterLocator.getManager().createBuffer(
191
				dataType, 
192
				w, 
193
				h, 
194
				store.getBandCount(), 
195
				true);
188 196
		
189
		double minPointX = gridResult.getGridExtent().getMin().getX();
190
		double maxPointY = gridResult.getGridExtent().getMax().getY();
191
		double cellsize = gridResult.getCellSize();
192
	
197
		NoData nd = RasterLocator.getManager().getDataStructFactory().createDefaultNoData(
198
				store.getBandCount(), dataType);
193 199
		
194
		GridInterpolated gridInterpolated=null;
195
		gridInterpolated = new GridInterpolated((RasterBuffer)imageGrid.getRasterBuf(),imageGrid.getGridExtent(),imageGrid.getGridExtent(),bands);
196
		
197
		// SE ESTABLECE EL METODO DE INTERPOLACION (por defecto vecino mas proximo)
198
		if(rMethod == GridInterpolated.INTERPOLATION_BicubicSpline)
199
			gridInterpolated.setInterpolationMethod(GridInterpolated.INTERPOLATION_BicubicSpline);
200
		else if(rMethod == GridInterpolated.INTERPOLATION_Bilinear)
201
			gridInterpolated.setInterpolationMethod(GridInterpolated.INTERPOLATION_Bilinear);
202
		else
203
			gridInterpolated.setInterpolationMethod(GridInterpolated.INTERPOLATION_NearestNeighbour);
204
		
200
		Interpolation interpolation = new Interpolation(bufInput);
201

  
205 202
		double coord[] = null;
206
		try {
207
			if(datatype == Buffer.TYPE_BYTE) {
208
				byte values[] = new byte[bands.length];
209
				int progress = 0;
210
				// OPTIMIZACION. Se esta recorriendo secuencialmente cada banda.
211
				for(int band = 0; band < bands.length; band++) {
212
					gridResult.setBandToOperate(band);
213
					gridInterpolated.setBandToOperate(band);
214
					for(int row = 0; row < gridResult.getLayerNY(); row++) {
215
						progress++;
216
						for(int col = 0; col < gridResult.getLayerNX(); col++) {
217
							coord = transform.getCoordPixel(col * cellsize+minPointX, maxPointY - row * cellsize);	
218
							values[band] = (byte)gridInterpolated._getValueAt(coord[0], coord[1]);
219
							gridResult.setCellValue(col,row,(byte)values[band]);
220
						}
221
						percent=(int)(progress * 100 / (gridResult.getLayerNY() * bands.length));
222
						if(task.getEvent() != null)
223
							task.manageEvent(task.getEvent());
224
					}	
225
				}	
203
		double values[] = new double[bands.length];
204
		int progress = 0;
205
		for(int row = 0; row < bufResult.getHeight(); row++) {
206
			for(int col = 0; col < bufResult.getWidth(); col++) {
207
				coord = transform.getCoordPixel(col * xCellSize + xmin, ymax - row * yCellSize);
208
				if(coord[0] < 0)
209
					coord[0] = 0;
210
				if(coord[1] < 0)
211
					coord[1] = 0;
212
				if(coord[0] > bufInput.getWidth() - 1)
213
					coord[0] = bufInput.getWidth() - 1;
214
				if(coord[1] > bufInput.getHeight() - 1)
215
					coord[1] = bufInput.getHeight() - 1;
216
				
217
				for (int iBand = 0; iBand < store.getBandCount(); iBand++) {
218
					
219
					
220
					if(rMethod == GridInterpolated.INTERPOLATION_Bilinear)
221
						values[iBand] = interpolation.getBilinearValue(coord[0], coord[1], iBand);
222
					if(rMethod == GridInterpolated.INTERPOLATION_InverseDistance)
223
						values[iBand] = interpolation.getInverseDistance(coord[0], coord[1], iBand);
224
					else
225
						values[iBand] = interpolation.getBilinearValue(coord[0], coord[1], iBand);
226
					
227
						
228
					if(dataType == Buffer.TYPE_BYTE) 
229
						bufResult.setElem(row, col, iBand, (byte)values[iBand]);
230
					else if(dataType == Buffer.TYPE_DOUBLE)
231
						bufResult.setElem(row, col, iBand, (double)values[iBand]);
232
					else if(dataType == Buffer.TYPE_FLOAT)
233
						bufResult.setElem(row, col, iBand, (float)values[iBand]);
234
					else if(dataType == Buffer.TYPE_SHORT)
235
						bufResult.setElem(row, col, iBand, (short)values[iBand]);
236
					else if(dataType == Buffer.TYPE_INT)
237
						bufResult.setElem(row, col, iBand, (int)values[iBand]);
238
				}
226 239
			}
240
			percent = (int)(progress * 100 / (bufResult.getHeight() * bands.length));
241
		}
227 242

  
228
			if(datatype == Buffer.TYPE_SHORT) {
229
				short values[] = new short[bands.length];
230
				int progress = 0;
231
				// OPTIMIZACION. Se esta recorriendo secuencialmente cada banda.
232
				for(int band = 0; band < bands.length; band++) {
233
					gridResult.setBandToOperate(band);
234
					gridInterpolated.setBandToOperate(band);
235
					for(int row = 0; row < gridResult.getLayerNY(); row++) {
236
						progress++;
237
						for(int col = 0; col < gridResult.getLayerNX(); col++) {
238
							coord=transform.getCoordPixel(col * cellsize+minPointX, maxPointY - row * cellsize);	
239
							values[band] = (short)gridInterpolated._getValueAt(coord[0], coord[1]);
240
							gridResult.setCellValue(col, row, (short)values[band]);
241
						}
242
						percent=(int)(progress * 100 / (gridResult.getLayerNY() * bands.length));
243
						if(task.getEvent() != null)
244
							task.manageEvent(task.getEvent());
245
					}	
246
				}	
243
		export(filename, bufResult, xCellSize, xmin, ymin);
244
		
245
		long t2 = new java.util.Date().getTime();
246
		milis = t2 - t1;
247
		
248
		SwingUtilities.invokeLater(new Runnable() {
249
			public void run() {
250
				if (externalActions != null) {
251
					externalActions.end(getResult());
252
				}
247 253
			}
248
			
249
			if(datatype == Buffer.TYPE_INT) {
250
				int values[] = new int[bands.length];
251
				int progress = 0;
252
				// OPTIMIZACION. Se esta recorriendo secuencialmente cada banda.
253
				for(int band = 0; band < bands.length; band++) {
254
					gridResult.setBandToOperate(band);
255
					gridInterpolated.setBandToOperate(band);
256
					for(int row = 0; row < gridResult.getLayerNY(); row++){
257
						progress++;
258
						for(int col = 0; col < gridResult.getLayerNX(); col++) {
259
							coord = transform.getCoordPixel(col * cellsize + minPointX, maxPointY - row * cellsize);	
260
							values[band] = (int)gridInterpolated._getValueAt(coord[0], coord[1]);
261
							gridResult.setCellValue(col, row, (int)values[band]);
262
						}
263
						percent=(int)( progress*100/(gridResult.getLayerNY()*bands.length));
264
						if(task.getEvent() != null)
265
							task.manageEvent(task.getEvent());
266
					}	
267
				}	
268
			}
269
			
270
			if(datatype == Buffer.TYPE_FLOAT) {	
271
				float values[] = new float[bands.length];
272
				int progress = 0;
273
				// OPTIMIZACION. Se esta recorriendo secuencialmente cada banda.
274
				for(int band = 0; band < bands.length; band++) {
275
					gridResult.setBandToOperate(band);
276
					gridInterpolated.setBandToOperate(band);
277
					for(int row = 0; row < gridResult.getLayerNY(); row++) {
278
						progress++;
279
						for(int col = 0; col < gridResult.getLayerNX(); col++) {
280
							coord = transform.getCoordPixel(col * cellsize + minPointX, maxPointY - row * cellsize);	
281
							values[band] = (float)gridInterpolated._getValueAt(coord[0], coord[1]);
282
							gridResult.setCellValue(col, row, (float)values[band]);
283
						}
284
						percent=(int)(progress * 100 / (gridResult.getLayerNY() * bands.length));
285
						if(task.getEvent() != null)
286
							task.manageEvent(task.getEvent());
287
					}	
288
				}	
289
			}
290
			
291
			if(datatype == Buffer.TYPE_DOUBLE) {
292
				double values[] = new double[bands.length];
293
				int progress = 0;
294
				// OPTIMIZACION. Se esta recorriendo secuencialmente cada banda.
295
				for(int band = 0; band < bands.length; band++) {
296
					gridResult.setBandToOperate(band);
297
					gridInterpolated.setBandToOperate(band);
298
					for(int row = 0; row < gridResult.getLayerNY(); row++) {
299
						progress++;
300
						for(int col = 0; col < gridResult.getLayerNX(); col++) {
301
							coord = transform.getCoordPixel(col * cellsize + minPointX, maxPointY - row * cellsize);	
302
							values[band] = (double)gridInterpolated._getValueAt(coord[0], coord[1]);
303
							gridResult.setCellValue(col, row, (double)values[band]);
304
						}
305
						percent=(int)( progress * 100 / (gridResult.getLayerNY() * bands.length));
306
						if(task.getEvent() != null)
307
							task.manageEvent(task.getEvent());
308
					}	
309
				}	
310
			}
311
			
312
		} catch (OutOfGridException e) {
313
			e.printStackTrace();
314
		} catch (RasterBufferInvalidAccessException e) {
315
			e.printStackTrace();
316
		} catch (RasterBufferInvalidException e) {
317
			e.printStackTrace();
318
		}
254
		});
319 255
		
320
		generateLayer();
321 256
		if(externalActions!=null)
322 257
			externalActions.end(filename);
323 258
	}
324

  
325

  
326
	private void generateLayer() {	
327 259
	
328
		GeoRasterWriter grw = null;
329
		IBuffer buffer= gridResult.getRasterBuf();
330
			writerBufferServer = new WriterBufferServer(buffer);
331
		AffineTransform aTransform = new AffineTransform(newExtend.getCellSize(), 0.0, 0.0, -newExtend.getCellSize(), newExtend.getMin().getX(), newExtend.getMax().getY());
332
		int endIndex = filename.lastIndexOf(".");
333
		if (endIndex < 0)
334
			endIndex = filename.length();
335
		try {
336
			grw = GeoRasterWriter.getWriter(writerBufferServer, filename,gridResult.getRasterBuf().getBandCount(),aTransform, gridResult.getRasterBuf().getWidth(),gridResult.getRasterBuf().getHeight(), gridResult.getRasterBuf().getDataType(), GeoRasterWriter.getWriter(filename).getParams(),null);
337
			grw.dataWrite();
338
			grw.setWkt(rasterSE.getWktProjection());
339
			grw.writeClose();
340
		} catch (NotSupportedExtensionException e1) {
341
			RasterToolsUtil.messageBoxError(PluginServices.getText(this, "error_writer_notsupportedextension"), this, e1);
342
		} catch (RasterDriverException e1) {
343
			RasterToolsUtil.messageBoxError(PluginServices.getText(this, "error_writer"), this, e1);	
344
		} catch (IOException e) {
345
			RasterToolsUtil.messageBoxError("error_salvando_rmf", this, e);
346
		} catch (InterruptedException e) {
347
			Thread.currentThread().interrupt();
348
		}
260
	/**
261
	 * Gets the size of the new image
262
	 * @param bbox
263
	 * @param newBbox
264
	 * @return
265
	 */
266
	private double[] getSize(Extent bbox, Extent newBbox) {
267
		double sumSideOldBBox = bbox.width() + bbox.height();
268
		double sumSideNewBBox = newBbox.width() + newBbox.height();
269
		double d1x = (bbox.width() * 100) / sumSideOldBBox; 
270
		double d1y = (bbox.height() * 100) / sumSideOldBBox;
271
		double d2x = (newBbox.width() * 100) / sumSideNewBBox;
272
		double d2y = (newBbox.height() * 100) / sumSideNewBBox;
273
		double p2y = (store.getHeight() * d2y) / d1y;
274
		double p2x = (store.getWidth() * d2x) / d1x;
275
		double newCellSize = newBbox.width() / p2x;
276
		return new double[]{Math.round(p2x), Math.round(p2y), newCellSize};
349 277
	}
350
		
278
	
279
	public Object getResult() {
280
		HashMap<String, Object> map = new HashMap<String, Object>();
281
		map.put(FILENAME, filename);
282
		map.put(TIME, new Long(milis));
283
		return map;
284
	}
351 285

  
352
	/*
353
	 * (non-Javadoc)
354
	 * @see org.gvsig.gui.beans.incrementabletask.IIncrementable#getTitle()
355
	 */
286
	public boolean export(final String sFilename, Buffer buf, double cellsize, double minX, double minY) {
287

  
288
        try {
289
            RasterManager manager = RasterLocator.getManager();
290
            final DataServerWriter writerBufferServer =
291
                manager.createDataServerWriter();
292
            writerBufferServer.setBuffer(buf, -1);
293
            final Params params = manager.createWriterParams(sFilename);
294
            final AffineTransform affineTransform =
295
                new AffineTransform(cellsize, 0, 0,
296
                    -cellsize, minX, minY);
297

  
298
            final RasterWriter writer =
299
                manager.createWriter(writerBufferServer, sFilename,
300
                    buf.getBandCount(), affineTransform, buf.getWidth(),
301
                    buf.getHeight(), buf.getDataType(), params, null);
302
            writer.dataWrite();
303
            writer.writeClose();
304

  
305
        } catch (final Exception e) {
306
        	e.printStackTrace();
307
            return false;
308
        }
309

  
310
        return true;
311

  
312
    }
313

  
356 314
	public String getTitle() {
357 315
		return Messages.getText("georreferenciacion_process");
358 316
	}
359 317
	
360
	/*
361
	 * (non-Javadoc)
362
	 * @see org.gvsig.gui.beans.incrementabletask.IIncrementable#getLabel()
363
	 */
364 318
	public int getPercent() {
365 319
		if(writerBufferServer == null)
366 320
			return percent;
367 321
		else
368 322
			return writerBufferServer.getPercent();
369 323
	}
370

  
371 324
	
372
	/*
373
	 * (non-Javadoc)
374
	 * @see org.gvsig.gui.beans.incrementabletask.IIncrementable#getLabel()
375
	 */
376 325
	public String getLog() {
377 326
		return Messages.getText("georreferencing_log_message");
378 327
	}
379

  
380 328
	
381 329
	public void interrupted() {
382
		// TODO Auto-generated method stub	
383 330
	}
384 331

  
385 332
	public void end(Object param) {	
386 333
	}
387

  
388 334
}

Also available in: Unified diff