package model.osagaia;
import model.StopBCException;
import util.streams.samples.Sample;
import platform.servicesregister.ServicesRegisterManager;
import platform.servicesregister.ServiceClosedException;
import util.Commands;
import model.interfaces.inputoutput.InputListener;
import network.connectors.EncapsulatedSample;
/**
* Input Unit of a BC container<br>
* Offers methods to:<br>
* <ul>
* <li> Connect to the input connector.
* That means waiting until this connector is available.
* <li> Disconnect from the input connector
* <li> Stop => raises an exception to the BC at the next try of reading
* in input stream (that will stop the BC)
* <li> Read a sample (class Sample or inherited)
* on the input stream (suspends the BC on a semaphore until either:
* <ul>
* <li> Sample is available
* <li> Input connector has been removed
* <li> BCes input has been disconnected
* <li> Input Unit has been stopped
* </ul></ul>
* When BCes input is disconnected or when the input connector is removed,
* the input unit waits for a reconnection.
*
* @author Dalmau
*/
// Classe de l'UE Osagaia
public class InputUnit {
private String nomconnecteurEntree; // nom symbolique du connecteur
private boolean arret; // indique si l'UE est arretee
private boolean connecte; // indique si l'UE est connectee
private model.korrontea.OutputUnit serveur; // Us du connecteur connecte en entree
private boolean lectureEnCours; // indique si le CM est en cours de lecture
private Class<?> classeEntree; // classe des echantillons d'entree
private ControlUnit uc;
private int rang;
private InputListener ecouteur;
/**
* Constuction of an Input Unit for BC container
* @param number number of the IU
*/
public InputUnit(int number) {
rang = number;
arret=false; // l'UE est prete e fonctionner
connecte = false; // l'UE n'est pas connectee
serveur = null;
lectureEnCours = false;
ecouteur = null;
try { classeEntree = Class.forName(Sample.class.getName()); }
catch (ClassNotFoundException cnfe) { classeEntree = null; }
}
/**
* Associate the Control Unit of the Osagaia Container to this Input Unit.
* @param cu Control Unit of the Osagaia Container
*/
public void setControlUnit(ControlUnit cu) {
uc=cu;
}
/**
* Find the Output Unit of the actually connected connector.
*
* @return the Output Unit of the actually connected connector.
* @throws ServiceClosedException if there is actually no connector connected to this
* Osagaia Input Unit
*/
public model.korrontea.OutputUnit findConnectorOU() throws ServiceClosedException {
model.korrontea.ControlUnit accesUS = (model.korrontea.ControlUnit)ServicesRegisterManager.lookForService(nomconnecteurEntree);
return accesUS.getOU();
}
/**
* Connects the Input Unit to a connector
*
* @param nom name of the connector to connect with
*/
public synchronized void connection(String nom) {
nomconnecteurEntree = nom;
if (!nomconnecteurEntree.equals(Commands.ES_NOT_USED)) {
// ouverture du service de l'US du connecteur en entree
model.korrontea.ControlUnit accesUS = (model.korrontea.ControlUnit)ServicesRegisterManager.platformWaitForService(nomconnecteurEntree);
serveur = accesUS.getOU();
serveur.consumerConnection(uc, rang); // signaler la connexion au connecteur
if (ecouteur != null) serveur.listenerConnection(uc, rang); // s'il y a un ecouteur lui faire vider le buffer
connecte=true; // l'UE est connecte
notifyAll(); // deblocage du CM s'il etait en lecture sur l'UE ou en attente de reconnexion
}
}
/**
* Disconnects the Input Unit from the connector
*/
public void disconnection() {
if (!nomconnecteurEntree.equals(Commands.ES_NOT_USED)) {
try { // essayer de signaler e l'US du connecteur qu'on se deconnecte
model.korrontea.ControlUnit accesUS = (model.korrontea.ControlUnit)ServicesRegisterManager.lookForService(nomconnecteurEntree);
serveur = accesUS.getOU();
serveur.consumerDisconnection(); // debloque le CM s'il est attente d'entree
}
catch (ServiceClosedException ace) {} // on n'est deje pas connecte au connecteur
connecte = false; // l'UE n'est plus connectee
while(lectureEnCours) { // attendre que le CM ait termine ou suspendu la lecture
Thread.yield();
}
}
}
/**
* Used to stop the IU.
* When stopped the IU raises a StopBCException when BC tries to get an input from this IU.
*/
public synchronized void stop() {
/* utilise pour que l'UE cesse de fonctionner
* quand ce booleen est a true tout appel e une lecture dans l'UE
* provoque une exception de classe StopCMException qui sera utilisee
* par le CM pour s'arreter
*/
arret=true;
notifyAll(); // deblocage du CM s'il etait en lecture sur l'UE ou en attente de reconnexion
}
/**
* Define the name of the class of samples to be read by the BC.
* When <b>readInInputUnit</b> is called without parameter, it is assumed that
* the BC reads samples assignment-compatible with the class defined by this method.
* If the sample actually present in the connector
* is not assignment-compatible with this class it is discarded and
* the Input Unit waits for another one.
*
* @param className name of the class of sample to be read.
* @throws ClassNotFoundException If the class name in parameter could not be found
*/
public void setInputClassFilter(String className) throws ClassNotFoundException {
classeEntree = Class.forName(className);
}
/**
* Removes the class ilter associated to this IU
*/
public void removeInputClassFilter() {
try { classeEntree = Class.forName(Sample.class.getName()); }
catch (ClassNotFoundException cnfe) { classeEntree = null; }
}
/**
* Indicates if an accepted input (see filter) is available on this IU
* @return true if an accepted input is available
* @throws StopBCException
*/
public boolean isInputAvailable() throws StopBCException {
if (arret) throw(new StopBCException("CM arrete lors d'une lecture dans l'UE"));
if (!connecte) return false;
else { // l'UE n'est pas arr?t?e et pas d?connect?e
return isSampleOfClassAvailable(classeEntree);
}
}
/**
* Read a sample on this IU
* @return the read sample
* @throws StopBCException when the BC has to be stopped
*/
public Sample readInInputUnit() throws StopBCException {
return readInInputUnit(classeEntree);
}
/**
* Waits for a sample of a given class in the input stream.
* The requester is locked on a semaphore until a sample is available.<br>
* If the sample actually present in the connector is not assignment-compatible
* with the class given in parameter it is discarded and the Input Unit waits for another one.
*
* @param className name of the class of sample to be read. If the sample actually present
* in the connector is not assignment-compatible with this class it is discarded and
* the Input Unit waits for another one.
*
* @return the sample read in the input stream
* @throws StopBCException Used to stop the BC by the platform
* @throws ClassNotFoundException If the class name in parameter could not be found
*/
public Sample readInInputUnit(String className) throws StopBCException, ClassNotFoundException {
return readInInputUnit(Class.forName(className));
}
/**
* Waits for a sample of a given class in the input stream.
* The requester is locked on a semaphore until a sample is available.<br>
* If the sample actually present in the connector is not assignment-compatible
* with the class given in parameter it is discarded and the Input Unit waits for another one.
*
* @param classeEchantillon class of sample to be read. If the sample actually present
* in the connector is not assignment-compatible with this class it is discarded and
* the Input Unit waits for another one.
* @return the sample read in the input stream
* @throws StopBCException Used to stop the BC by the platform
*/
private Sample readInInputUnit(Class<?> classeEchantillon) throws StopBCException {
synchronized(this) { // semaphore debloque par une reconnexion ou un arret de l'UE
while (!connecte && !arret){ // attendre d'etre connecte ou arrete
try { wait(); } catch(InterruptedException ie) {}
}
}
// si l'UE est arretee lever une exception pour arreter le CM
if (arret) throw(new StopBCException("CM arrete lors d'une lecture dans l'UE"));
else { // l'UE n'est pas arretee
EncapsulatedSample ech=null;
Sample echLu=null;
boolean nonRecu=true;
while (nonRecu && connecte && (!arret)) { // tenter une recuperation d'echantillon dans le connecteur
// si pendant cette tentative le connecteur d'entree a ete supprime
// ou si l'UE a ete deconnectee il faut attendre une reconnexion ou un arret
lectureEnCours = true; // la lecture est en cours
try { // essayer de recuperer un echantillon dans l'US du connecteur
model.korrontea.ControlUnit accesUS = (model.korrontea.ControlUnit)ServicesRegisterManager.lookForService(nomconnecteurEntree);
serveur = accesUS.getOU();
ech = serveur.getSample(); // appel bloquant dont on sort avec l'?chantillon ou une exception
echLu = ech.getSample(uc.getCM().getClass().getClassLoader());
echLu.setInputNumber(rang);
// on arrive ici parce qu'on a reeu un echantillon => le retourner
if (connecte && (!arret)) {
if (classeEchantillon.isInstance(echLu)) nonRecu=false; // on a eu un echantillon de la bonne classe => on le renvoie
else nonRecu=true; // on a eu un echantillon pas de la bonne classe => on l'ignore
}
}
catch (ServiceClosedException ace) { // le connecteur n'existe plus
// on arrive ici soit
// parce qu'on ete deconnecte => attendre d'etre reconnecte ou arrete si on n'est pas arrete on retente la lecture
// parce qu'on a ete arrete => terminer la lecture et arreter le CM
connecte=false; // l'UE n'est plus connectee => attendre une reconnexion ou un arret
synchronized(this) { // semaphore debloque par une reconnexion ou un arret de l'UE
lectureEnCours = false; // la lecture est suspendue
while (!connecte && !arret){ // attendre d'etre reconnecte ou arrete
try { wait(); } catch(InterruptedException ie) {}
}
}
if (arret) nonRecu=false; // si on a ete arrete pandant l'attente se terminer
}
}
// si on a ete arrete pendant une tentative de recuperation d'echantillon il faut arreter le CM
lectureEnCours = false; // la lecture est terminee
if (arret) throw(new StopBCException("CM arrete lors d'une lecture dans l'UE"));
else return echLu; // renvoyer l'echantillon
}
}
/**
* Reads a sample when an event indicating that a new sample is available occurs
* @return the sample read in the input stream
* @throws StopBCException Used to stop the BC by the platform
*/
public Sample readOnEvent() throws StopBCException {
EncapsulatedSample ech=null;
Sample echLu=null;
if (connecte && (!arret)) { // tenter une recuperation d'echantillon dans le connecteur
// si pendant cette tentative le connecteur d'entree a ete supprime
// ou si l'UE a ete deconnectee il faut attendre une reconnexion ou un arret
lectureEnCours = true; // la lecture est en cours
try { // essayer de recuperer un echantillon dans l'US du connecteur
model.korrontea.ControlUnit accesUS = (model.korrontea.ControlUnit)ServicesRegisterManager.lookForService(nomconnecteurEntree);
serveur = accesUS.getOU();
ech = serveur.getSample(); // appel bloquant dont on sort avec l'?chantillon ou une exception
echLu = ech.getSample(uc.getCM().getClass().getClassLoader());
// on arrive ici parce qu'on a reeu un echantillon => le retourner
if (connecte && (!arret)) {
if (!classeEntree.isInstance(echLu)) echLu=null; // on a eu un echantillon pas de la bonne classe => on l'ignore
}
}
catch (ServiceClosedException ace) { // le connecteur n'existe plus
// on arrive ici soit
// parce qu'on ete deconnecte => attendre d'etre reconnecte ou arrete si on n'est pas arrete on retente la lecture
// parce qu'on a ete arrete => terminer la lecture et arreter le CM
connecte=false; // l'UE n'est plus connectee => attendre une reconnexion ou un arret
lectureEnCours = false; // la lecture est suspendue
}
if (arret) echLu=null; // si on a ete arrete pandant l'attente se terminer
}
lectureEnCours = false; // la lecture est terminee
if ((!arret)&& connecte && (echLu != null)) {
echLu.setInputNumber(rang); // c'est OK on a l'echantillon
}
else {
if (arret) throw(new StopBCException("CM arrete lors d'une lecture dans l'UE")); // le composant est arrete
else echLu = null; // l'Ue est deconnectee
}
return echLu;
}
/**
* Adds an input listener to this IU
* @param listener input listener to add
*/
public void addInputListener(InputListener listener) {
ecouteur = listener;
try { // s'il y a un connecteur sur cette entree
model.korrontea.ControlUnit accesUS = (model.korrontea.ControlUnit)ServicesRegisterManager.lookForService(nomconnecteurEntree);
serveur = accesUS.getOU();
serveur.listenerConnection(uc, rang); // faire vider le buffer par l'ecouteur d'entree
}
catch (ServiceClosedException sce) {}
}
/**
* Removes the input listener associated to this IU
*/
public void removeInputListener() {
ecouteur = null;
}
/**
* Returns the actually associated input listener
* @return input listener associated to this IU
*/
public InputListener getInputListener() {
return ecouteur;
}
private boolean isSampleOfClassAvailable(Class<?> sampleClass) {
try {
model.korrontea.ControlUnit accesUS = (model.korrontea.ControlUnit)ServicesRegisterManager.lookForService(nomconnecteurEntree);
return accesUS.getOU().getBuffer().isSampleOfClassAvailable(sampleClass, uc.getCM().getClass().getClassLoader());
}
catch(ServiceClosedException sce) {
return false;
}
}
}