Click here to Skip to main content
15,894,410 members
Articles / Database Development / SQL Server

A Fairly Capable Authorization Sub-System with Row-Level Security Capabilities (AFCAS)

Rate me:
Please Sign up or sign in to vote.
4.84/5 (23 votes)
12 Feb 2009LGPL325 min read 102.1K   1.1K   78  
An implementation of role-based authorization control (RBAC) model with row-level access control capabilities at the database server level
#region copyright

// Copyright (C) 2008 Kemal ERDOGAN
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, version 3 of the License.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#endregion

namespace Afcas.Base {
    using System;
    using System.Collections.Generic;
    using System.Threading;
    using Utils;

    /// <summary>
    /// A cache for objects to store them for the duration of a logical transaction.
    /// This class is NOT thread-safe!
    /// </summary>
    public class ObjectCache: IDisposable {
        private readonly IDictionary< Type, IDictionary< string, object > > _CacheCache;

        private object _SyncRoot;

        public ObjectCache( ) {
            _CacheCache = new Dictionary< Type, IDictionary< string, object > >( );
        }

        private object SyncRoot {
            get {
                Interlocked.CompareExchange( ref _SyncRoot, new object( ), null );
                return _SyncRoot;
            }
        }


        internal static Stack< ObjectCache > CacheStack {
            get {
                LocalDataStoreSlot ds = Thread.GetNamedDataSlot( "ObjectCache.CacheStack" );
                Stack< ObjectCache > stack = Thread.GetData( ds ) as Stack< ObjectCache >;
                if( stack == null ) {
                    stack = new Stack< ObjectCache >( );
                    Thread.SetData( ds, stack );
                }
                return stack;
            }
        }

        public static ObjectCache Current {
            get {
                Stack< ObjectCache > stack = CacheStack;
                if( stack.Count == 0 ) {
                    ObjectCache res = new ObjectCache( );
                    stack.Push( res );
                }

                return stack.Peek( );
            }
        }

        #region IDisposable Members

        public void Dispose( ) {
            Dispose( true );
            GC.SuppressFinalize( this );
        }

        #endregion

        protected virtual void Dispose( bool shouldClean ) {
            _CacheCache.Clear( );
        }

        private IDictionary< string, object > GetCache< T >( ) {
            lock( SyncRoot ) {
                IDictionary< string, object > cache;
                if( !_CacheCache.TryGetValue( typeof( T ), out cache ) ) {
                    cache = new Dictionary< string, object >( );
                    _CacheCache.Add( typeof( T ), cache );
                }
                return cache;
            }
        }

        private T PutOrUpdateExisting< T >( T element, bool throwIfExists ) where T: AbstractKeyedNamed< T > {
            IDictionary< string, object > cache;
            lock( cache = GetCache< T >( ) ) {
                T elem = element;
                object res;
                if( cache.TryGetValue( element.Key, out res ) ) {
                    if( !ReferenceEquals( res, element ) ) {
                        if( throwIfExists ) {
                            throw new ArgumentException( "Identical objects with different memory references deteched" );
                        }
                        elem = ( T )res;
                        elem.CopyFrom( element );
                    }
                } else {
                    cache.Add( element.Key, element );
                }
                return elem;
            }
        }


        public static void PushCurrent( ObjectCache cache ) {
            if( cache == null ) {
                throw new ArgumentNullException( "cache" );
            }
            CacheStack.Push( cache );
        }

        public static void PopCurrent( ) {
            if( CacheStack.Count == 0 ) {
                throw new InvalidProgramException( "No current ObjectCache set" );
            }
            CacheStack.Pop( );
        }

        public void Complete( ) {
            //currently noop
        }

        public void Put< T >( T element ) where T: AbstractKeyedNamed< T > {
            PutOrUpdateExisting( element, true );
        }

        public T PutOrUpdate< T >( T element ) where T: AbstractKeyedNamed< T > {
            return PutOrUpdateExisting( element, false );
        }

        public T Get< T >( string key ) where T: AbstractKeyedNamed< T > {
            IDictionary< string, object > cache;
            lock( cache = GetCache< T >( ) ) {
                object res;
                if( cache.TryGetValue( key, out res ) ) {
                    return ( T )res;
                }
                return default( T );
            }
        }

        public bool Remove< T >( string id ) where T: AbstractKeyedNamed< T > {
            IDictionary< string, object > cache;
            lock( cache = GetCache< T >( ) ) {
                return cache.Remove( id );
            }
        }

        public IList< T > GetAll< T >( ) {
            IDictionary< string, object > cache;
            lock( cache = GetCache< T >( ) ) {
                List< T > res = new List< T >( cache.Count );
                foreach( T elem in cache.Values ) {
                    res.Add( elem );
                }
                return res;
            }
        }

        public IEnumerator< T > GetEnumerator< T >( ) where T: AbstractKeyedNamed< T > {
            return new EnumeratorWrapper< T >( GetCache< T >( ).Values.GetEnumerator( ) );
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
France France
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions