Statistics
| Revision:

gvsig-tools / org.gvsig.tools / library / trunk / org.gvsig.tools / org.gvsig.tools.lib / src / main / java / org / gvsig / tools / dynobject / impl / DefaultDynObjectManager.java @ 308

History | View | Annotate | Download (21.6 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program 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 this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 */
22
package org.gvsig.tools.dynobject.impl;
23

    
24
import java.io.IOException;
25
import java.io.InputStream;
26
import java.util.ArrayList;
27
import java.util.Arrays;
28
import java.util.Collections;
29
import java.util.HashMap;
30
import java.util.HashSet;
31
import java.util.Iterator;
32
import java.util.List;
33
import java.util.Map;
34
import java.util.Set;
35

    
36
import org.slf4j.Logger;
37
import org.slf4j.LoggerFactory;
38
import org.xmlpull.v1.XmlPullParser;
39
import org.xmlpull.v1.XmlPullParserException;
40

    
41
import org.gvsig.tools.ToolsLocator;
42
import org.gvsig.tools.dynobject.DynClass;
43
import org.gvsig.tools.dynobject.DynClassName;
44
import org.gvsig.tools.dynobject.DynMethod;
45
import org.gvsig.tools.dynobject.DynObject;
46
import org.gvsig.tools.dynobject.DynObjectManager;
47
import org.gvsig.tools.dynobject.DynObjectPagingHelper;
48
import org.gvsig.tools.dynobject.DynObjectRuntimeException;
49
import org.gvsig.tools.dynobject.DynObjectSet;
50
import org.gvsig.tools.dynobject.DynStruct;
51
import org.gvsig.tools.dynobject.exception.DuplicateDynClassException;
52
import org.gvsig.tools.dynobject.exception.DynMethodException;
53
import org.gvsig.tools.dynobject.exception.DynMethodIllegalCodeException;
54
import org.gvsig.tools.dynobject.exception.DynMethodNotSupportedException;
55
import org.gvsig.tools.dynobject.exception.IllegalDynMethodException;
56
import org.gvsig.tools.dynobject.exception.IllegalDynMethodInvocationException;
57
import org.gvsig.tools.exception.BaseException;
58

    
59
/**
60
 * Default {@link DynObjectManager} implementation.
61
 * 
62
 * @author gvSIG Team
63
 * @version $Id$
64
 */
65
public class DefaultDynObjectManager implements DynObjectManager {
66

    
67
    private final static Logger LOG = LoggerFactory
68
        .getLogger(DefaultDynObjectManager.class);
69

    
70
    private static DefaultDynObjectManager manager = null;
71

    
72
    private class MethodInfo {
73

    
74
        int code;
75
        DynClass dynClass;
76
        DynMethod dynMethod;
77
        Class theClass;
78

    
79
        MethodInfo(Class theClass, DynClass dynClass, DynMethod dynMethod,
80
            int code) {
81
            this.code = code;
82
            this.dynClass = dynClass;
83
            this.dynMethod = dynMethod;
84
            this.theClass = theClass;
85
        }
86

    
87
        String getKey() {
88
            return DefaultDynObjectManager
89
                .getKey(theClass, dynClass, dynMethod);
90
        }
91

    
92
        void check(Class theClass, int code) throws DynMethodException {
93
            if (code != this.code) {
94
                throw new DynMethodIllegalCodeException(dynMethod.getName(),
95
                    this.code, code);
96
            }
97
            if (theClass != null) {
98
                if (this.theClass == null) {
99
                    throw new IllegalDynMethodInvocationException(
100
                        dynMethod.getName(), theClass);
101
                }
102
                if (!this.theClass.isAssignableFrom(theClass)) {
103
                    throw new IllegalDynMethodInvocationException(
104
                        dynMethod.getName(), theClass);
105
                }
106
            }
107
        }
108

    
109
        void check(DynClass dynClass, int code) throws DynMethodException {
110
            if (code != this.code) {
111
                throw new DynMethodIllegalCodeException(dynMethod.getName(),
112
                    this.code, code);
113
            }
114
            if (dynClass != null) {
115
                if (this.dynClass == null) {
116
                    throw new IllegalDynMethodInvocationException(
117
                        dynMethod.getName(), dynClass);
118
                }
119
                if (dynClass != this.dynClass
120
                    || !dynClass.getName().equalsIgnoreCase(
121
                        this.dynClass.getName())) {
122
                    throw new IllegalDynMethodInvocationException(
123
                        dynMethod.getName(), dynClass);
124
                }
125
            }
126
        }
127
    }
128

    
129
    private class ClassesNamespaces {
130

    
131
        private Map defaultNamespace;
132
        private Map namespaces;
133

    
134
        ClassesNamespaces() {
135
            this.namespaces = new HashMap();
136
            this.defaultNamespace = new HashMap();
137
        }
138

    
139
        public Map addNamespace(String name) {
140
            Map namespace = new HashMap();
141
            this.namespaces.put(name.toLowerCase(), namespace);
142
            return namespace;
143
        }
144

    
145
        public Map getNamespace(String name) {
146
            return (Map) this.namespaces.get(name.toLowerCase());
147
        }
148

    
149
        public void clear() {
150
            this.defaultNamespace.clear();
151
            this.namespaces.clear();
152
        }
153

    
154
        public boolean containsClass(String name) {
155
            name = name.toLowerCase();
156
            if (this.defaultNamespace.containsKey(name)) {
157
                return true;
158
            }
159

    
160
            Iterator it = this.namespaces.values().iterator();
161
            while (it.hasNext()) {
162
                Map names = (Map) it.next();
163
                if (names.containsKey(name)) {
164
                    return true;
165
                }
166
            }
167
            return false;
168
        }
169

    
170
        public boolean containsClass(String namespace, String name) {
171
            name = name.toLowerCase();
172
            if (namespace == null) {
173
                return this.defaultNamespace.containsKey(name);
174
            }
175
            Map space = this.getNamespace(namespace);
176
            if (space == null) {
177
                return false;
178
            }
179
            return space.containsKey(name);
180
        }
181

    
182
        public boolean containsClass(DynClass dynClass) {
183
            if (this.defaultNamespace.containsValue(dynClass)) {
184
                return true;
185
            }
186

    
187
            Iterator it = this.namespaces.values().iterator();
188
            while (it.hasNext()) {
189
                Map names = (Map) it.next();
190
                if (names.containsValue(dynClass)) {
191
                    return true;
192
                }
193
            }
194
            return false;
195
        }
196

    
197
        public DynClass get(String name, String namespace) {
198
            if (namespace == null) {
199
                return (DynClass) this.defaultNamespace.get(name.toLowerCase());
200
            }
201
            Map space = this.getNamespace(namespace);
202
            if (space == null) {
203
                return null;
204
            }
205
            return (DynClass) space.get(name.toLowerCase());
206
        }
207

    
208
        public Set keySet() {
209
            Set keyset = new HashSet();
210
            Iterator it = this.iterator();
211
            while (it.hasNext()) {
212
                DynClass dynClass = (DynClass) it.next();
213
                keyset.add(dynClass.getFullName());
214
            }
215
            return keyset;
216
        }
217

    
218
        public Iterator iterator() {
219
            final class MyIterator implements Iterator {
220

    
221
                Iterator current;
222
                Iterator others;
223

    
224
                MyIterator(Iterator main, Iterator others) {
225
                    this.current = main;
226
                    this.others = others;
227
                }
228

    
229
                public boolean hasNext() {
230
                    if (this.current.hasNext()) {
231
                        return true;
232
                    }
233
                    while (this.others.hasNext()) { 
234
                        Object obj = others.next();
235
                        this.current = (Iterator) ((HashMap) obj).values().iterator();
236
                        if (this.current.hasNext()) {
237
                            return true;
238
                        }
239
                    }
240
                    return false;
241
                }
242

    
243
                public Object next() {
244
                    if (this.current.hasNext()) {
245
                        return this.current.next();
246
                    }
247
                    while (this.others.hasNext()) {
248
                        Object obj = others.next();
249
                        this.current = (Iterator) ((HashMap) obj).values().iterator();
250
                        if (this.current.hasNext()) {
251
                            return this.current.next();
252
                        }
253
                    }
254
                    return null;
255
                }
256

    
257
                public void remove() {
258
                    throw new UnsupportedOperationException();
259
                }
260
            }
261

    
262
            return new MyIterator(this.defaultNamespace.values().iterator(),
263
                this.namespaces.values().iterator());
264
        }
265

    
266
        public Object add(DynStruct dynClass) {
267
            String name = dynClass.getName().toLowerCase();
268
            Map namespace;
269
            if (dynClass.getNamespace() != null) {
270
                namespace = (Map) this.getNamespace(dynClass.getNamespace());
271
                if (namespace == null) {
272
                    namespace = this.addNamespace(dynClass.getNamespace());
273
                }
274
            } else {
275
                namespace = this.defaultNamespace;
276
            }
277
            if (namespace.containsKey(name)) {
278
                throw new DuplicateDynClassException(dynClass);
279
            }
280
            return namespace.put(name, dynClass);
281
        }
282

    
283
        public void remove(DynStruct dynClass) {
284
            String name = dynClass.getName().toLowerCase();
285
            Map namespace;
286
            if (dynClass.getNamespace() != null) {
287
                namespace = (Map) this.getNamespace(dynClass.getNamespace());
288
                if (namespace == null) {
289
                    namespace = this.addNamespace(dynClass.getNamespace());
290
                }
291
            } else {
292
                namespace = this.defaultNamespace;
293
            }
294
            if (namespace.containsKey(name)) {
295
                namespace.remove(name);
296
            }
297
        }
298

    
299
        public int size() {
300
            int count = this.defaultNamespace.size();
301

    
302
            Iterator it = this.namespaces.values().iterator();
303
            while (it.hasNext()) {
304
                Map names = (Map) it.next();
305
                count += names.size();
306
            }
307
            return count;
308
        }
309

    
310
    }
311

    
312
    private Map anonymousClasses;
313
    private ClassesNamespaces classes;
314
    private Map methodsMap;
315
    private MethodInfo[] methods;
316

    
317
    public static DefaultDynObjectManager getManager() {
318
        if (manager == null) {
319
            manager = new DefaultDynObjectManager();
320
        }
321
        return manager;
322
    }
323

    
324
    static String getKey(Class theClass, DynClass dynClass, DynMethod dynMethod) {
325
        return DefaultDynObjectManager.getKey(theClass, dynClass,
326
            dynMethod.getName());
327
    }
328

    
329
    static String getKey(Class theClass, DynClass dynClass, String methodName) {
330
        if (dynClass == null) {
331
            return theClass.getName() + ":" + methodName;
332
        } else {
333
            return dynClass.getName() + ":" + methodName;
334
        }
335
    }
336

    
337
    public DefaultDynObjectManager() {
338
        this.classes = new ClassesNamespaces();
339
        this.anonymousClasses = new HashMap();
340
        this.methodsMap = new HashMap();
341
        this.methods = null;
342
    }
343

    
344
    public DynClass createDynClass(String name, String description) {
345
        return new DefaultDynClass(this, name, description);
346
    }
347

    
348
    public DynClass createDynClass(String namespace, String name,
349
        String description) {
350
        return new DefaultDynClass(this, namespace, name, description);
351
    }
352

    
353
    public void add(DynClass dynClass) {
354
        try {
355
            ((DefaultDynClass) dynClass).check();
356
        } catch (Exception ex) {
357
            throw new DynObjectRuntimeException(ex);
358
        }
359
        this.classes.add(dynClass);
360
        LOG.trace("Add DynClass definition {}.",
361
            new Object[] { dynClass.getFullName() });
362

    
363
    }
364

    
365
    public DynClass add(String name, String description) {
366
        DynClass dynClass =
367
            (DynClass) this.classes.get(name.toLowerCase(), null);
368
        if (dynClass == null) {
369
            dynClass = this.createDynClass(name, description);
370
            this.add(dynClass);
371
        }
372
        return dynClass;
373
    }
374

    
375
    public DynClass add(String name) {
376
        return this.add(name, null);
377
    }
378

    
379
    public void remove(DynStruct dynClass) {
380
        this.classes.remove(dynClass);
381
    }
382

    
383
    // public static String getFullName(String namespace, String name) {
384
    // if( namespace == null ) {
385
    // return name;
386
    // }
387
    // return namespace + ":" + name;
388
    // }
389
    // public static String[] splitFullName(String fullname) {
390
    // String[] name = new String[] { null, fullname };
391
    // int x=fullname.indexOf(':');
392
    // if( x>-1 ) {
393
    // name[0] = fullname.substring(0, x);
394
    // name[1] = fullname.substring(x+1);
395
    // }
396
    // return name;
397
    //
398
    // }
399

    
400
    public DynClass get(String theName) {
401
        DynClassName name = createDynClassName(theName);
402
        return this.get(name.getNamespace(), name.getName());
403
    }
404

    
405
    public DynClass get(String namespace, String name) {
406
        return (DynClass) this.classes.get(name, namespace);
407
    }
408

    
409
    public DynClass get(DynClass[] superClasses) {
410
        StringBuffer name = new StringBuffer();
411
        for (int i = 0; i < superClasses.length; i++) {
412
            name.append(superClasses[i].getName()).append("+");
413
        }
414
        DefaultDynClass dynClass =
415
            (DefaultDynClass) this.anonymousClasses.get(name.toString());
416
        if (dynClass == null) {
417
            dynClass =
418
                new DefaultDynClass(this, name.toString(), null, superClasses);
419
            dynClass.setAnonymous(true);
420
        }
421
        return dynClass;
422
    }
423

    
424
    public int getCount() {
425
        return this.classes.size();
426
    }
427

    
428
    public List getNames() {
429
        String[] names = (String[]) this.classes.keySet().toArray();
430
        Arrays.sort(names);
431
        return Collections.unmodifiableList(Arrays.asList(names));
432
    }
433

    
434
    public boolean has(String name) {
435
        return this.classes.containsClass(name);
436
    }
437

    
438
    public boolean has(String namespace, String name) {
439
        return this.classes.containsClass(namespace, name);
440
    }
441

    
442
    public Iterator iterator() {
443
        return this.classes.iterator();
444
    }
445

    
446
    public DynObject createDynObject(String dynClassName) {
447
        DynClassName name = createDynClassName(dynClassName);
448
        return this.createDynObject(name.getName(), name.getNamespace());
449
    }
450

    
451
    public DynObject createDynObject(String dynClassName, String namespace) {
452

    
453
        DynClass dynClass =
454
            (DynClass) this.classes.get(dynClassName, namespace);
455
        if (dynClass == null) {
456
            throw new IllegalArgumentException("Can't locate class '"
457
                + createDynClassName(namespace, dynClassName).getFullName()
458
                + "'.");
459
        }
460
        return this.createDynObject(dynClass);
461
    }
462

    
463
    public DynObject createDynObject(DynStruct dynClass) {
464
        return new DefaultDynObject(dynClass);
465
    }
466

    
467
    public void consolide() {
468
        Iterator it = this.classes.iterator();
469
        while (it.hasNext()) {
470
            DefaultDynClass dc = (DefaultDynClass) it.next();
471
            dc.consolide();
472
        }
473
        it = this.anonymousClasses.values().iterator();
474
        while (it.hasNext()) {
475
            DefaultDynClass dc = (DefaultDynClass) it.next();
476
            dc.consolide();
477
        }
478
    }
479

    
480
    public int registerDynMethod(DynClass dynClass, DynMethod dynMethod) {
481
        ((DefaultDynClass) dynClass).addMethod(dynMethod);
482
        return registerDynMethod(null, dynClass, dynMethod);
483
    }
484

    
485
    public int registerDynMethod(Class theClass, DynMethod dynMethod) {
486
        return registerDynMethod(theClass, null, dynMethod);
487
    }
488

    
489
    int registerDynMethod(Class theClass, DynClass dynClass, DynMethod dynMethod) {
490
        MethodInfo info = new MethodInfo(theClass, dynClass, dynMethod, 0);
491
        MethodInfo oldInfo = (MethodInfo) methodsMap.get(info.getKey());
492
        if (oldInfo != null) {
493
            // Update the method info
494
            oldInfo.dynClass = dynClass;
495
            oldInfo.dynMethod = dynMethod;
496
            return oldInfo.code;
497
        }
498
        if (methods == null) {
499
            methods = new MethodInfo[1];
500
            info.code = 0;
501
        } else {
502
            MethodInfo[] temp1 = new MethodInfo[methods.length + 1];
503
            System.arraycopy(methods, 0, temp1, 0, methods.length);
504
            info.code = temp1.length - 1;
505
            methods = temp1;
506
        }
507
        methods[info.code] = info;
508
        methodsMap.put(info.getKey(), info);
509

    
510
        return info.code;
511
    }
512

    
513
    public Object invokeDynMethod(Object self, int code, DynObject context)
514
        throws DynMethodException {
515

    
516
        try {
517
            /*
518
             * Intentamos ejecutar la operacion, y si peta ya haremos las
519
             * comprobaciones oportunas para lanzar la excepcion que toque.
520
             * 
521
             * Asi evitamos codigo de comprobacion para los casos que valla bien
522
             * que deberian ser la mayoria.
523
             */
524
            return methods[code].dynMethod.invoke(self, context);
525
        } catch (RuntimeException e) {
526
            getDynMethod(self, code);
527
            throw e;
528
        } catch (DynMethodException e) {
529
            getDynMethod(self, code);
530
            throw e;
531
        }
532

    
533
    }
534

    
535
    public int getDynMethodCode(DynClass dynClass, String methodName)
536
        throws DynMethodException {
537
        String key = DefaultDynObjectManager.getKey(null, dynClass, methodName);
538
        MethodInfo info = (MethodInfo) methodsMap.get(key);
539
        if (info == null) {
540
            throw new IllegalDynMethodException(methodName, dynClass);
541
        }
542
        info.check(dynClass, info.code);
543
        return info.code;
544
    }
545

    
546
    public int getDynMethodCode(Class theClass, String methodName)
547
        throws DynMethodException {
548
        String key = DefaultDynObjectManager.getKey(theClass, null, methodName);
549
        MethodInfo info = (MethodInfo) methodsMap.get(key);
550
        if (info == null) {
551
            throw new IllegalDynMethodException(methodName, theClass);
552
        }
553
        info.check(theClass, info.code);
554
        return info.code;
555
    }
556

    
557
    public DynMethod getDynMethod(int code) throws DynMethodException {
558
        if (code >= methods.length) {
559
            throw new DynMethodNotSupportedException(code, "{null}");
560
        }
561
        MethodInfo info = methods[code];
562
        info.check((Class) null, code);
563
        return info.dynMethod;
564
    }
565

    
566
    public DynMethod getDynMethod(Object obj, int code)
567
        throws DynMethodException {
568
        return getDynMethod(obj.getClass(), code);
569
    }
570

    
571
    public DynMethod getDynMethod(Class theClass, int code)
572
        throws DynMethodException {
573
        if (code >= methods.length) {
574
            throw new DynMethodNotSupportedException(code, theClass.getName());
575
        }
576
        MethodInfo info = methods[code];
577
        info.check(theClass, code);
578
        return info.dynMethod;
579
    }
580

    
581
    public DynMethod getDynMethod(DynClass dynClass, int code)
582
        throws DynMethodException {
583
        if (code >= methods.length) {
584
            throw new DynMethodNotSupportedException(code, dynClass.getName());
585
        }
586
        MethodInfo info = methods[code];
587
        info.check(dynClass, code);
588
        return info.dynMethod;
589
    }
590

    
591
    public DynMethod getDynMethod(DynObject dynObject, int code)
592
        throws DynMethodException {
593
        return getDynMethod(dynObject.getDynClass(), code);
594
    }
595

    
596
    public void validate(DynObject object) {
597
        // TODO
598
        return;
599
    }
600

    
601
    public Class getDefaultClassOfType(int type) {
602
        return ToolsLocator.getDataTypesManager().getDefaultClass(type);
603
    }
604

    
605
    public Map importDynClassDefinitions(InputStream resource,
606
        ClassLoader loader) throws XmlPullParserException, IOException {
607
        return new DynClassImportHelper().importDefinitions(resource, loader,
608
            null);
609
    }
610

    
611
    public Map importDynClassDefinitions(XmlPullParser parser,
612
        ClassLoader loader, String defaultNamespace)
613
        throws XmlPullParserException, IOException {
614
        return new DynClassImportHelper().importDefinitions(parser, loader,
615
            defaultNamespace);
616
    }
617

    
618
    public Map importDynClassDefinitions(InputStream resource,
619
        ClassLoader loader, String defaultNamespace)
620
        throws XmlPullParserException, IOException {
621
        return new DynClassImportHelper().importDefinitions(resource, loader,
622
            defaultNamespace);
623
    }
624

    
625
    public DynObjectPagingHelper createDynObjectPagingHelper(DynObjectSet set)
626
        throws BaseException {
627
        return new DefaultDynObjectPagingHelper(set); 
628
    }
629

    
630
    public DynObjectPagingHelper createDynObjectPagingHelper(DynObjectSet set,
631
        int pageSize) throws BaseException {
632
        return new DefaultDynObjectPagingHelper(set, pageSize);
633
    }
634

    
635
    public DynClassName createDynClassName(String namespace, String name) {
636
        return new DefaultDynClassName(namespace, name);
637
    }
638

    
639
    public DynClassName createDynClassName(String name) {
640
        return new DefaultDynClassName(name);
641
    }
642

    
643
    public Iterator iterator(String namespace) {
644
        List list = new ArrayList();
645
        Iterator it = this.classes.iterator();
646
        while( it.hasNext() ) {
647
            
648
            Object obj = it.next();
649
            DynStruct dynStruct = (DynStruct) obj;
650
            list.add(dynStruct);                      
651
            
652
        }
653
        return list.iterator();
654
    }
655

    
656

    
657
}