~ubuntu-branches/ubuntu/precise/libhibernate-jbosscache-java/precise

« back to all changes in this revision

Viewing changes to src/main/java/hibernate/cache/jbc/BasicRegionAdapter.java

  • Committer: Package Import Robot
  • Author(s): Brian Thomason, by sponsor Steffen Moeller
  • Date: 2011-12-26 00:23:47 UTC
  • mfrom: (1.1.1)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: package-import@ubuntu.com-20111226002347-r481ylr1w2dwdo1q
* First upload to Debian.
[ by sponsor Steffen Moeller ]
* Added Brian to uploaders and set DMUA flag
* Merged changes from 3.3.2.GA-1 to 3.3.2.GA-2  with Brian's work
* Omitted ".Final" from version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Hibernate, Relational Persistence for Idiomatic Java
 
3
 *
 
4
 * Copyright (c) 2007, Red Hat Middleware LLC or third-party contributors as
 
5
 * indicated by the @author tags or express copyright attribution
 
6
 * statements applied by the authors.  All third-party contributions are
 
7
 * distributed under license by Red Hat Middleware LLC.
 
8
 *
 
9
 * This copyrighted material is made available to anyone wishing to use, modify,
 
10
 * copy, or redistribute it subject to the terms and conditions of the GNU
 
11
 * Lesser General Public License, as published by the Free Software Foundation.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
15
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 
16
 * for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU Lesser General Public License
 
19
 * along with this distribution; if not, write to:
 
20
 * Free Software Foundation, Inc.
 
21
 * 51 Franklin Street, Fifth Floor
 
22
 * Boston, MA  02110-1301  USA
 
23
 */
 
24
package org.hibernate.cache.jbc;
 
25
 
 
26
import java.util.Collections;
 
27
import java.util.HashMap;
 
28
import java.util.HashSet;
 
29
import java.util.List;
 
30
import java.util.Map;
 
31
import java.util.Set;
 
32
import java.util.concurrent.atomic.AtomicReference;
 
33
 
 
34
import javax.transaction.SystemException;
 
35
import javax.transaction.Transaction;
 
36
import javax.transaction.TransactionManager;
 
37
 
 
38
import org.hibernate.cache.CacheException;
 
39
import org.hibernate.cache.Region;
 
40
import org.hibernate.cache.jbc.util.CacheHelper;
 
41
import org.hibernate.cache.jbc.util.NonLockingDataVersion;
 
42
import org.jboss.cache.Cache;
 
43
import org.jboss.cache.Fqn;
 
44
import org.jboss.cache.Node;
 
45
import org.jboss.cache.NodeSPI;
 
46
import org.jboss.cache.config.Configuration;
 
47
import org.jboss.cache.config.Option;
 
48
import org.jboss.cache.config.Configuration.NodeLockingScheme;
 
49
import org.jboss.cache.notifications.annotation.NodeInvalidated;
 
50
import org.jboss.cache.notifications.annotation.NodeModified;
 
51
import org.jboss.cache.notifications.annotation.ViewChanged;
 
52
import org.jboss.cache.notifications.event.NodeInvalidatedEvent;
 
53
import org.jboss.cache.notifications.event.NodeModifiedEvent;
 
54
import org.jboss.cache.notifications.event.ViewChangedEvent;
 
55
import org.jboss.cache.optimistic.DataVersion;
 
56
import org.slf4j.Logger;
 
57
import org.slf4j.LoggerFactory;
 
58
 
 
59
/**
 
60
 * General support for writing {@link Region} implementations for JBoss Cache
 
61
 * 2.x.
 
62
 * 
 
63
 * @author Steve Ebersole
 
64
 */
 
65
public abstract class BasicRegionAdapter implements Region {
 
66
   
 
67
    private enum InvalidateState { INVALID, CLEARING, VALID };
 
68
    
 
69
    public static final String ITEM = CacheHelper.ITEM;
 
70
 
 
71
    protected final Cache jbcCache;
 
72
    protected final String regionName;
 
73
    protected final Fqn regionFqn;
 
74
    protected final Fqn internalFqn;
 
75
    protected Node regionRoot;
 
76
    protected final boolean optimistic;
 
77
    protected final TransactionManager transactionManager;
 
78
    protected final Logger log;
 
79
    protected final Object regionRootMutex = new Object();
 
80
    protected final Object memberId;
 
81
    protected final boolean replication;
 
82
    protected final Object invalidationMutex = new Object();
 
83
    protected final AtomicReference<InvalidateState> invalidateState = 
 
84
       new AtomicReference<InvalidateState>(InvalidateState.VALID);
 
85
    protected final Set<Object> currentView = new HashSet<Object>();
 
86
 
 
87
//    protected RegionRootListener listener;
 
88
    
 
89
    public BasicRegionAdapter(Cache jbcCache, String regionName, String regionPrefix) {
 
90
 
 
91
        this.log = LoggerFactory.getLogger(getClass());
 
92
        
 
93
        this.jbcCache = jbcCache;
 
94
        this.transactionManager = jbcCache.getConfiguration().getRuntimeConfig().getTransactionManager();
 
95
        this.regionName = regionName;
 
96
        this.regionFqn = createRegionFqn(regionName, regionPrefix);
 
97
        this.internalFqn = CacheHelper.getInternalFqn(regionFqn);
 
98
        this.optimistic = jbcCache.getConfiguration().getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC;
 
99
        this.memberId = jbcCache.getLocalAddress();
 
100
        this.replication = CacheHelper.isClusteredReplication(jbcCache);
 
101
        
 
102
        this.jbcCache.addCacheListener(this);
 
103
        
 
104
        synchronized (currentView) {
 
105
           List view = jbcCache.getMembers();
 
106
           if (view != null) {
 
107
              currentView.addAll(view);
 
108
           }
 
109
        }
 
110
        
 
111
        activateLocalClusterNode();
 
112
        
 
113
        log.debug("Created Region for " + regionName + " -- regionPrefix is " + regionPrefix);
 
114
    }
 
115
 
 
116
    protected abstract Fqn<String> createRegionFqn(String regionName, String regionPrefix);
 
117
 
 
118
    protected void activateLocalClusterNode() {
 
119
       
 
120
        // Regions can get instantiated in the course of normal work (e.g.
 
121
        // a named query region will be created the first time the query is
 
122
        // executed), so suspend any ongoing tx
 
123
        Transaction tx = suspend();
 
124
        try {
 
125
            Configuration cfg = jbcCache.getConfiguration();
 
126
            if (cfg.isUseRegionBasedMarshalling()) {
 
127
                org.jboss.cache.Region jbcRegion = jbcCache.getRegion(regionFqn, true);
 
128
                ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
 
129
                if (classLoader == null) {
 
130
                    classLoader = getClass().getClassLoader();
 
131
                }
 
132
                jbcRegion.registerContextClassLoader(classLoader);
 
133
                if ( !jbcRegion.isActive() ) {
 
134
                    jbcRegion.activate();
 
135
                }
 
136
            }
 
137
            
 
138
//            // If we are using replication, we may remove the root node
 
139
//            // and then need to re-add it. In that case, the fact
 
140
//            // that it is resident will not replicate, so use a listener
 
141
//            // to set it as resident
 
142
//            if (CacheHelper.isClusteredReplication(cfg.getCacheMode()) 
 
143
//                  || CacheHelper.isClusteredInvalidation(cfg.getCacheMode())) {
 
144
//                listener = new RegionRootListener();
 
145
//                jbcCache.addCacheListener(listener);
 
146
//            }
 
147
            
 
148
            regionRoot = jbcCache.getRoot().getChild( regionFqn );
 
149
            if (regionRoot == null || !regionRoot.isValid()) {
 
150
               // Establish the region root node with a non-locking data version
 
151
               DataVersion version = optimistic ? NonLockingDataVersion.INSTANCE : null;
 
152
               regionRoot = CacheHelper.addNode(jbcCache, regionFqn, true, true, version);
 
153
            }
 
154
            else if (optimistic && regionRoot instanceof NodeSPI) {
 
155
                // FIXME Hacky workaround to JBCACHE-1202
 
156
                if ( !( ( ( NodeSPI ) regionRoot ).getVersion() instanceof NonLockingDataVersion ) ) {
 
157
                    ((NodeSPI) regionRoot).setVersion(NonLockingDataVersion.INSTANCE);
 
158
                }
 
159
            }
 
160
            if (!regionRoot.isResident()) {
 
161
               regionRoot.setResident(true);
 
162
            }
 
163
            establishInternalNodes();
 
164
        }
 
165
        catch (Exception e) {
 
166
            throw new CacheException(e.getMessage(), e);
 
167
        }
 
168
        finally {
 
169
            resume(tx);
 
170
        }
 
171
        
 
172
    }
 
173
 
 
174
    private void establishRegionRootNode()
 
175
    {
 
176
        synchronized (regionRootMutex) {
 
177
            // If we've been blocking for the mutex, perhaps another
 
178
            // thread has already reestablished the root.
 
179
            // In case the node was reestablised via replication, confirm it's 
 
180
            // marked "resident" (a status which doesn't replicate)
 
181
            if (regionRoot != null && regionRoot.isValid()) {
 
182
                return;
 
183
            }
 
184
            
 
185
            // For pessimistic locking, we just want to toss out our ref
 
186
            // to any old invalid root node and get the latest (may be null)            
 
187
            if (!optimistic) {
 
188
               establishInternalNodes();
 
189
               regionRoot = jbcCache.getRoot().getChild( regionFqn );
 
190
               return;
 
191
            }
 
192
            
 
193
            // The rest only matters for optimistic locking, where we
 
194
            // need to establish the proper data version on the region root
 
195
            
 
196
            // Don't hold a transactional lock for this 
 
197
            Transaction tx = suspend();
 
198
            Node newRoot = null;
 
199
            try {
 
200
                 // Make sure the root node for the region exists and 
 
201
                 // has a DataVersion that never complains
 
202
                 newRoot = jbcCache.getRoot().getChild( regionFqn );
 
203
                 if (newRoot == null || !newRoot.isValid()) {                
 
204
                     // Establish the region root node with a non-locking data version
 
205
                     DataVersion version = optimistic ? NonLockingDataVersion.INSTANCE : null;
 
206
                     newRoot = CacheHelper.addNode(jbcCache, regionFqn, true, true, version);    
 
207
                 }
 
208
                 else if (newRoot instanceof NodeSPI) {
 
209
                     // FIXME Hacky workaround to JBCACHE-1202
 
210
                     if ( !( ( ( NodeSPI ) newRoot ).getVersion() instanceof NonLockingDataVersion ) ) {
 
211
                          ((NodeSPI) newRoot).setVersion(NonLockingDataVersion.INSTANCE);
 
212
                     }
 
213
                 }
 
214
                 // Never evict this node
 
215
                 newRoot.setResident(true);
 
216
                 establishInternalNodes();
 
217
            }
 
218
            finally {
 
219
                resume(tx);
 
220
                regionRoot = newRoot;
 
221
            }
 
222
        }
 
223
    }
 
224
 
 
225
    private void establishInternalNodes()
 
226
    {
 
227
       synchronized (currentView) {
 
228
          Transaction tx = suspend();
 
229
          try {
 
230
             for (Object member : currentView) {
 
231
                DataVersion version = optimistic ? NonLockingDataVersion.INSTANCE : null;
 
232
                Fqn f = Fqn.fromRelativeElements(internalFqn, member);
 
233
                CacheHelper.addNode(jbcCache, f, true, false, version);
 
234
             }
 
235
          }
 
236
          finally {
 
237
             resume(tx);
 
238
          }
 
239
       }
 
240
       
 
241
    }
 
242
 
 
243
    public String getName() {
 
244
        return regionName;
 
245
    }
 
246
 
 
247
    public Cache getCacheInstance() {
 
248
        return jbcCache;
 
249
    }
 
250
 
 
251
    public Fqn getRegionFqn() {
 
252
        return regionFqn;
 
253
    }
 
254
    
 
255
    public Object getMemberId()
 
256
    {
 
257
       return this.memberId;
 
258
    }
 
259
    
 
260
    /**
 
261
     * Checks for the validity of the root cache node for this region,
 
262
     * creating a new one if it does not exist or is invalid, and also
 
263
     * ensuring that the root node is marked as resident.  Suspends any 
 
264
     * transaction while doing this to ensure no transactional locks are held 
 
265
     * on the region root.
 
266
     * 
 
267
     * TODO remove this once JBCACHE-1250 is resolved.
 
268
     */
 
269
    public void ensureRegionRootExists() {
 
270
       
 
271
       if (regionRoot == null || !regionRoot.isValid())
 
272
          establishRegionRootNode();
 
273
       
 
274
       // Fix up the resident flag
 
275
       if (regionRoot != null && regionRoot.isValid() && !regionRoot.isResident())
 
276
          regionRoot.setResident(true);
 
277
    }
 
278
    
 
279
    public boolean checkValid()
 
280
    {
 
281
       boolean valid = invalidateState.get() == InvalidateState.VALID;
 
282
       
 
283
       if (!valid) {
 
284
          synchronized (invalidationMutex) {
 
285
             if (invalidateState.compareAndSet(InvalidateState.INVALID, InvalidateState.CLEARING)) {
 
286
                Transaction tx = suspend();
 
287
                try {
 
288
                   Option opt = new Option();
 
289
                   opt.setLockAcquisitionTimeout(1);
 
290
                   opt.setCacheModeLocal(true);
 
291
                   CacheHelper.removeAll(jbcCache, regionFqn, opt);
 
292
                   invalidateState.compareAndSet(InvalidateState.CLEARING, InvalidateState.VALID);
 
293
                }
 
294
                catch (Exception e) {
 
295
                   if (log.isTraceEnabled()) {
 
296
                      log.trace("Could not invalidate region: " + e.getLocalizedMessage());
 
297
                   }
 
298
                }
 
299
                finally {
 
300
                   resume(tx);
 
301
                }
 
302
             }
 
303
          }
 
304
          valid = invalidateState.get() == InvalidateState.VALID;
 
305
       }
 
306
       
 
307
       return valid;   
 
308
    }
 
309
 
 
310
    public void destroy() throws CacheException {
 
311
        try {
 
312
            // NOTE : this is being used from the process of shutting down a
 
313
            // SessionFactory. Specific things to consider:
 
314
            // (1) this clearing of the region should not propagate to
 
315
            // other nodes on the cluster (if any); this is the
 
316
            // cache-mode-local option bit...
 
317
            // (2) really just trying a best effort to cleanup after
 
318
            // ourselves; lock failures, etc are not critical here;
 
319
            // this is the fail-silently option bit...
 
320
            Option option = new Option();
 
321
            option.setCacheModeLocal(true);
 
322
            option.setFailSilently(true);
 
323
            if (optimistic) {
 
324
                option.setDataVersion(NonLockingDataVersion.INSTANCE);
 
325
            }
 
326
            jbcCache.getInvocationContext().setOptionOverrides(option);
 
327
            jbcCache.removeNode(regionFqn);
 
328
            deactivateLocalNode();            
 
329
        } catch (Exception e) {
 
330
            throw new CacheException(e);
 
331
        }
 
332
        finally {
 
333
            jbcCache.removeCacheListener(this);
 
334
        }
 
335
    }
 
336
 
 
337
    protected void deactivateLocalNode() {
 
338
        org.jboss.cache.Region jbcRegion = jbcCache.getRegion(regionFqn, false);
 
339
        if (jbcRegion != null && jbcRegion.isActive()) {
 
340
            jbcRegion.deactivate();
 
341
            jbcRegion.unregisterContextClassLoader();
 
342
        }
 
343
    }
 
344
 
 
345
        public boolean contains(Object key) {
 
346
                if ( !checkValid() ) {
 
347
                        return false;
 
348
                }
 
349
 
 
350
                try {
 
351
                        Option opt = new Option();
 
352
            opt.setLockAcquisitionTimeout(100);
 
353
            CacheHelper.setInvocationOption( jbcCache, opt );
 
354
                        return CacheHelper.getAllowingTimeout( jbcCache, regionFqn, key ) != null;
 
355
                }
 
356
                catch ( CacheException ce ) {
 
357
                        throw ce;
 
358
                }
 
359
                catch ( Throwable t ) {
 
360
                        throw new CacheException( t );
 
361
                }
 
362
        }
 
363
 
 
364
    public long getSizeInMemory() {
 
365
        // not supported
 
366
        return -1;
 
367
    }
 
368
 
 
369
    public long getElementCountInMemory() {
 
370
        if (checkValid()) {
 
371
           try {
 
372
               Set childrenNames = CacheHelper.getChildrenNames(jbcCache, regionFqn);
 
373
               int size = childrenNames.size();
 
374
               if (childrenNames.contains(CacheHelper.Internal.NODE)) {
 
375
                  size--;
 
376
               }
 
377
               return size;
 
378
           }
 
379
                   catch ( CacheException ce ) {
 
380
                           throw ce;
 
381
                   }
 
382
                   catch (Exception e) {
 
383
               throw new CacheException(e);
 
384
           }
 
385
        }
 
386
        else {
 
387
           return 0;
 
388
        }           
 
389
    }
 
390
 
 
391
    public long getElementCountOnDisk() {
 
392
        return -1;
 
393
    }
 
394
 
 
395
    public Map toMap() {
 
396
        if (checkValid()) {
 
397
           try {
 
398
               Map result = new HashMap();
 
399
               Set childrenNames = CacheHelper.getChildrenNames(jbcCache, regionFqn);
 
400
               for (Object childName : childrenNames) {
 
401
                   if (CacheHelper.Internal.NODE != childName) {
 
402
                      result.put(childName, CacheHelper.get(jbcCache,regionFqn, childName));
 
403
                   }
 
404
               }
 
405
               return result;
 
406
           } catch (CacheException e) {
 
407
               throw e;
 
408
           } catch (Exception e) {
 
409
               throw new CacheException(e);
 
410
           }
 
411
        }
 
412
        else {
 
413
           return Collections.emptyMap();
 
414
        }
 
415
    }
 
416
 
 
417
    public long nextTimestamp() {
 
418
        return System.currentTimeMillis() / 100;
 
419
    }
 
420
 
 
421
    public int getTimeout() {
 
422
        return 600; // 60 seconds
 
423
    }
 
424
 
 
425
    /**
 
426
     * Performs a JBoss Cache <code>get(Fqn, Object)</code> after first
 
427
     * {@link #suspend suspending any ongoing transaction}. Wraps any exception
 
428
     * in a {@link CacheException}. Ensures any ongoing transaction is resumed.
 
429
     * 
 
430
     * @param key The key of the item to get
 
431
     * @param opt any option to add to the get invocation. May be <code>null</code>
 
432
     * @param suppressTimeout should any TimeoutException be suppressed?
 
433
     * @return The retrieved object
 
434
         * @throws CacheException issue managing transaction or talking to cache
 
435
     */
 
436
    protected Object suspendAndGet(Object key, Option opt, boolean suppressTimeout) throws CacheException {
 
437
        Transaction tx = suspend();
 
438
        try {
 
439
            CacheHelper.setInvocationOption(getCacheInstance(), opt);
 
440
            if (suppressTimeout)
 
441
                return CacheHelper.getAllowingTimeout(getCacheInstance(), getRegionFqn(), key);
 
442
            else
 
443
                return CacheHelper.get(getCacheInstance(), getRegionFqn(), key);
 
444
        } finally {
 
445
            resume(tx);
 
446
        }
 
447
    }
 
448
 
 
449
    /**
 
450
     * Tell the TransactionManager to suspend any ongoing transaction.
 
451
     * 
 
452
     * @return the transaction that was suspended, or <code>null</code> if
 
453
     *         there wasn't one
 
454
     */
 
455
    public Transaction suspend() {
 
456
        Transaction tx = null;
 
457
        try {
 
458
            if (transactionManager != null) {
 
459
                tx = transactionManager.suspend();
 
460
            }
 
461
        } catch (SystemException se) {
 
462
            throw new CacheException("Could not suspend transaction", se);
 
463
        }
 
464
        return tx;
 
465
    }
 
466
 
 
467
    /**
 
468
     * Tell the TransactionManager to resume the given transaction
 
469
     * 
 
470
     * @param tx
 
471
     *            the transaction to suspend. May be <code>null</code>.
 
472
     */
 
473
    public void resume(Transaction tx) {
 
474
        try {
 
475
            if (tx != null)
 
476
                transactionManager.resume(tx);
 
477
        } catch (Exception e) {
 
478
            throw new CacheException("Could not resume transaction", e);
 
479
        }
 
480
    }
 
481
 
 
482
    /**
 
483
     * Get an Option with a {@link Option#getDataVersion() data version}
 
484
     * of {@link NonLockingDataVersion}.  The data version will not be 
 
485
     * set if the cache is not configured for optimistic locking.
 
486
     * 
 
487
     * @param allowNullReturn If <code>true</code>, return <code>null</code>
 
488
     *                        if the cache is not using optimistic locking.
 
489
     *                        If <code>false</code>, return a default
 
490
     *                        {@link Option}.
 
491
     *                        
 
492
     * @return the Option, or <code>null</code>.
 
493
     */
 
494
    protected Option getNonLockingDataVersionOption(boolean allowNullReturn) {
 
495
        return optimistic ? NonLockingDataVersion.getInvocationOption() 
 
496
                          : (allowNullReturn) ? null : new Option();
 
497
    }
 
498
 
 
499
    public static Fqn<String> getTypeFirstRegionFqn(String regionName, String regionPrefix, String regionType) {
 
500
        Fqn<String> base = Fqn.fromString(regionType);
 
501
        Fqn<String> added = Fqn.fromString(escapeRegionName(regionName, regionPrefix));
 
502
        return new Fqn<String>(base, added);
 
503
    }
 
504
 
 
505
    public static Fqn<String> getTypeLastRegionFqn(String regionName, String regionPrefix, String regionType) {
 
506
        Fqn<String> base = Fqn.fromString(escapeRegionName(regionName, regionPrefix));
 
507
        return new Fqn<String>(base, regionType);
 
508
    }
 
509
 
 
510
    public static String escapeRegionName(String regionName, String regionPrefix) {
 
511
        String escaped = null;
 
512
        int idx = -1;
 
513
        if (regionPrefix != null) {
 
514
            idx = regionName.indexOf(regionPrefix);
 
515
        }
 
516
 
 
517
        if (idx > -1) {
 
518
            int regionEnd = idx + regionPrefix.length();
 
519
            String prefix = regionName.substring(0, regionEnd);
 
520
            String suffix = regionName.substring(regionEnd);
 
521
            suffix = suffix.replace('.', '/');
 
522
            escaped = prefix + suffix;
 
523
        } else {
 
524
            escaped = regionName.replace('.', '/');
 
525
            if (regionPrefix != null && regionPrefix.length() > 0) {
 
526
                escaped = regionPrefix + "/" + escaped;
 
527
            }
 
528
        }
 
529
        return escaped;
 
530
    }
 
531
    
 
532
    @NodeModified
 
533
    public void nodeModified(NodeModifiedEvent event)
 
534
    {
 
535
       handleEvictAllModification(event);
 
536
    }
 
537
    
 
538
    protected boolean handleEvictAllModification(NodeModifiedEvent event) {
 
539
       
 
540
       if (!event.isPre() && (replication || event.isOriginLocal()) && event.getData().containsKey(ITEM))
 
541
       {
 
542
          if (event.getFqn().isChildOf(internalFqn))
 
543
          {
 
544
             invalidateState.set(InvalidateState.INVALID);
 
545
             return true;
 
546
          }
 
547
       }
 
548
       return false;       
 
549
    }
 
550
    
 
551
    @NodeInvalidated
 
552
    public void nodeInvalidated(NodeInvalidatedEvent event)
 
553
    {
 
554
       handleEvictAllInvalidation(event);
 
555
    }
 
556
    
 
557
    protected boolean handleEvictAllInvalidation(NodeInvalidatedEvent event)
 
558
    {
 
559
       if (!event.isPre() && event.getFqn().isChildOf(internalFqn))
 
560
       {
 
561
          invalidateState.set(InvalidateState.INVALID);
 
562
          return true;
 
563
       }      
 
564
       return false;
 
565
    }
 
566
    
 
567
    @ViewChanged
 
568
    public void viewChanged(ViewChangedEvent event) {
 
569
       
 
570
       synchronized (currentView) {
 
571
          List view = event.getNewView().getMembers();
 
572
          if (view != null) {
 
573
             currentView.addAll(view);
 
574
             establishInternalNodes();
 
575
          }
 
576
       }
 
577
       
 
578
    }
 
579
   
 
580
}