Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libFMap_geometries / src / org / gvsig / fmap / geom / GeometryManager.java @ 21047

History | View | Annotate | Download (14.3 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   IVER T.I. S.A
34
 *   Salamanca 50
35
 *   46005 Valencia
36
 *   Spain
37
 *
38
 *   +34 963163400
39
 *   dac@iver.es
40
 */
41
package org.gvsig.fmap.geom;
42

    
43
import java.util.ArrayList;
44
import java.util.HashMap;
45
import java.util.List;
46
import java.util.Map;
47

    
48
import org.gvsig.fmap.geom.operation.GeometryOperation;
49
import org.gvsig.fmap.geom.operation.GeometryOperationContext;
50
import org.gvsig.fmap.geom.operation.GeometryOperationException;
51
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
52
import org.gvsig.fmap.geom.type.GeometryType;
53

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

    
71
        private static GeometryManager instance;
72

    
73
        /** This list holds the unique name of all registered geometry operations. 
74
         * The index in which they are stored is also the operation code used to invoke each one of them */
75
        private List geometryOperations = new ArrayList();
76
                
77
        /** Common operations are registered here. Type specific operations are registered in the corresponding GeometryType instance */ 
78
        private List commonOperations = new ArrayList();
79
        
80
        /** Common operations are assigned an index greater or equal than this constant, so that it is easy and efficient for the manager 
81
         * to decide whether to lookup in the common register or in the type specific register. */
82
        private static final int COMMON_OPS_OFFSET = 1000;
83
        
84
        /** This map holds the instances of all registered GeometryType. The key is the name of the specific Geometry subclass. 
85
         * In other words, the string "org.gvsig.fmap.geom.primitive.Point2D" is the hash key to obtain an instance of GeometryType holding the 
86
         * operations associated to the class org.gvsig.fmap.geom.primitive.Point2D.
87
         */
88
        private Map geometryTypes = new HashMap();
89
        
90
        /** GeometryType index counter. Each time a new geometry type is registered it is assigned this counter's value as index and after that 
91
         * it is incremented by 1 */
92
        private int geomTypeIndex = 100;
93

    
94
        /**
95
         * Singleton's private constructor
96
         */
97
        private GeometryManager() {
98
        }
99

    
100
        /**
101
         * Returns this singleton's unique instance
102
         * @return unique instance of GeometryManager
103
         */
104
        public static GeometryManager getInstance() {
105
                if (instance == null) {
106
                        instance = new GeometryManager();
107
                }
108
                return instance;
109
        }
110

    
111
        /**
112
         * Registers the unique name of one operation. If it already exists then this method does nothing but returning 
113
         * the name's corresponding index.  
114
         * @param geomOpName Name used to register the geometry operation
115
         * @return index assigned to the operation name passed as parameter
116
         */
117
        private int registerGeometryOperationName(String geomOpName) {
118
                if (geomOpName == null)
119
                        throw new IllegalArgumentException("geomOpName cannot be null.");
120

    
121
                int index = geometryOperations.indexOf(geomOpName);
122
                if (index == -1) {
123
                        geometryOperations.add(geomOpName);
124
                        index = geometryOperations.indexOf(geomOpName);
125
                }
126
                return index;
127
        }
128
        
129
        
130
        /**
131
         * Sets a common operation into the common operations map. 
132
         * @param index index in which to set the operation
133
         * @param geomOp operation to be set
134
         */
135
        private void setCommonOperation(int index, GeometryOperation geomOp) {
136
                
137
                while (index > commonOperations.size()) {
138
                        commonOperations.add(null);
139
                }
140
                
141
                if (index == commonOperations.size()) {
142
                        commonOperations.add(geomOp);
143
                } else {                                
144
                        commonOperations.set(index, geomOp);
145
                }
146
        }        
147
        
148
        /**
149
         * Registers a GeometryOperation associated to a GeometryType. 
150
         * Returns an unique index that is used later to identify and invoke the operation.
151
         * 
152
         * This method is only used if you already got a reference to the GeometryType. If not,
153
         * it is more convenient to use the method that receives the geometry class as parameter. 
154
         *  
155
         * By convention, the return value should be stored in a public constant within the class implementing 
156
         * the operation:<BR>         
157
         * <pre>
158
         * public class MyOperation extends GeometryOperation {
159
         *   public static final int OPERATION_INDEX = 
160
         *     GeometryManager.getInstance()
161
         *        .registerGeometryOperation("MyOperation", new MyOperation(), geomType);
162
         * }
163
         * </pre>
164
         * @param geomOpName Operation's unique name
165
         * @param geomOp Specific GeometryOperation's instance implementing this operation
166
         * @param geomType GeometryType instance to which this operation should be associated
167
         * @return Index assigned to this operation. This index is used later to access the operation.
168
         * 
169
         */
170
        public int registerGeometryOperation(String geomOpName,
171
                        GeometryOperation geomOp, GeometryType geomType) {
172
                if (geomOp == null)
173
                        throw new IllegalArgumentException("geomOp cannot be null.");
174
                if (geomType == null)
175
                        throw new IllegalArgumentException("geomType cannot be null.");
176

    
177
                int index = registerGeometryOperationName(geomOpName);
178
                
179
                geomType.setGeometryOperation(index, geomOp);
180

    
181
                return index;
182
        }
183

    
184
        /**
185
         * Registers a GeometryOperation that is common for all GeometryType (registered yet or not) 
186
         * Returns an unique index that is used later to identify and invoke the operation.
187
         *  
188
         * By convention, the return value should be stored in a public constant within the class implementing 
189
         * the operation:<BR>         
190
         * <pre>
191
         * public class MyOperation extends GeometryOperation {
192
         *   public static final int OPERATION_INDEX = 
193
         *     GeometryManager.getInstance()
194
         *        .registerGeometryOperation("MyOperation", new MyOperation());
195
         * }
196
         * </pre>
197
         *  
198
         * @param geomOpName Operation's unique name
199
         * @param geomOp Specific GeometryOperation's instance implementing this operation
200
         * @return Index assigned to this operation. This index is used later to access the operation. 
201
         */
202
        public int registerGeometryOperation(String geomOpName,
203
                        GeometryOperation geomOp) {
204
                if (geomOpName == null)
205
                        throw new IllegalArgumentException("geomOpName cannot be null.");
206
                if (geomOp == null)
207
                        throw new IllegalArgumentException("geomOp cannot be null.");
208

    
209
                int index = registerGeometryOperationName(geomOpName);
210

    
211
                setCommonOperation(index, geomOp);
212
                
213
                
214
                return index + COMMON_OPS_OFFSET;
215
                
216
        }
217
        
218
        /**
219
         * Registers a GeometryOperation associated to a GeometryType. 
220
         * Returns an unique index that is used later to identify and invoke the operation.<br>
221
         *  
222
         * By convention, the return value should be stored in a public constant within the class implementing 
223
         * the operation:<BR>         
224
         * <pre>
225
         * public class MyOperation extends GeometryOperation {
226
         *   public static final int OPERATION_INDEX = 
227
         *     GeometryManager.getInstance()
228
         *        .registerGeometryOperation("MyOperation", new MyOperation(), MyGeometry.class);
229
         * }
230
         * </pre>
231
         * 
232
         * This method is only used if you have not a reference to the GeometryType associated to the
233
         * geometry class. If you have such reference then it is slightly faster to use the method that receives
234
         * the GeometryType.<br>
235
         * 
236
         * @param geomOpName Operation's unique name
237
         * @param geomOp Specific GeometryOperation's instance implementing this operation
238
         * @param geomClass Geometry implementation class
239
         * @return Index assigned to this operation. This index is used later to access the operation.
240
         */        
241
        public int registerGeometryOperation(String geomOpName,
242
                        GeometryOperation geomOp, Class geomClass) {
243
                
244
                GeometryType geomType = getGeometryType(geomClass);
245
                return registerGeometryOperation(geomOpName, geomOp, geomType);
246
        }
247
        
248

    
249
        /**
250
         * Registers a GeometryOperation associated to a GeometryType. 
251
         * Returns an unique index that is used later to identify and invoke the operation.<br>
252
         *  
253
         * By convention, the return value should be stored in a public constant within the class implementing 
254
         * the operation:<BR>         
255
         * <pre>
256
         * public class MyOperation extends GeometryOperation {
257
         *   public static final int OPERATION_INDEX = 
258
         *     GeometryManager.getInstance()
259
         *        .registerGeometryOperation("MyOperation", MyOperation.class, myGeomType);
260
         * }
261
         * </pre>
262
         *
263
         * @param geomOpName Operation's unique name
264
         * @param geomOpClass GeometryOperation class
265
         * @param geomType GeometryType instance to which this operation should be associated
266
         * @return Index assigned to this operation. This index is used later to access the operation.
267
         * @throws IllegalAccessException, {@link InstantiationException} Either exception maybe thrown when
268
         * trying to instance the geometry operation class.
269
         */
270
        public int registerGeometryOperation(String geomOpName, Class geomOpClass,
271
                        GeometryType geomType)
272
                        throws IllegalAccessException, InstantiationException {
273
                
274
                GeometryOperation geomOp = (GeometryOperation) geomOpClass.newInstance();                
275
                return registerGeometryOperation(geomOpName, geomOp, geomType);                
276
        }
277

    
278
        /**
279
         * Registers a Geometry implementation class as a new geometry type and returns the 
280
         * associated GeometryType instance. If the class is already registered
281
         * then this method does nothing but returning the associated GeometryType.<br>
282
         * 
283
         * @param geomClass
284
         *            Geometry subclass. It must not be null and must implement Geometry, otherwise an exception 
285
         *            is raised.
286
         * @param name
287
         *                           Symbolic name for the geometry type, it can be null. If it is null then the symbolic name 
288
         *                       will be the simple class name.
289
         * @return Instance of GeometryType associated to the Geometry implementation class
290
         *         geomClass
291
         * @throws IllegalArgumentException
292
         *             If geomClass is null or does not implement Geometry
293
         */
294
        public GeometryType registerGeometryType(Class geomClass, String name) {
295

    
296
                if (geomClass == null) {
297
                        throw new IllegalArgumentException("geomClass cannot be null.");
298
                }
299

    
300
                if (!Geometry.class.isAssignableFrom(geomClass)) {
301
                        throw new IllegalArgumentException(geomClass.getName()
302
                                        + " must implement the Geometry interface");
303
                }
304

    
305
                // Comprobar si ya est? registrada
306
                GeometryType geomType = (GeometryType) geometryTypes.get(geomClass
307
                                .getName());
308

    
309
                // Si no est? registrada, registrarla
310
                if (geomType == null) {
311
                        geomType = new GeometryType(geomClass, name, geomTypeIndex++);
312
                        geometryTypes.put(geomClass.getName(), geomType);
313
                }
314

    
315
                return geomType;
316
        }
317

    
318
        /**
319
         * Registers a Geometry implementation as a new geometry type and returns the 
320
         * associated GeometryType instance. If the class is already registered
321
         * then this method does nothing but returning the associated GeometryType.<br>
322
         * 
323
         * @param geomClass
324
         *            Geometry implementation class. It must not be null and must implement Geometry, 
325
         *            otherwise an exception is thrown.
326
         * @param name
327
         *                           Symbolic name for the geometry type, it can be null. If it is null then the symbolic name 
328
         *                       will be the simple class name.
329
         * @return Instancia de GeometryType asociada a la clase de geometr?a
330
         *         geomClass
331
         * @throws IllegalArgumentException
332
         *             If geomClass is null or does not implement Geometry
333
         */
334
        public GeometryType registerGeometryType(Class geomClass) {
335
                return registerGeometryType(geomClass, null);
336
        }
337
        /**
338
         * Returns an instance of GeometryType given the associated Geometry implementation 
339
         * class.
340
         * 
341
         * @param geomClass
342
         * @return Instance of GeometryType associated to geomClass
343
         */
344
        public GeometryType getGeometryType(Class geomClass) {
345
                return (GeometryType) geometryTypes.get(geomClass.getName());
346
        }
347

    
348
        /**
349
         * Returns the associated GeometryType given the fully qualified name of
350
         * the Geometry implementation class.
351
         * 
352
         * @param className
353
         *            Fully qualified name of the Geometry implementation class
354
         * @return GeometryType associated to the class
355
         */
356
        public GeometryType getGeometryType(String className) {
357
                return (GeometryType) geometryTypes.get(className);
358
        }
359

    
360
        /**
361
         * Returns an operation given the Geometry implementation class and the operation 
362
         * index.
363
         * 
364
         * @param geomClass
365
         * @param index
366
         * @return
367
         */
368
        public GeometryOperation getGeometryOperation(Class geomClass, int index) {
369
                GeometryType geomType = getGeometryType(geomClass);
370
                if (geomType != null) {
371
                        return geomType.getGeometryOperation(index);
372
                }
373
                return null;
374
        }
375
        
376
        /**
377
         * Invokes an operation given its code, the geometry and the operation context holding the 
378
         * parameters required for the operation.
379
         * 
380
         * @param opCode Operation code.
381
         * @param geom Geometry to which apply the operation
382
         * @param ctx Context holding the operation parameters
383
         * @return The object returned by an operation, depends on each operation. 
384
         */
385
        public Object invokeOperation(int opCode, Geometry geom, GeometryOperationContext ctx) throws GeometryOperationNotSupportedException, GeometryOperationException {
386
                
387
                GeometryOperation geomOp = null;
388
                
389
                if (opCode < COMMON_OPS_OFFSET) {
390
                        geomOp =  geom.getGeometryType().getGeometryOperation(opCode);
391
                } else {
392
                        geomOp = ((GeometryOperation)commonOperations.get(opCode - COMMON_OPS_OFFSET));
393
                }
394
                
395
                if (geomOp != null) {
396
                        return geomOp.invoke(geom, ctx);
397
                }
398
                
399
                throw new GeometryOperationNotSupportedException(opCode, geom.getGeometryType());
400
        }
401
}