Revision 21731 branches/v2_0_0_prep/libraries/libFMap_geometries/src/org/gvsig/fmap/geom/GeometryManager.java

View differences:

GeometryManager.java
56 56
/**
57 57
 * This singleton provides a centralized access to gvSIG's Geometry Model.
58 58
 * Its responsibilities are:<br>
59
 * 
59
 *
60 60
 * <ul>
61 61
 * <li>Offering a set of convenient methods for registering and retrieving geometry types.
62
 * <li>Offering a set of convenient methods for registering and retrieving geometry operations associated 
62
 * <li>Offering a set of convenient methods for registering and retrieving geometry operations associated
63 63
 * to one or more geometry types.
64
 * <li><code>TODO:</code> Offering a set of convenient methods for registering and retrieving custom 
64
 * <li><code>TODO:</code> Offering a set of convenient methods for registering and retrieving custom
65 65
 * geometry factories.
66 66
 * <ul>
67
 *  
67
 *
68 68
 * @author jiyarza
69 69
 *
70 70
 */
71 71
public class GeometryManager {
72 72

  
73 73
	private static Logger logger = Logger.getLogger(GeometryManager.class);
74
	
74

  
75 75
	private static GeometryManager instance;
76 76

  
77
	/** This list holds the unique name of all registered geometry operations. 
77
	/** This list holds the unique name of all registered geometry operations.
78 78
	 * The index in which they are stored is also the operation code used to invoke each one of them */
79 79
	private List geometryOperations = new ArrayList();
80
		
81
	/** Common operations are registered here. Type specific operations are registered in the corresponding GeometryType instance */ 
80

  
81
	/** Common operations are registered here. Type specific operations are registered in the corresponding GeometryType instance */
82 82
	private List commonOperations = new ArrayList();
83
	
84
	/** Common operations are assigned an index greater or equal than this constant, so that it is easy and efficient for the manager 
83

  
84
	/** Common operations are assigned an index greater or equal than this constant, so that it is easy and efficient for the manager
85 85
	 * to decide whether to lookup in the common register or in the type specific register. */
86 86
	private static final int COMMON_OPS_OFFSET = 1000;
87
	
88
	/** This map holds the instances of all registered GeometryType. The key is the name of the specific Geometry subclass. 
89
	 * In other words, the string "org.gvsig.fmap.geom.primitive.Point2D" is the hash key to obtain an instance of GeometryType holding the 
87

  
88
	/** This map holds the instances of all registered GeometryType. The key is the name of the specific Geometry subclass.
89
	 * In other words, the string "org.gvsig.fmap.geom.primitive.Point2D" is the hash key to obtain an instance of GeometryType holding the
90 90
	 * operations associated to the class org.gvsig.fmap.geom.primitive.Point2D.
91 91
	 */
92 92
	private Map geometryTypes = new HashMap();
93
	
94
	/** GeometryType index counter. Each time a new geometry type is registered it is assigned this counter's value as index and after that 
93

  
94
	/** GeometryType index counter. Each time a new geometry type is registered it is assigned this counter's value as index and after that
95 95
	 * it is incremented by 1 */
96
	private int geomTypeIndex = 10000;
96
	private int geomTypeIndex = 65536;//2^16
97 97

  
98 98
	/**
99 99
	 * Geometry Factory
100 100
	 */
101 101
	private GeometryFactory factory = new GeometryFactory();
102
	
102

  
103 103
	/**
104 104
	 * Singleton's private constructor
105 105
	 */
......
125 125
	public void registerGeometryFactory(GeometryFactory factory) {
126 126
		this.factory = factory;
127 127
	}
128
	
128

  
129 129
	/**
130 130
	 * Returns the current geometry factory
131 131
	 * @return
......
133 133
	public GeometryFactory getGeometryFactory() {
134 134
		return factory;
135 135
	}
136
	
136

  
137 137
	/**
138
	 * Registers the unique name of one operation. If it already exists then this method does nothing but returning 
139
	 * the name's corresponding index.  
138
	 * Registers the unique name of one operation. If it already exists then this method does nothing but returning
139
	 * the name's corresponding index.
140 140
	 * @param geomOpName Name used to register the geometry operation
141 141
	 * @return index assigned to the operation name passed as parameter
142 142
	 */
......
151 151
		}
152 152
		return index;
153 153
	}
154
	
155
	
154

  
155

  
156 156
	/**
157
	 * Sets a common operation into the common operations map. 
157
	 * Sets a common operation into the common operations map.
158 158
	 * @param index index in which to set the operation
159 159
	 * @param geomOp operation to be set
160 160
	 */
161 161
	private void setCommonOperation(int index, GeometryOperation geomOp) {
162
		
162

  
163 163
		while (index > commonOperations.size()) {
164 164
			commonOperations.add(null);
165 165
		}
166
		
166

  
167 167
		if (index == commonOperations.size()) {
168 168
			commonOperations.add(geomOp);
169
		} else {				
169
		} else {
170 170
			commonOperations.set(index, geomOp);
171 171
		}
172
	}	
173
	
172
	}
173

  
174 174
	/**
175
	 * Registers a GeometryOperation associated to a GeometryType. 
175
	 * Registers a GeometryOperation associated to a GeometryType.
176 176
	 * Returns an unique index that is used later to identify and invoke the operation.
177
	 * 
177
	 *
178 178
	 * This method is only used if you already got a reference to the GeometryType. If not,
179
	 * it is more convenient to use the method that receives the geometry class as parameter. 
180
	 *  
181
	 * By convention, the return value should be stored in a public constant within the class implementing 
182
	 * the operation:<BR>	 
179
	 * it is more convenient to use the method that receives the geometry class as parameter.
180
	 *
181
	 * By convention, the return value should be stored in a public constant within the class implementing
182
	 * the operation:<BR>
183 183
	 * <pre>
184 184
	 * public class MyOperation extends GeometryOperation {
185
	 *   public static final int CODE = 
185
	 *   public static final int CODE =
186 186
	 *     GeometryManager.getInstance()
187 187
	 *        .registerGeometryOperation("MyOperation", new MyOperation(), geomType);
188 188
	 * }
......
191 191
	 * @param geomOp Specific GeometryOperation's instance implementing this operation
192 192
	 * @param geomType GeometryType instance to which this operation should be associated
193 193
	 * @return Index assigned to this operation. This index is used later to access the operation.
194
	 * 
194
	 *
195 195
	 */
196 196
	public int registerGeometryOperation(String geomOpName,
197 197
			GeometryOperation geomOp, GeometryType geomType) {
......
201 201
			throw new IllegalArgumentException("geomType cannot be null.");
202 202

  
203 203
		int index = registerGeometryOperationName(geomOpName);
204
		
204

  
205 205
		geomType.setGeometryOperation(index, geomOp);
206 206

  
207 207
		return index;
208 208
	}
209 209

  
210 210
	/**
211
	 * Registers a GeometryOperation that is common for all GeometryType (registered yet or not) 
211
	 * Registers a GeometryOperation that is common for all GeometryType (registered yet or not)
212 212
	 * Returns an unique index that is used later to identify and invoke the operation.
213
	 *  
214
	 * By convention, the return value should be stored in a public constant within the class implementing 
215
	 * the operation:<BR>	 
213
	 *
214
	 * By convention, the return value should be stored in a public constant within the class implementing
215
	 * the operation:<BR>
216 216
	 * <pre>
217 217
	 * public class MyOperation extends GeometryOperation {
218
	 *   public static final int CODE = 
218
	 *   public static final int CODE =
219 219
	 *     GeometryManager.getInstance()
220 220
	 *        .registerGeometryOperation("MyOperation", new MyOperation());
221 221
	 * }
222 222
	 * </pre>
223
	 *  
223
	 *
224 224
	 * @param geomOpName Operation's unique name
225 225
	 * @param geomOp Specific GeometryOperation's instance implementing this operation
226
	 * @return Index assigned to this operation. This index is used later to access the operation. 
226
	 * @return Index assigned to this operation. This index is used later to access the operation.
227 227
	 */
228 228
	public int registerGeometryOperation(String geomOpName,
229 229
			GeometryOperation geomOp) {
......
235 235
		int index = registerGeometryOperationName(geomOpName);
236 236

  
237 237
		setCommonOperation(index, geomOp);
238
		
239
		
238

  
239

  
240 240
		return index + COMMON_OPS_OFFSET;
241
		
241

  
242 242
	}
243
	
243

  
244 244
	/**
245
	 * Registers a GeometryOperation associated to a GeometryType. 
245
	 * Registers a GeometryOperation associated to a GeometryType.
246 246
	 * Returns an unique index that is used later to identify and invoke the operation.<br>
247
	 *  
248
	 * By convention, the return value should be stored in a public constant within the class implementing 
249
	 * the operation:<BR>	 
247
	 *
248
	 * By convention, the return value should be stored in a public constant within the class implementing
249
	 * the operation:<BR>
250 250
	 * <pre>
251 251
	 * public class MyOperation extends GeometryOperation {
252
	 *   public static final int CODE = 
252
	 *   public static final int CODE =
253 253
	 *     GeometryManager.getInstance()
254 254
	 *        .registerGeometryOperation("MyOperation", new MyOperation(), MyGeometry.class);
255 255
	 * }
256 256
	 * </pre>
257
	 * 
257
	 *
258 258
	 * This method is only used if you have not a reference to the GeometryType associated to the
259 259
	 * geometry class. If you have such reference then it is slightly faster to use the method that receives
260 260
	 * the GeometryType.<br>
261
	 * 
261
	 *
262 262
	 * @param geomOpName Operation's unique name
263 263
	 * @param geomOp Specific GeometryOperation's instance implementing this operation
264 264
	 * @param geomClass Geometry implementation class
265 265
	 * @return Index assigned to this operation. This index is used later to access the operation.
266
	 */	
266
	 */
267 267
	public int registerGeometryOperation(String geomOpName,
268 268
			GeometryOperation geomOp, Class geomClass) {
269
		
269

  
270 270
		GeometryType geomType = getGeometryType(geomClass);
271 271
		return registerGeometryOperation(geomOpName, geomOp, geomType);
272 272
	}
273
	
274 273

  
274

  
275 275
	/**
276
	 * Registers a GeometryOperation associated to a GeometryType. 
276
	 * Registers a GeometryOperation associated to a GeometryType.
277 277
	 * Returns an unique index that is used later to identify and invoke the operation.<br>
278
	 *  
279
	 * By convention, the return value should be stored in a public constant within the class implementing 
280
	 * the operation:<BR>	 
278
	 *
279
	 * By convention, the return value should be stored in a public constant within the class implementing
280
	 * the operation:<BR>
281 281
	 * <pre>
282 282
	 * public class MyOperation extends GeometryOperation {
283
	 *   public static final int CODE = 
283
	 *   public static final int CODE =
284 284
	 *     GeometryManager.getInstance()
285 285
	 *        .registerGeometryOperation("MyOperation", MyOperation.class, myGeomType);
286 286
	 * }
......
296 296
	public int registerGeometryOperation(String geomOpName, Class geomOpClass,
297 297
			GeometryType geomType)
298 298
			throws IllegalAccessException, InstantiationException {
299
		
300
		GeometryOperation geomOp = (GeometryOperation) geomOpClass.newInstance();		
301
		return registerGeometryOperation(geomOpName, geomOp, geomType);		
299

  
300
		GeometryOperation geomOp = (GeometryOperation) geomOpClass.newInstance();
301
		return registerGeometryOperation(geomOpName, geomOp, geomType);
302 302
	}
303 303

  
304 304
	/**
305
	 * Registers a Geometry implementation class as a new geometry type and returns the 
305
	 * Registers a Geometry implementation class as a new geometry type and returns the
306 306
	 * associated GeometryType instance. If the class is already registered
307 307
	 * then this method does nothing but returning the associated GeometryType.<br>
308
	 * 
308
	 *
309 309
	 * How to register a new geometry type:
310 310
	 * <pre>
311
	 * 
311
	 *
312 312
	 * public class MyGeom3D implements Solid {
313 313
	 *   private static final GeometryType geomType = GeometryManager.getInstance()
314 314
	 *	   .registerGeometryType(MyGeom3D.class, "MyGeom3D");
315
	 * 
315
	 *
316 316
	 *   public static final int .CODE = geomType.getType();
317 317
	 * ...
318 318
	 *   public int getType() {
......
320 320
	 *   }
321 321
	 * }
322 322
	 * </pre>
323
	 * 
323
	 *
324 324
	 * @param geomClass
325
	 *            Geometry subclass. It must not be null and must implement Geometry, otherwise an exception 
325
	 *            Geometry subclass. It must not be null and must implement Geometry, otherwise an exception
326 326
	 *            is raised.
327 327
	 * @param name
328
	 * 			  Symbolic name for the geometry type, it can be null. If it is null then the symbolic name 
328
	 * 			  Symbolic name for the geometry type, it can be null. If it is null then the symbolic name
329 329
	 * 		      will be the simple class name.
330 330
	 * @return Instance of GeometryType associated to the Geometry implementation class
331 331
	 *         geomClass
......
356 356
			throw new IllegalArgumentException("Attempt to register a geometry type that is already registered: " + geomClass.getName());
357 357
		}
358 358
		logger.debug("Class " + geomType.getGeometryClass().getName() + " registered with name " + geomType.getName());
359
		
359

  
360 360
		return geomType;
361 361
	}
362 362

  
363 363
	/**
364
	 * Registers a Geometry implementation as a new geometry type and returns the 
364
	 * Registers a Geometry implementation as a new geometry type and returns the
365 365
	 * associated GeometryType instance. If the class is already registered
366 366
	 * then this method does nothing but returning the associated GeometryType.<br>
367
	 * 
367
	 *
368 368
	 * In this case the symbolic name will be the geometry's simple class name
369
	 * 
369
	 *
370 370
	 * How to register a new geometry type:
371 371
	 * <pre>
372
	 * 
372
	 *
373 373
	 * public class MyGeom3D implements Solid {
374 374
	 *   private static final GeometryType geomType = GeometryManager.getInstance()
375 375
	 *	   .registerGeometryType(MyGeom3D.class);
376
	 * 
376
	 *
377 377
	 *   public static final int .CODE = geomType.getType();
378 378
	 * ...
379 379
	 *   public int getType() {
......
381 381
	 *   }
382 382
	 * }
383 383
	 * </pre>
384
	 * 
384
	 *
385 385
	 * @param geomClass
386
	 *            Geometry implementation class. It must not be null and must implement Geometry, 
386
	 *            Geometry implementation class. It must not be null and must implement Geometry,
387 387
	 *            otherwise an exception is thrown.
388 388
	 * @return Instance of GeometryType associated to the Geometry implementation class
389 389
	 * @throws IllegalArgumentException
......
393 393
		return registerGeometryType(geomClass, null);
394 394
	}
395 395
	/**
396
	 * Returns an instance of GeometryType given the associated Geometry implementation 
396
	 * Returns an instance of GeometryType given the associated Geometry implementation
397 397
	 * class.
398
	 * 
398
	 *
399 399
	 * @param geomClass
400 400
	 * @return Instance of GeometryType associated to the Geometry implementation class
401 401
	 */
......
407 407
	/**
408 408
	 * Returns the associated GeometryType given the fully qualified name of
409 409
	 * the Geometry implementation class.
410
	 * 
410
	 *
411 411
	 * @param className
412 412
	 *            Fully qualified name of the Geometry implementation class
413 413
	 * @return GeometryType associated to the class
......
417 417
	}
418 418

  
419 419
	/**
420
	 * Returns an operation given the Geometry implementation class and the operation 
420
	 * Returns an operation given the Geometry implementation class and the operation
421 421
	 * code. If opCode corresponds to a common operation (a common operation is an operation
422 422
	 * registered for all geometries), then this method returns the common operation.
423 423
	 * <br>
424
	 * For better performance, if you need to call an operation multiple times, 
425
	 * use this method only once and keep the returned object in a local variable 
424
	 * For better performance, if you need to call an operation multiple times,
425
	 * use this method only once and keep the returned object in a local variable
426 426
	 * over which you can iterate. For instance:
427
	 * 
427
	 *
428 428
	 * <pre>
429 429
	 * ...
430 430
	 *  // Get the operation you need
......
437 437
	 * } catch (GeometryOperationNotSupportedException gonse) {
438 438
	 *    // treat exception
439 439
	 * }
440
	 * 
440
	 *
441 441
	 *  // Fill the operation context with required params
442 442
	 * GeometryOperationContext ctx = new GeometryOperationContext();
443
	 *    
444
	 *  // Here is the main loop where you call the operation 
443
	 *
444
	 *  // Here is the main loop where you call the operation
445 445
	 * for (int i=0; i<MyGeometries.length; i++) {
446 446
	 *    Object result = geomOp.invoke(myGeometries[i], ctx);
447 447
	 * }
448
	 * 
448
	 *
449 449
	 * </pre>
450
	 * 
450
	 *
451 451
	 * @param geomClass
452 452
	 * @param opCode
453 453
	 * @return Geometry operation
454 454
	 */
455 455
	public GeometryOperation getGeometryOperation(Class geomClass, int opCode) throws GeometryTypeNotSupportedException, GeometryOperationNotSupportedException {
456
		
457
		GeometryOperation geomOp = null;				
458
		
456

  
457
		GeometryOperation geomOp = null;
458

  
459 459
		// Check if it is a common operation, and if so, get it from the common registry
460 460
		if (opCode >= COMMON_OPS_OFFSET) {
461 461
			geomOp = ((GeometryOperation)commonOperations.get(opCode - COMMON_OPS_OFFSET));
462
			
462

  
463 463
			if (geomOp == null) {
464 464
				throw new GeometryOperationNotSupportedException(opCode);
465 465
			}
466 466
		} else {
467
			// If it is type specific, get it from its type	registry	
467
			// If it is type specific, get it from its type	registry
468 468
			if (geomClass != null) {
469 469
				GeometryType geomType = getGeometryType(geomClass);
470
				
470

  
471 471
				// If the geometry type is not registered, throw an exception
472 472
				if (geomType == null) {
473 473
					throw new GeometryTypeNotSupportedException(geomClass);
474 474
				}
475
				
475

  
476 476
				// Get the operation
477 477
				geomOp = geomType.getGeometryOperation(opCode);
478
				
478

  
479 479
				// If the operation is not registered throw an exception
480 480
				if (geomOp == null) {
481 481
					throw new GeometryOperationNotSupportedException(opCode, geomType);
482
				}					
482
				}
483 483
			}
484
		}		
484
		}
485 485
		return geomOp;
486 486
	}
487
		
487

  
488 488
	/**
489
	 * Invokes an operation given its code, the geometry and the operation context holding the 
489
	 * Invokes an operation given its code, the geometry and the operation context holding the
490 490
	 * parameters required for the operation.
491
	 * 
491
	 *
492 492
	 * @param opCode Operation code.
493 493
	 * @param geom Geometry to which apply the operation
494 494
	 * @param ctx Context holding the operation parameters
495
	 * @return The object returned by an operation, depends on each operation. 
495
	 * @return The object returned by an operation, depends on each operation.
496 496
	 */
497 497
	public Object invokeOperation(int opCode, Geometry geom, GeometryOperationContext ctx) throws GeometryOperationNotSupportedException, GeometryOperationException {
498
		
498

  
499 499
		GeometryOperation geomOp = null;
500
		
500

  
501 501
		if (opCode < COMMON_OPS_OFFSET) {
502 502
			geomOp =  geom.getGeometryType().getGeometryOperation(opCode);
503 503
		} else {
504 504
			geomOp = ((GeometryOperation)commonOperations.get(opCode - COMMON_OPS_OFFSET));
505 505
		}
506
		
506

  
507 507
		if (geomOp != null) {
508 508
			return geomOp.invoke(geom, ctx);
509 509
		}
510
		
510

  
511 511
		throw new GeometryOperationNotSupportedException(opCode, geom.getGeometryType());
512 512
	}
513 513
}

Also available in: Unified diff