1  //!-- UTF8
     2  /*
     3   Oregano Multiuser Server - Version 1.2.0 - January 4th, 2005
     4   
     5  	Web:  www.oregano-server.org
     6  	Mail: info@oregano-server.org
     7   
     8  	Copyright 2003 - 2004 - 2004 Jens Halm / Cologne, Germany
     9   
    10   This library is free software; you can redistribute it and/or
    11   modify it under the terms of the GNU Lesser General Public
    12   License as published by the Free Software Foundation; either
    13   version 2.1 of the License, or (at your option) any later version.
    14   
    15   This library is distributed in the hope that it will be useful,
    16   but WITHOUT ANY WARRANTY; without even the implied warranty of
    17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    18   Lesser General Public License for more details.
    19   
    20   You should have received a copy of the GNU Lesser General Public
    21   License along with this library; if not, write to the Free Software
    22   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    23  */
    24  
    25  /*
    26   -------------------------------------------
    27  	Classe Locks
    28   
    29  	@description :
    30  	Gestion des verrous de prorpiétés dans un groupe.
    31   
    32   
    33  	@author Jens Halm copyright http://www.spicefactory.org/
    34  	@author erixtekila copyleft http://www.v-i-a.net  
    35   -------------------------------------------
    36  	version history :
    37  	1.2.0 : 04/02/05
    38  			- Portage en actionscript 2 pour le
    39  			compile time type checking
    40   -------------------------------------------
    41   */
    42  
    43  import org.omus.util.EventDispatcher;
    44  import org.omus.util.iObservable;
    45  import org.omus.util._Error;
    46  import org.omus.util._Class;
    47  
    48  import org.omus.msg.EnvelopeFactory;
    49  import org.omus.msg.Envelope;
    50  import org.omus.msg.Message;
    51  
    52  import org.omus.core.Session;
    53  
    54  /**
    55   *	Cette classe gère des verrous sur certaines propriétés comprises dans une groupe.
    56   *	<p>
    57   *	Evénements auxquels s'abonner :
    58   *	<ul>
    59   *	<li>onAcquire(lockName:String, success:Boolean)		Généré lorsq'une demande de gestion de verrou est effectuée.
    60   *															_param loockName		Nom du verrou.
    61   *															_param success			true pour accepté, false pour refusé.
    62   *	</li><li>onRelease(lockName:String)						Généré lorsqu'un verrou est dévérouillé.
    63   *															_param lockName			Nom du verrou.
    64   *	</li><li>onReleaseAll										Généré lorsque tous les verrous sont ouverts.
    65   *	</li><li>onError(error:_Error)								Généré à cause d'une mauvaise modification de propriété persistante.
    66   *	</li></ul></p>
    67   *	Elle est aggrémentée par composition des méthodes des sources d'événements (EventDispatcher).
    68   *	@see org.omus.util.EventDispatcher
    69   *	@see org.omus.util.iObservable
    70   *
    71   *	@author Jens Halm copyright http://www.spicefactory.org/
    72   *	@author erixtekila copyleft http://www.v-i-a.net 
    73   *	@version 1.2.0
    74   */
    75  class org.omus.core.Locks implements iObservable
    76  {
    77  	//--------------------
    78  	// PROPRIETES
    79  	//--------------------
    80  	/**
    81  	 *	Liste des noms de verrous.
    82  	 */
    83  	private var lockNames:Array;
    84  	
    85  	/**
    86  	 *	Référence au système de génération d'événements.
    87  	 */
    88  	private var _eventSource:EventDispatcher;
    89  	
    90  	//--------------------
    91  	// CONSTRUCTEUR
    92  	//--------------------
    93  	/**
    94  	 *	L'objet Locks dispose des méthodes d'EventDispatcher par composition.
    95  	 *	
    96  	 */
    97  	public function Locks()
    98  	{		
    99  		// Composition avec EventDispatcher
   100  		_eventSource = new EventDispatcher();
   101  		
   102  		// Propriétés
   103  		lockNames = new Array();
   104  
   105  		// trace(this+ " installé.");
   106  	}
   107  	
   108  	
   109  	//--------------------
   110  	// METHODES PUBLIQUES
   111  	//--------------------
   112  	/**
   113  	 *	Utilisé dans un contexte littéral
   114  	 *	@return	Une chaine définissant l'objet
   115  	 */
   116  	public function toString():String
   117  	{
   118  		return "[Objet Locks]\norg.omus.Locks: number of acquired locks = " + lockNames.length;
   119  	}
   120  	
   121  	/**
   122  	 *	Supprime tous les verrous.
   123  	 */
   124  	public function reset ():Void
   125  	{
   126  		this.lockNames = new Array();
   127  	}
   128  	
   129  	/**
   130  	 *	Tente d'obtenir le droit sur une propriété protégée par verrou.
   131  	 *
   132  	 *	@param lockName			Nom du verrou.
   133  	 */
   134  	public function acquire (lockName:String):Void
   135  	{
   136  		// TODO : Accès Singleton.
   137  		var clazz = _Class.getInstance();
   138  		var envFactory = EnvelopeFactory.getInstance();
   139  		var session = Session.getInstance();
   140  		
   141  		if (! clazz.checkArguments("org.omus.core.Locks.acquire", [[lockName, "string", true]])) return;
   142  		var env = envFactory.getOutgoing(new Message(lockName),"locks.acq");
   143  		session.sendMessage(env);
   144  	}
   145  	
   146  	/**
   147  	 *	Déverouille un verrou.
   148  	 *
   149  	 *	@param lockName			Nom du verrou.
   150  	 */
   151  	public function release (lockName:String):Void
   152  	{
   153  		// TODO : Accès Singleton.
   154  		var clazz = _Class.getInstance();
   155  		var envFactory = EnvelopeFactory.getInstance();
   156  		var session = Session.getInstance();
   157  		
   158  		if (! clazz.checkArguments("org.omus.core.Locks.release", [[lockName, "string", true]])) return;
   159  		var env = envFactory.getOutgoing(new Message(lockName), "locks.rel");
   160  		session.sendMessage(env);
   161  	}
   162  	
   163  	/**
   164  	 *	Déverouille tous les verrous.
   165  	 */
   166  	public function releaseAll ():Void
   167  	{
   168  		// TODO : Accès Singleton.
   169  		var envFactory = EnvelopeFactory.getInstance();
   170  		var session = Session.getInstance();
   171  		
   172  		var env = envFactory.getOutgoing(new Message(""), "locks.relAll");
   173  		session.sendMessage(env);
   174  	}
   175  	
   176  	/**
   177  	 *	Averti si un verrou a été déposé par un autre utilisateur.
   178  	 *
   179  	 *	@param lockName		Nom du verrou.
   180  	 *	@return				true si un verrou est déjà apposé.
   181  	 */
   182  	public function isAcquired (lockName:String):Boolean
   183  	{
   184  		// TODO : Accès Singleton.
   185  		var clazz = _Class.getInstance();
   186  		var envFactory = EnvelopeFactory.getInstance();
   187  		var session = Session.getInstance();
   188  		
   189  		if (clazz.checkArguments("org.omus.core.Locks.isAcquired", [[lockName, "string", true]]))
   190  		{
   191  			var l = lockNames;
   192  			var c = l.length;
   193  			for (var i = 0; i < c; i++)
   194  			{
   195  				if (l[i] == lockName) return true;
   196  			}
   197  			return false;
   198  		}
   199  	}
   200  	
   201  	/**
   202  	 *	Renvoie une liste de tous les verrous actuellement posé par le client.
   203  	 */
   204  	public function getAllAcquired ():Array
   205  	{
   206  		return lockNames.slice(0, lockNames.length);
   207  	}
   208  	
   209  	//*** Implémentation de iObservable ***\
   210  	/**
   211  	 *	Notifie les observateurs d'un événement.
   212  	 *
   213  	 *	@param logLevel Une chaine caractérisant le niveau de logging de l'information.
   214  	 *	@param eventName Nom de l'événement.
   215  	 *	@param arg1		[option] Autant de paramêtres de voulu.
   216  	 */
   217  	private function fireEvent (logLevel:String, eventName:String):Void
   218  	{
   219  		_eventSource.fireEvent.apply (_eventSource, arguments);
   220  	}
   221  	
   222  	/**
   223  	 *	Ajoute un nouvel observateur.
   224  	 * 
   225  	 *	@param		listener Référence de l'observateur.
   226  	 *	@return Un booléen indiquant la réussite de l'opération.
   227  	 */
   228  	public function addListener (listener:Object):Boolean
   229  	{
   230  		return _eventSource.addListener(listener);
   231  	}
   232  	
   233  	/**
   234  	 *	Supprime un observateur.
   235  	 *
   236  	 *	@param		listener Référence de l'observateur.
   237  	 *	@return Un booléen indiquant la réussite de l'opération.
   238  	 */
   239  	public function removeListener (listener:Object):Boolean
   240  	{
   241  		return _eventSource.removeListener(listener);
   242  	}
   243  	
   244  	/**
   245  	 *	Supprime tous les abonnés.
   246  	 */
   247  	public function removeAllListeners ():Void
   248  	{
   249  		_eventSource.removeAllListeners();
   250  	}
   251  	
   252  	/**
   253  	 *	Retourne le nombre d'observateurs.
   254  	 *
   255  	 *	@return Le nombre d'observateurs enregistrés.
   256  	 */
   257  	public function countListeners ():Number
   258  	{
   259  		return _eventSource.countListeners();
   260  	}
   261  	
   262  	//*** Gestionnaire des accusés de réception ***\\
   263  	// TODO : Implémenter iMessageHandler ?
   264  	/*
   265  	 *	Gestionnaire de l'accusé de réception de tous les messages serveur.
   266  	 *	Génère un événement onAcquire, onRelease, onReleaseAll ou onError aux observateurs.
   267  	 *
   268  	 *	@param env		Enveloppe du message retourné.
   269  	 */
   270  	public function handleMessage (env:Envelope):Void
   271  	{
   272  		var type = env.getType();
   273  		var msg = env.getMessage();
   274  		var lockName = msg.getSubject();
   275  		var errCode = msg.getAttachment().error;
   276  		if (errCode == "ok")
   277  		{
   278  			if (type == "locks.acq")
   279  			{
   280  				var idx = indexOf(lockName);
   281  				if (idx == -1) lockNames.push(lockName);
   282  				// Broadcsat
   283  				fireEvent("info", "onAcquire", lockName, true);
   284  			} else 
   285  			{
   286  				if (type == "locks.rel") 
   287  				{
   288  					var idx = indexOf(lockName);
   289  					//!! TODO : Syntaxe. if (idx != -1) l.splice(idx, 1);
   290  					if (idx != -1) lockNames.splice(idx, 1);
   291  					// Broadcast
   292  					fireEvent("info", "onRelease", lockName);
   293  				} else 
   294  				{
   295  					var evtName = "onReleaseAll";
   296  					lockNames = new Array();
   297  					// Broadcast
   298  					fireEvent("info", "onReleaseAll");
   299  				}
   300  			}
   301  		} else 
   302  		{
   303  			var method = (type == "locks.acq") ? "acquire" : (type == "locks.rel") ? "release" : "releaseAll" ;
   304  			if (method == "acquire" && errCode == "grp-002")
   305  			{
   306  				// Broadcast
   307  				fireEvent("info", "onAcquire", lockName, false);
   308  			} else 
   309  			{
   310  				var args = (type == "locks.relAll") ? new Array() : [lockName] ;
   311  				// Broadcast
   312  				fireEvent("error","onError",new _Error(errCode, method, args));
   313  			}
   314  		}
   315  	}
   316  	
   317  		
   318  	
   319  	//--------------------
   320  	// METHODES PRIVEES
   321  	//--------------------
   322  	/**
   323  	 *	Retourne l'indice d'un verrou dans la liste
   324  	 *
   325  	 *	@param lockName		Nom du verrou.
   326  	 *	@return				L'indice du verrou ou -1 s'il n'existe pas.
   327  	 */
   328  	private function indexOf (lockName:String):Number {
   329  		var l = lockNames;
   330  		var long = l.length;
   331  		for (var i = 0; i < long; i++) 
   332  		{
   333  			if (l[i] == lockName)
   334  			{
   335  				return i;
   336  			}
   337  		}
   338  		return -1;
   339  	} 
   340  	
   341  	//--------------------
   342  	// METHODES STATIQUES
   343  	//--------------------
   344  	/**
   345  	 *	Utilisé dans un contexte littéral
   346  	 *
   347  	 *	@return Une chaine définissant l'objet.
   348  	 */
   349  	public static function toLog():String
   350  	{
   351  		return "[Objet Locks]";
   352  	}
   353  }
   354