/*******************************************************************************
* ALMA - Atacama Large Millimeter Array
* Copyright (c) ESO - European Southern Observatory, 2011
* (in the framework of the ALMA collaboration).
* All rights reserved.
*
* This library 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*******************************************************************************/
package cl.utfsm.samplingSystemUI;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.concurrent.LinkedBlockingQueue;
import alma.ACSErrTypeCommon.CouldntAccessComponentEx;
import alma.ACSErrTypeCommon.TypeNotSupportedEx;
import alma.JavaContainerError.wrappers.AcsJContainerEx;
import alma.ACSErrTypeCommon.CouldntAccessPropertyEx;
import cl.utfsm.samplingSystemUI.core.AcsInformationException;
import cl.utfsm.samplingSystemUI.core.DataItem;
import cl.utfsm.samplingSystemUI.core.SampDetail;
import cl.utfsm.samplingSystemUI.core.SamplingManagerException;
import cl.utfsm.samplingSystemUI.core.SamplingManagerUITool;
import cl.utfsm.samplingSystemUI.core.ThreadCommunicator;
/**
* Class that handles the comunication with the acs sampling system.
* This class extends the core funtionality given by SamplingManagerUITool
* @see SamplingManagerUITool
*
*/
public abstract class DataPrinter extends SamplingManagerUITool{
/*Information required by the acs sampling system.
* @param name component to be sampled (e.g. LAMP1)
* @param property property to be sampled (e.g brightness)
* @param frequency sampling frequency: period between two consecutive
* sampling
* (units are 100ns; e.g. 1000000 means 0.1 sec i.e.
* 10 sample per second)
* @param reportRate number of second the process should buffer
* before actually sending (notifying) data
* (units are 100ns; e.g. 10000000 means collect data
* for 1 second)
*/
private static long FREQ_CONV=10000000L;//1E7
protected long frequency=FREQ_CONV; //set frequency default to 1 Hz.
protected long reportRate=1;
protected String component;
protected String property;
protected SamplingWidget widget;
public Sampler samp = null;
private static int initializations=0;
private boolean componentAvailable = true;
private SamplingSystemGUI ssg = null;
public DataPrinter(SamplingSystemGUI ssg) {
this.ssg = ssg;
}
/**
* Returns the frequency in Hz.
*
* @return double. frequency in Hz.
*/
public double getFrequency() {
double freq = ((double)FREQ_CONV/(double)this.frequency);
String tmp = new Double(freq).toString();
tmp = tmp.substring(0,tmp.lastIndexOf(".")+2);
freq = Double.parseDouble(tmp);
return freq;
}
public long getReportRate() {
return reportRate;
}
public String getComponent() {
return component;
}
public String getProperty() {
return property;
}
public SamplingWidget getSamplingWidget(){
return widget;
}
public void setComponent(String component) {
this.component = component;
}
public void setProperty(String property) {
this.property = property;
}
/**
* Sets the frequency in the sampObj.
*
* @param double frequency in Hz. Internally its converted into
* the value that sampObj requires.
* @see SampObj
*/
public void setFrequency(double f) {
long freq = (long)(FREQ_CONV/f);
this.frequency = freq;
}
public void setReportRate(long reportRate) {
this.reportRate = reportRate;
}
public IGraphicalUpdater getWidget() {
return widget;
}
protected abstract void updateValue(DataItem item);
public abstract ArrayList<DataItem> getSamples();
/**
* Do a post processing once stop all samplings threads. The child class
* must implement it if is necessary do a post processing on samplings data
* stored.
* @see Sampler
*/
public abstract void postProcessing();
/**
* Starts the sampling, connecting to ACS Manager and the Sampling Manager.
* @throws CouldntAccessComponentEx Component wasn't available at the time.
* @throws TypeNotSupportedEx Sampling Manager specific exception. Some types are currently not supported in acssamp.
* @throws CouldntAccessPropertyEx
*/
public void startSample() throws CouldntAccessComponentEx, TypeNotSupportedEx , CouldntAccessPropertyEx, SamplingManagerException{
samp = new Sampler();
synchronized(this){
System.out.println("Initialization:"+ initializations);
if(initializations==0){
try{
spinUp(SampTool.NAME,ssg.MAN_NAME);
}
catch (AcsInformationException e){
System.out.print(e.getMessage());
System.exit(-1);
}
catch (SamplingManagerException e){
System.out.print(e.getMessage());
System.exit(-1);
} catch (AcsJContainerEx e) {
System.out.println(e.getMessage());
System.exit(-1);
}
}
initializations++;
}
try {
SamplingManagerUITool.startSample(new SampDetail(component,property,
(long)this.frequency,reportRate));
} catch(alma.ACSErrTypeCommon.CouldntAccessComponentEx e) {
setComponentAvailable(false,"Cannot access component implementation");
throw e;
} catch(alma.ACSErrTypeCommon.TypeNotSupportedEx e) {
setComponentAvailable(false,"Type not supported");
throw e;
} catch (CouldntAccessPropertyEx e){
setComponentAvailable(false,"Cannot access the property");
throw e;
} catch(SamplingManagerException e){
setComponentAvailable(false,e.getMessage());
throw e;
}
samp.start();
}
public void stopSampling(){
synchronized(this){
initializations--;
if( componentAvailable == true ) {
samp.halt();
SamplingManagerUITool.stopSample(new SampDetail(component, property, (long)frequency, reportRate));
postProcessing();
}
}
}
/**
* Pauses/unpauses the displaying of the sampling process
* @param p Pause status
*/
public void pauseSampling(boolean p) {
if( componentAvailable == true )
samp.setPause(p);
}
public void finalize(){
stopSampling();
synchronized (this) {
if(initializations==0){
try {
tearDown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* Allows to handle whether a component is or isn't available to be sampled.
* @param available True if the component is currently available.
* @param reason A explanation of the cause why the component isn't available.
*/
public void setComponentAvailable(boolean available, String reason) {
componentAvailable = available;
}
public boolean isComponentAvailable() {
return componentAvailable;
}
public boolean isStopped() {
if(samp == null){
return true;
}
return samp.isStopped();
}
public SerializableProperty getSerializableProperty(){
SerializableProperty sp = new SerializableProperty();
sp.setComponent(getComponent());
sp.setFrequency(getFrequency());
sp.setProperty(getProperty());
return sp;
}
/**
* Thread class for receive data from one notification channel. <br/>
* For each time that is called {@startSample} is created a new instance of
* this class.
*
* @see startSample
*
* @author Jorge Avarias <javarias[at]inf.utfsm.cl>
*/
class Sampler extends Thread {
private boolean stop = false;
/**
* Flag to freeze the information displayer (graphic or whatever).
* Anyways, the sampling processes continues
*/
private boolean pause = false;
public boolean isStopped() {
return stop;
}
public boolean isPaused() {
return pause;
}
public void setPause(boolean p) {
pause = p;
}
public void halt() {
stop=true;
}
public void run(){
//int timeout_ms = (int)(1000/getFrequency())*10; //maximum of 10 times of delay
//Timer timer = new Timer( timeout_ms );
boolean runningTimer = false;
LinkedBlockingQueue<DataItem> cChannel;
LinkedList<DataItem> c = new LinkedList<DataItem>();
int n=0;
while(true){
try {
if(stop==true) {
//timer.reset();
return;
}
Thread.sleep(100);
//"NC_LAMP1_brightness_10000000_1"
cChannel = ThreadCommunicator.getInstance().getChannel("NC_"+component+"_"+
property+"_"+frequency+"_"+reportRate);
if(cChannel==null)
continue;
if( (cChannel.size() == 0) && !runningTimer ) {
runningTimer = true;
//timer = new Timer(timeout_ms);
//timer.start();
}
if(runningTimer) {
if( cChannel.size() == 1 ) {
runningTimer = false;
//timer.reset();
}
}
cChannel.drainTo(c);
//TODO:Improve the way to drain data: Actually drainTo method
//drain all sampled data from the sampling start.
if(c.isEmpty())
continue;
if( !pause )
for(int i=n;i<c.size();i++){
updateValue(c.get(i));
}
n=c.size();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}