Statistics
| Revision:

gvsig-tools / org.gvsig.tools / library / trunk / org.gvsig.tools / org.gvsig.tools.lib / src / main / java / org / gvsig / tools / persistence / impl / DefaultPersistentContext.java @ 2145

History | View | Annotate | Download (13.5 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
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
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
/* gvSIG. Geographic Information System of the Valencian Government
25
*
26
* Copyright (C) 2007-2008 Infrastructures and Transports Department
27
* of the Valencian Government (CIT)
28
*
29
* This program is free software; you can redistribute it and/or
30
* modify it under the terms of the GNU General Public License
31
* as published by the Free Software Foundation; either version 2
32
* of the License, or (at your option) any later version.
33
*
34
* This program is distributed in the hope that it will be useful,
35
* but WITHOUT ANY WARRANTY; without even the implied warranty of
36
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37
* GNU General Public License for more details.
38
*
39
* You should have received a copy of the GNU General Public License
40
* along with this program; if not, write to the Free Software
41
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
42
* MA  02110-1301, USA.
43
*
44
*/
45

    
46
/*
47
* AUTHORS (In addition to CIT):
48
* 2009 IVER T.I   {{Task}}
49
*/
50

    
51
package org.gvsig.tools.persistence.impl;
52

    
53
import java.util.ArrayList;
54
import java.util.Iterator;
55
import java.util.LinkedHashMap;
56
import java.util.List;
57
import java.util.Map;
58
import java.util.Map.Entry;
59
import org.apache.commons.lang3.mutable.MutableInt;
60

    
61
import org.gvsig.tools.persistence.PersistenceFactory;
62
import org.gvsig.tools.persistence.PersistenceManager;
63
import org.gvsig.tools.persistence.PersistentContext;
64
import org.gvsig.tools.persistence.PersistentState;
65
import org.gvsig.tools.persistence.exception.PersistenceClassNotRegistered;
66
import org.gvsig.tools.persistence.exception.PersistenceException;
67
import org.gvsig.tools.persistence.exception.PersistenceRuntimeException;
68
import org.gvsig.tools.persistence.exception.PersistenceValidateExceptions;
69
import org.gvsig.tools.persistence.impl.exception.ObjectNotFoundException;
70
import org.gvsig.tools.persistence.impl.exception.PersistenceIDNotLoadedException;
71
import org.gvsig.tools.persistence.spi.PersistentContextServices;
72
import org.gvsig.tools.persistence.spi.PersistentIdentifier;
73
import org.gvsig.tools.persistence.spi.PersistentStateServices;
74
import org.slf4j.Logger;
75
import org.slf4j.LoggerFactory;
76

    
77
public class DefaultPersistentContext implements PersistentContextServices {
78

    
79
    private static Logger LOG = LoggerFactory.getLogger(DefaultPersistentContext.class);
80
    
81
        private Map idToReference;
82
        private Map objToReference;
83
        private PersistentIdentifier rootId;
84
        private PersistenceManager manager;
85
        private boolean collectErrors;
86
        private PersistenceException errors;
87
        private boolean validated;
88
  private MutableInt referenceCounter;
89

    
90
        public DefaultPersistentContext(PersistenceManager manager, MutableInt referenceCounter) {
91
                this.manager = manager;
92
                this.collectErrors = false;
93
                this.errors = null;
94
                this.validated = false;
95
    this.referenceCounter = referenceCounter;
96

    
97
                // Use LinkedHashMap for predictable order when save to a file
98
                this.idToReference = new LinkedHashMap(); 
99
                this.objToReference = new LinkedHashMap();
100
        }
101

    
102
        private class DefaultPersistentIdentifier implements PersistentIdentifier, Comparable {
103
                private String value;
104
                
105
                DefaultPersistentIdentifier(String value) {
106
                        this.value = value;
107
                }
108
                
109
//                String getValue() {
110
//                        return value;
111
//                }
112

    
113
                public boolean equals(Object obj) {
114
                        if (!(obj instanceof DefaultPersistentIdentifier)) {
115
                                return false;
116
                        }
117
                        return value == ((DefaultPersistentIdentifier) obj).value;
118
                }
119

    
120
                public boolean hasValue(Object value) {
121
                        return this.value.equals(value);
122
                }
123
                
124
                public int hashCode() {
125
                        return value.hashCode();
126
                }
127
                
128
                public String toString() {
129
                        return value;
130
                }
131

    
132
                public int compareTo(Object obj) {
133
                        if (!(obj instanceof DefaultPersistentIdentifier)) {
134
                                return -1;
135
                        }
136
                        return value.compareTo( ((DefaultPersistentIdentifier) obj).value) ;
137
                }
138
        }
139
        
140
        private class ContextValue implements ObjectReference, Comparable {
141
                private Object obj;
142
                private PersistentState state;
143
                private PersistentIdentifier id;
144
        private boolean isNullStateReported;
145

    
146
                ContextValue(PersistentIdentifier id, PersistentState state) {
147
                        this.id = id;
148
                        this.state = state;
149
                        this.obj = null;
150
            this.isNullStateReported = false;
151
        }
152
                
153
        @Override
154
                public boolean hasObject() {
155
                        return this.obj != null;
156
                }
157

    
158
        @Override
159
                public Object getObject() {
160
            if( this.state == null ) {
161
                if( !isNullStateReported ) {
162
                    try {
163
                        throw new IllegalArgumentException("The persistent storage may be corrupt. Can't have state for id '"+id+"'.");
164
                    } catch(Exception ex) {
165
                        this.getContext().addError(ex);
166
                        LOG.warn(ex.getMessage(), ex);
167
                    }
168
                    isNullStateReported = true;
169
                }
170
                return null;
171
            }
172
                        if( this.obj == null ) {
173
                                try {
174
                                        updateObjectInReference(this);
175
                                } catch (Exception e) {
176
                    if( this.getContext().getCollectErrors() ) {
177
                        this.getContext().addError(e);
178
                        LOG.warn(e.getMessage(), e);
179
                    } else {
180
                        throw new PersistenceRuntimeException(e);
181
                    }
182
                                }
183
                        }
184
                        return this.obj;
185
                }
186
                
187
        @Override
188
                public PersistentState getState() {
189
                        return this.state;
190
                }
191
                
192
        @Override
193
                public PersistentIdentifier getId() {
194
                        return this.id;
195
                }
196

    
197
                protected void update(Object object) {
198
                        this.obj = object;
199
                }
200
                
201
        @Override
202
                public boolean equals(Object obj) {
203
                        if (!(obj instanceof ContextValue)) {
204
                                return false;
205
                        }
206
                        return id.equals(((ContextValue) obj).id);
207
                }
208

    
209
        @Override
210
                public int hashCode() {
211
                        return id.hashCode();
212
                }
213
                
214
        @Override
215
                public String toString() {
216
                        String idStr = id == null ? "null" : id.toString();
217
                        return getClass().getName().concat(": id = ").concat(idStr);
218
                }
219

    
220
        @Override
221
                public int compareTo(Object arg0) {
222
                        if (!(obj instanceof ContextValue)) {
223
                                return -1;
224
                        }
225
                        return ((DefaultPersistentIdentifier)id).compareTo(((ContextValue) obj).id);
226
                }
227

    
228
        @Override
229
        public PersistentContext getContext() {
230
            return DefaultPersistentContext.this;
231
        }
232

    
233
        }
234

    
235
    @Override
236
        public PersistentIdentifier getNewIdentifier() {
237
                return new DefaultPersistentIdentifier(String.valueOf(referenceCounter.getAndIncrement()));
238
        }
239
        
240
    @Override
241
        public PersistentIdentifier getIdentifier(String id) throws PersistenceException {
242
                Iterator it = this.idToReference.values().iterator();
243
                while( it.hasNext() ) {
244
                        ContextValue value = (ContextValue) it.next();
245
                        if( ((DefaultPersistentIdentifier)(value.getId())).hasValue(id) ) {
246
                                return value.getId();
247
                        }
248
                }
249
                return new DefaultPersistentIdentifier(id);
250
        }
251
        
252
        public ObjectReference add(PersistentIdentifier id) throws PersistenceException  {
253
                this.validated = false;
254
                ContextValue value = (ContextValue) idToReference.get(id);
255
                if (value == null ) {
256
                        value = new ContextValue(id, null);
257
                        idToReference.put(value.getId(), value);
258
                }
259
                return value;
260
        }
261
        
262
        public ObjectReference add(PersistentState state, Object obj) throws PersistenceException  {
263
                this.validated = false;
264
                PersistentIdentifier id = ((PersistentStateServices)state).getId();
265
                ContextValue value = (ContextValue) idToReference.get(id);
266
                if (value == null ) {
267
                        value = new ContextValue( id, state);
268
                        idToReference.put(value.getId(), value);
269
                }
270
                if( value.getState() == null ) {
271
                        value.state = state;
272
                }
273
                if( obj != null ) {
274
                        value.update(obj);
275
                        objToReference.put(obj,value);
276
                }
277
                return value;
278
        }
279
        
280
        public ObjectReference get(PersistentState state) throws PersistenceException {
281
                PersistentIdentifier id = ((PersistentStateServices)state).getId();
282
                ContextValue ref = (ContextValue) idToReference.get(id);
283
                if (ref == null ) {
284
                        ref = new ContextValue(id, state);
285
                        idToReference.put(id, ref);
286
                }
287
                return ref;
288
        }
289

    
290
        public ObjectReference get(PersistentIdentifier id) {
291
                ContextValue value = (ContextValue) idToReference.get(id);
292
                return value;
293
        }
294
        
295
        public ObjectReference get(Object obj) {
296
                return (ContextValue) objToReference.get(obj);
297
        }
298
        
299
        private void updateObjectInReference(ContextValue ref) throws PersistenceException {
300
                /*
301
                 * Note: this method is used by the inner class Reference.
302
                 */
303
                PersistentStateServices state = (PersistentStateServices) ref.getState();
304
                PersistenceFactory factory = manager.getFactories().get(state);
305
                
306
                if (factory == null) {
307
                        /*
308
                         * This happens if persistence refers to objects
309
                         * of a missing plugin (example: persistence
310
                         * has data about oracle connections but we dont have
311
                         * the oracle plugin in the current execution)
312
                         */
313
                    String classname = "";
314
                    if (state == null) {
315
                        classname = "[State is null]";
316
                    } else {
317
                        classname = state.getTheClassName();
318
                        if (classname == null) {
319
                            classname = "[Null]";
320
                        }
321
                    }
322
                        throw new PersistenceClassNotRegistered(classname);
323
                }
324
                
325

    
326
                // This can be done in two step to avoid cyclic references
327
                state.setFactory(factory);
328
                ref.update( factory.createFromState(state) );
329
                factory.loadFromState(state, ref.getObject());
330
                
331
                objToReference.put(ref.getObject(), ref);
332
        }
333
        
334
        public void update(ObjectReference ref) throws PersistenceException {
335
                this.validated = false;
336
                this.updateObjectInReference((ContextValue) ref);
337
        }
338

    
339
        private void updateAll() throws PersistenceException {
340
                Iterator it = idToReference.entrySet().iterator();
341
                while ( it.hasNext() ) {
342
                        ContextValue ref = (ContextValue) ((Entry) it.next()).getValue();
343
                        this.update(ref);
344
                }
345
        }
346

    
347
        public void clear() {
348
                this.validated = false;
349
                Iterator it = idToReference.entrySet().iterator();
350
                while ( it.hasNext() ) {
351
                        ContextValue ref = (ContextValue) ((Entry) it.next()).getValue();
352
                        ref.update(null);
353
                }
354
        }
355

    
356
        public Iterator iterator() {
357
                final class StatesIterator implements Iterator {
358
                        private Iterator referenceIterator;
359

    
360
                        StatesIterator(Map idToReference) {
361
                                this.referenceIterator = idToReference.entrySet().iterator();
362
                        }
363
                        
364
//                        StatesIterator(Map idToReference) {
365
//                                List values = new ArrayList(); 
366
//                                values.addAll(idToReference.values());
367
//                                Collections.sort(values);
368
//                                this.referenceIterator = values.iterator();
369
//                        }
370
                        
371
                        public boolean hasNext() {
372
                                return referenceIterator.hasNext();
373
                        }
374
                        public Object next() {
375
                                ContextValue ref = (ContextValue) ((Entry) referenceIterator.next()).getValue();
376
//                                ContextValue ref = (ContextValue) referenceIterator.next();
377
                                return ref.getState();
378
                        }
379
                        public void remove() {
380
                                throw new UnsupportedOperationException();
381
                        }
382
                }
383
                
384
                return new StatesIterator(idToReference);
385
        }
386

    
387
        public PersistentState getState(Integer id)
388
                        throws PersistenceException {
389
                ContextValue ref = (ContextValue) this.get(id);
390
                if (ref == null) {
391
                        throw new PersistenceIDNotLoadedException(id);
392
                }
393
                return ref.getState();
394
        }
395

    
396
        public PersistentState getState(Object obj)
397
                        throws PersistenceException {
398
                ContextValue ref = (ContextValue) this.get(obj);
399
                if (ref == null) {
400
                        return null;
401
                }
402
                return ref.getState();
403
        }
404

    
405
        public Object getObject(Integer id) throws PersistenceException {
406
                ContextValue ref = (ContextValue) this.get(id);
407
                if (ref == null) {
408
                        throw new PersistenceIDNotLoadedException(id);
409
                }
410
                return ref.getObject();
411
        }
412

    
413
        public PersistentIdentifier getId(Object obj) throws PersistenceException {
414
                ContextValue ref = (ContextValue) this.get(obj);
415
                if( ref != null ) {
416
                        return ref.getId();
417
                }
418
                this.updateAll();
419
                ref = (ContextValue) this.get(obj);
420
                if (ref == null) {
421
                        throw new ObjectNotFoundException();
422
                }
423
                return ref.getId();                
424
        }
425

    
426

    
427
        public void setRootId(PersistentIdentifier id) {
428
                this.rootId = id;
429
        }
430

    
431
        public ObjectReference getRoot() throws PersistenceException {
432
                ObjectReference root = this.get(this.rootId); 
433
                return  root;
434
        }
435

    
436
        public void setCollectErrors(boolean collectErrors) {
437
                this.collectErrors = collectErrors;
438
        }
439

    
440
        public boolean getCollectErrors() {
441
                return this.collectErrors;
442
        }
443

    
444
        public void addError(Throwable cause) {
445
                if( this.errors == null ) {
446
                        this.errors = new PersistenceException();
447
                }
448
                this.errors.add(cause);
449
        }
450

    
451
        public PersistenceException getErrors() {
452
                return this.errors;
453
        }
454

    
455
        public void validate(int mode) throws PersistenceValidateExceptions {
456
                if( this.validated ) {
457
                        return;
458
                }
459
                List exceptions = new ArrayList();
460

    
461
                Iterator it = this.iterator();
462
                while( it.hasNext() ) {
463
                        PersistentState astate = (PersistentState) it.next();
464
                        try {
465
                                this.manager.validate(astate,mode);
466
                        } catch(Exception e) {
467
                                exceptions.add(e);
468
                        }
469
                }
470

    
471
                this.validated=true;
472
                if (exceptions.size() > 0) {
473
                        throw  new PersistenceValidateExceptions(exceptions);
474
                }                
475
        }
476
}