///
/// Copyright © 2003-2008 JetBrains s.r.o.
/// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder).
///
using System;
using System.Collections;
using System.Threading;
using JetBrains.DataStructures;
using JetBrains.Omea.OpenAPI;
namespace JetBrains.Omea.ResourceStore
{
internal interface IUpdateListener
{
void ResourceSaved( IResource resource, IPropertyChangeSet changeSet );
void ResourceDeleting( IResource resource );
void Trace();
int GetKnownType();
}
///
/// Class which manages updating live resource lists.
///
internal class ResourceListUpdateManager
{
private IntHashTable _typedUpdateListeners = new IntHashTable(); // >>
private ArrayList _untypedUpdateListeners = new ArrayList(); // >
private ArrayList _priorityUpdateListeners = new ArrayList(); // >
private ArrayList _allUpdateListeners = new ArrayList();
private int _reentryLevel = 0;
public void AddUpdateListener( IUpdateListener listener, bool priority )
{
int knownType = listener.GetKnownType();
if ( knownType >= 0 )
{
ArrayList list;
lock( _typedUpdateListeners )
{
list = (ArrayList) _typedUpdateListeners [knownType];
if ( list == null )
{
list = new ArrayList();
_typedUpdateListeners [knownType] = list;
}
}
lock( list )
{
list.Add( new WeakReference( listener ) );
}
}
else if ( priority )
{
lock( _priorityUpdateListeners )
{
_priorityUpdateListeners.Add( new WeakReference( listener ) );
}
}
else
{
lock( _untypedUpdateListeners )
{
_untypedUpdateListeners.Add( new WeakReference( listener ) );
}
}
lock( _allUpdateListeners )
{
_allUpdateListeners.Add( new WeakReference( listener ) );
}
}
public void RemoveUpdateListener( IUpdateListener listener, bool priority )
{
int knownType = listener.GetKnownType();
if ( knownType >= 0 )
{
ArrayList list;
lock( _typedUpdateListeners )
{
list = (ArrayList) _typedUpdateListeners [knownType];
}
if ( list != null )
{
lock( list )
{
RemoveUpdateListenerFromList( list, listener );
}
}
}
else if ( priority )
{
lock( _priorityUpdateListeners )
{
RemoveUpdateListenerFromList( _untypedUpdateListeners, listener );
}
}
else
{
lock( _untypedUpdateListeners )
{
RemoveUpdateListenerFromList( _untypedUpdateListeners, listener );
}
}
lock( _allUpdateListeners )
{
RemoveUpdateListenerFromList( _allUpdateListeners, listener );
}
CompactList( _allUpdateListeners );
}
private void RemoveUpdateListenerFromList( ArrayList list, IUpdateListener listener )
{
for( int i=list.Count-1; i >= 0; i-- )
{
WeakReference weakRef = (WeakReference) list [i];
if ( weakRef.IsAlive && weakRef.Target == listener )
{
weakRef.Target = null;
}
}
}
public int ListenerCount
{
get { return _allUpdateListeners.Count; }
}
public void NotifyResourceSaved( IResource resource, IPropertyChangeSet changeSet )
{
Interlocked.Increment( ref _reentryLevel );
ArrayList list;
lock( _typedUpdateListeners )
{
list = (ArrayList) _typedUpdateListeners [resource.TypeId];
}
if ( list != null )
{
NotifyList( list, resource, changeSet, false );
}
if ( changeSet != null && changeSet.IsPropertyChanged( ResourceProps.Type ) )
{
int oldType = (int) changeSet.GetOldValue( ResourceProps.Type );
lock( _typedUpdateListeners )
{
list = (ArrayList) _typedUpdateListeners [oldType];
}
if ( list != null )
{
NotifyList( list, resource, changeSet, false );
}
}
NotifyList( _priorityUpdateListeners, resource, changeSet, false );
NotifyList( _untypedUpdateListeners, resource, changeSet, false );
Interlocked.Decrement( ref _reentryLevel );
}
public void NotifyResourceDeleting( IResource resource )
{
Interlocked.Increment( ref _reentryLevel );
ArrayList list;
lock( _typedUpdateListeners )
{
list = (ArrayList) _typedUpdateListeners [resource.TypeId];
}
if ( list != null )
{
NotifyList( list, resource, null, true );
}
NotifyList( _priorityUpdateListeners, resource, null, true );
NotifyList( _untypedUpdateListeners, resource, null, true );
Interlocked.Decrement( ref _reentryLevel );
}
private void NotifyList( ArrayList list, IResource resource, IPropertyChangeSet changeSet, bool deleting )
{
bool needCompact = false;
int startCount = list.Count;
for( int index=0; index= 0; i-- )
{
WeakReference weakRef = (WeakReference) list [i];
if ( !weakRef.IsAlive || weakRef.Target == null )
{
list.RemoveAt( i );
}
}
}
}
public void TraceListeners()
{
for( int i=_allUpdateListeners.Count-1; i >= 0; i-- )
{
WeakReference weakRef = (WeakReference) _allUpdateListeners [i];
if ( !weakRef.IsAlive )
{
_allUpdateListeners.RemoveAt( i );
}
else
{
(weakRef.Target as IUpdateListener).Trace();
}
}
}
}
}