package model.korrontea; import java.util.Vector; import network.connectors.EncapsulatedSample; import platform.servicesregister.ServiceClosedException; import util.streams.samples.Sample; /** * Buffer manager in a producer/consumer mode with semaphores.<br> * The buffer watches the number of samples pending.<br> * When this number is over the warning level defined in util.Parameters it raises, * via the CU, an alarm for the platform.<br> * When this number is over the saturation level defined in util.Parameters it raises, * via the CU, an alarm for the platform and starts discarding older samples.<br> * When this number, after been over warning level, is only 1, it raises, * via the CU, an alarm for the platform indicating that data circulation is now fluent.<br> * Offers methods to: * <ul> * <li> Depose a sample in the buffer (object of class Sample or inherited class) * <li> Get a sample in the buffer (object of class Sample or inherited class). * The requester is suspended on a semaphore until: * <ul> * <li> The requested sample is available * <li> The connector is removed * <li> The requester asks the buffer for a disconnection * </ul> * <li> Accept a consumer connection * <li> Accept a consumer disconnection. * <li> Start * <li> Stop (all suspended consumers are unlocked) * </ul> * * @author Dalmau */ // Classe pour gerer les buffers des connecteurs en mode producteur/consommateur // Un evenement est signale e l'UC quand le buffer atteint le seuil d'alarme // Un evenement est signale e l'UC quand le buffer est sature // Un evenement est signale e l'UC quand le buffer est redevenu fluide // Les seuils d'alarme et de saturation sont definis dans util.Parametres public final class ConnectorBuffer { private Vector<EncapsulatedSample> buffer; // buffer qui reeoit les echantillons en attente dans le connecteur private boolean consommateurConnecte; // indique si le consommateur de ces buffers est connecte private int seuilAlarme, seuilSaturation; // seuils de declenchement des evenements vers la PF // les booleens qui suivent permettent de ne pas lever plusieurs fois les alarmes // L'alarme est levee quand on depasse le seuil d'alarme puis desamorcee // Elle est reamorcee quand on tombe e 1 // La saturation est signalee quand on sature le buffer puis desamorcee // Elle est reamorcee quand on tombe au dessous du seuil d'alarme private boolean alarmeSignalee, saturationSignalee; private boolean arret; // pour arreter le consommateur lorsque le connecteur est detruit private ControlUnit uc; // UC du connecteur private String identifiant; // identifiant de ce buffer utilise lorsqu'il leve un evenement private model.osagaia.ControlUnit ucOsagaia; private int rangUE; /** * Buffer constructor * * @param ident idicate if this buffer is an input or an output one (only used for alarm information) * @param alarmLevel alarm level * @param saturationLevel saturation level */ public ConnectorBuffer(String ident, int alarmLevel, int saturationLevel) { this.uc = null; // pas d'UC au depart : elle sera definie par setUC identifiant = ident; // type de buffer (entree ou sortie) seuilAlarme = alarmLevel; // seuil pour lever un evenement alarmeSignalee = false; // pas d'evenement leve seuilSaturation = saturationLevel; // seuil de saturation => le buffer perd des elements saturationSignalee = false; // pas d'evenement leve buffer = new Vector<EncapsulatedSample>(); // contenu du buffer arret = true; // le buffer n'est pas actif (utilise lors de la suppression d'un connecteur) // L'indicateur de connexion du consommateur n'est pas utilisee pour un buffer d'entree // car ce consommateur est le CM du connecteur et est donc connecte des que le connecteur est cree consommateurConnecte = false; rangUE = -1; } /** * Associates the Control Unit of the connector to the BC * * @param controlUnit Control Unit of the connector */ public void setUC(ControlUnit controlUnit) { this.uc = controlUnit; // UC du connecteur } // lancement du buffer /** * Starts the buffer */ public void start() { arret=false; } // Arret du buffer => debloque et arrete les threads producteurs/consommateurs /** * Stops the buffer (all suspended consumers are unlocked). */ public synchronized void stop() { arret=true; notifyAll(); // pour debloquer les threads et pouvoir les arreter } /** * Accepts a consumer disconnection. */ public synchronized void consumerDisconnection() { ucOsagaia = null; consommateurConnecte = false; rangUE = -1; notifyAll(); // pour debloquer les threads et pouvoir les arreter } /** * Accepts a consumer connection. * @param uc control unit * @param number number of the connected IU */ public void consumerConnection(model.osagaia.ControlUnit uc, int number) { ucOsagaia = uc; rangUE = number; consommateurConnecte = true; // appele via l'UC du connecteur par le consommateur lorsqu'il se connecte } /** * Accepts a listener connection * @param uc control unit * @param number number of the connected IU */ public void listenerConnection(model.osagaia.ControlUnit uc, int number) { ucOsagaia = uc; rangUE = number; for (int i=0; i<buffer.size(); i++) { // faire vider le buffer par l'ecouteur d'entree if (ucOsagaia != null ) ucOsagaia.setInputAvailable(rangUE); } } /** * Returns the size of the buffer * * @return number of samples waiting in the buffer */ public int getSize() { return buffer.size(); } /** * Indicates if a sample of a given class associated to a given class loader is present in the buffer * @param sampleClass class of sample * @param cl associated class loader * @return true if there is at least one sample of the given class associated to the given class loader */ public synchronized boolean isSampleOfClassAvailable(Class<?> sampleClass, ClassLoader cl) { boolean trouve = false; int i=0; while ((!trouve) && (i<buffer.size())) { EncapsulatedSample element = buffer.elementAt(i); // donnee dans le buffer de sortie du connecteur Sample test = element.getSample(cl); // si elle est compatible avec la classe donnee en parametre OK, sinon voir les autres if (sampleClass.isInstance(test)) trouve = true; else i++; } return trouve; } // Methode appelee par le consommateur pour retirer un element du buffer /** * Get a sample in the buffer (object of class Sample or inherited class). * The requester is suspended on a semaphore until: * <ul> * <li> The requested sample is available * <li> The connector is removed * <li> The requester asks the buffer for a disconnection * </ul> * * @return the sample * @throws ServiceClosedException when the connector is not available */ public synchronized EncapsulatedSample getSample() throws ServiceClosedException { consommateurConnecte = true; // si cette methode est appelee c'est que le consommateur est connecte while ((buffer.size()==0) && (!arret) && consommateurConnecte) { try { wait(); // se bloquer si buffer vide et que le connecteur est en marche et que le consommateur est connecte } catch (InterruptedException ie) {} } if (!consommateurConnecte) { // le consommateur a ete debloque parce qu'il a demande sa deconnexion // une exception est levee pour le consommateur throw new ServiceClosedException("US Korrontea deconnectee"); } if (!arret) { // si le connecteur n'est pas arrete (il a pu l'etre pendant qu'on etait bloque) // recuperer puis enlever un echantillon du buffer EncapsulatedSample trouve = buffer.firstElement(); buffer.removeElementAt(0); // traiter le reamoreage des evenements int tailleActuelle = buffer.size(); if (alarmeSignalee && (tailleActuelle <= 1)) { uc.raiseAlarm(identifiant+" fluide"); alarmeSignalee = false; // reamorcer l'evenement } if (tailleActuelle <= seuilAlarme) { saturationSignalee = false; // reamorcer l'evenement } if ((!arret) && consommateurConnecte) return trouve; // element retire du buffer else throw new ServiceClosedException("US Korrontea deconnectee"); } else // si le buffer a ete arrete => une exception est levee pour le consommateur throw new ServiceClosedException("US Korrontea deconnectee"); } // Methode utilisee par les producteurs pour deposer un element dans le buffer /** * Deposes a sample in the buffer (object of class Sample or inherited class) * * @param ech sample to depose in the buffer */ public void deposeSample(EncapsulatedSample ech) { int tailleActuelle = buffer.size(); // Traiter les alarmes if ((tailleActuelle==seuilAlarme) && (!alarmeSignalee)) { // lever un evenement via l'UC car le buffer commence e se remplir trop uc.raiseAlarm(identifiant+" seuilAlarme"); alarmeSignalee = true; } if (tailleActuelle==seuilSaturation) { // on perd les echantillons les plus anciens buffer.removeElementAt(0); // lever un evenement via l'UC car le buffer est sature if (!saturationSignalee) { uc.raiseAlarm(identifiant+" seuilSaturation"); saturationSignalee = true; } } ajouteSample(ech); if (ucOsagaia != null ) ucOsagaia.setInputAvailable(rangUE); } private synchronized void ajouteSample(EncapsulatedSample sample) { buffer.addElement(sample); // d?poser l'?chantillon notifyAll(); // d?bloquer les consommateurs } }