import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.SSLSocket;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jfree.chart.JFreeChart;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.xy.XYSeriesCollection;
public class ServerThread extends Thread
{
private BufferedReader sIn = null;
private BufferedWriter sOut = null;
private SSLSocket sslClient = null;
private int clientNo = 0;
private ConfigRead config;
private Debug debug;
private DataTransfer data;
private boolean userNameCorrect = false;
private boolean passWordCorrect = false;
private String clientAdress = "";
private String clientHostName = "";
private int errorCount = 0;
private int errorMax = 10;
private boolean interruptThread = false;
private StatistikPictureContainer statPictureContainer;
public ServerThread ( SSLSocket s , int no , DataTransfer data , ConfigRead config , Debug debug )
{
this.sslClient = s;
this.clientNo = no;
this.config = config;
this.debug = debug;
this.data = data;
if ( s != null )
{
this.clientAdress = sslClient.getInetAddress().getHostAddress();
this.clientHostName = sslClient.getInetAddress().getHostName();
}
else
{
this.clientAdress = "";
this.clientHostName = "";
}
try
{
sOut = new BufferedWriter ( new OutputStreamWriter ( sslClient.getOutputStream() ));
sIn = new BufferedReader ( new InputStreamReader ( sslClient.getInputStream() ));
debug.print ( 2 , this.clientNo , this.clientAdress , "Reader aufgebaut" );
}
catch ( IOException e )
{
debug.print ( 1 , this.clientNo , this.clientAdress , "Reader nicht aufgebaut " + e.getMessage() );
}
catch ( NullPointerException e )
{
debug.print ( 1 , this.clientNo , this.clientAdress , "Reader nicht aufgebaut " + e.getMessage() );
}
}
public void run()
{
String line = "";
boolean state = false;
MysqlConnection con = null;
this.interruptThread = false;
ServerThreadMonitor smt = new ServerThreadMonitor ( this , config , debug );
smt.start();
if ( config.getActionLogActive() == true )
{
con = new MysqlConnection ( debug , config );
con.connect();
}
Document xmlDocument = null;
SAXBuilder builder = new SAXBuilder();
Element messageRoot = null;
while ( ! this.interruptThread )
{
if ( this.errorCount >= this.errorMax )
{
debug.print ( 2 , this.clientNo , this.clientAdress , "Fehlerzaehlerueberlauf | ErrorCounter: " + this.errorCount );
break;
}
try
{
if ( ( line = sIn.readLine() ) != null )
{
debug.print ( 2 , this.clientNo , this.clientAdress , line );
smt.triggerTimestamp();
}
}
catch ( IOException e )
{
this.errorCount = this.errorCount + 1;
debug.print ( 1 , this.clientNo , this.clientAdress , "Fehler beim Lesen vom Stream | ErrorCounter: " + this.errorCount );
}
if ( line != null )
{
// mögliche Telegramminhalt
// <UserName>UserName</UserName>
// <PassWord>PassWord</PassWord>
// <Connection>closed</Connection>
// <get><SubSystem>Device</SubSystem></get>
// <get><Heizung>Außentemperatur</Heizung><Fhem>AussenTemperatur</Fhem><Seriell>AussenTemperatur</Seriell></get>
// <get Mode="Direct"><SubSystem>Device</SubSystem></get>
// <get>completeValues</get>
// <set><Heizung Device="/40/10021/0/0/12080" Mode="value">1803</Heizung></set>
// <getItems>SubSystem</getItems>
// <force>collect</force>
// <force>FhemGetConfig</force>
// <force>restart</force>
// <get>problems</get>
// <get>version</get>
// <get>debugLevel</get>
// <StatisticImage><table>1_seriell_log</table><timestamp><from>550087882</from><to>1550087882</to></timestamp><columns><column>solarvorlauf</column><column>aussentemperatur</column></columns><graph>barGraph</graph><outputOptions>AVG</outputOptions><timeClass>month</timeClass><verticalLabels>true</verticalLabels><dateAxis>true</dateAxis><yAxisAutoScale>false</yAxisAutoScale></StatisticImage>
if ( config.getActionLogActive() == true )
{
// timestamp clientNo clientAdress Name?? Line
ArrayList<String[]> log = new ArrayList<String[]>();
String [] eintrag = new String [2];
eintrag[0] = "clientNo";
eintrag[1] = this.clientNo + "";
log.add( eintrag.clone() );
eintrag[0] = "clientAdress";
eintrag[1] = this.clientAdress;
log.add( eintrag.clone() );
eintrag[0] = "name";
eintrag[1] = this.clientHostName;
log.add( eintrag.clone() );
eintrag[0] = ( "packet" );
if ( line.length() >= 600 )
{
eintrag[1] = line.substring( 0 , 599 );
}
else
{
eintrag[1] = line;
}
log.add( eintrag.clone() );
con.writeActionLog( log );
}
// Zeilen in xml doc wandeln
try
{
xmlDocument = null;
messageRoot = null;
debug.print( 2 , this.clientNo , this.clientAdress , "Eingelesene Zeile versuchen in xmlDocument zu wandeln" );
xmlDocument = builder.build( new StringReader ( line ) );
state = true;
}
catch ( JDOMException e )
{
debug.print( 2 , this.clientNo , this.clientAdress , "Fehler beim Wandeln " + e.getMessage() );
state = false;
}
catch ( IOException e )
{
debug.print( 2 , this.clientNo , this.clientAdress , "Fehler beim Wandeln String nicht vorhanden " + e.getMessage() );
state = false;
}
// Verarbeiten
if ( state == true )
{
messageRoot = xmlDocument.getRootElement();
debug.print( 2 , this.clientNo , this.clientAdress , "Rootelement der Message: " + messageRoot.getName() );
switch ( messageRoot.getName() )
{
case "UserName":
debug.print( 2 , this.clientNo , this.clientAdress , "UserName Telegramm empfangen" );
if ( messageRoot.getValue().equals ( config.getUserName() ) )
{
debug.print ( 2 , this.clientNo , this.clientAdress , "UserName passt" );
this.sendMessage ( "<UserName>correct</UserName>" );
this.userNameCorrect = true;
}
else
{
debug.print ( 2 , this.clientNo , this.clientAdress , "UserName passt nicht" );
this.sendMessage ( "<UserName>incorrect</UserName>" );
this.userNameCorrect = false;
}
break;
case "PassWord":
debug.print( 2 , this.clientNo , this.clientAdress , "PassWort Telegramm empfangen" );
if ( messageRoot.getValue().equals ( config.getPassWord() ) && this.userNameCorrect == true )
{
debug.print ( 2 , this.clientNo , this.clientAdress , "PassWord passt" );
this.sendMessage ( "<PassWord>correct</PassWord>" );
this.passWordCorrect = true;
}
else
{
debug.print ( 2 , this.clientNo , this.clientAdress , "PassWord passt nicht" );
this.sendMessage ( "<PassWord>incorrect</PassWord>" );
this.passWordCorrect = false;
}
break;
case "StatisticImage2":
debug.print ( 0 , this.clientNo , this.clientAdress , "StatisticImage2 Telegramm gefunden" );
if ( messageRoot.getValue().equals( "quit" ) )
{
this.sendMessage ( "<StatisticImage2>quit</StatisticImage2>" );
Runtime rt = Runtime.getRuntime();
debug.print( 3, "Speicher total vor: " + rt.totalMemory() + " Speicher frei: " + rt.freeMemory() + " Speicher belegt: " + ( rt.totalMemory() - rt.freeMemory() ) );
statPictureContainer = null;
System.gc();
debug.print( 3, "Speicher total nach: " + rt.totalMemory() + " Speicher frei: " + rt.freeMemory() + " Speicher belegt: " + ( rt.totalMemory() - rt.freeMemory() ) );
rt = null;
state = true;
}
else
{
String table = messageRoot.getChild( "table" ).getValue();
int fromTimestamp = Integer.parseInt( messageRoot.getChild( "timestamp" ).getChild( "from" ).getValue() );
int toTimestamp = Integer.parseInt( messageRoot.getChild( "timestamp" ).getChild( "to" ).getValue() );
boolean barGraph = false;
if ( messageRoot.getChild( "graph" ).getValue().equals( "barGraph" ) )
{
barGraph = true;
}
boolean lineGraph = false;
if ( messageRoot.getChild( "graph" ).getValue().equals( "lineGraph" ) )
{
barGraph = true;
}
boolean grouped = Boolean.parseBoolean( messageRoot.getChild( "grouped" ).getValue() );
String outputOptions = "";
String timeClass = "";
if ( grouped == true )
{
outputOptions = messageRoot.getChild( "outputOptions" ).getValue();
timeClass = messageRoot.getChild( "timeClass" ).getValue();
}
boolean verticalLabels = Boolean.parseBoolean( messageRoot.getChild( "verticalLabels" ).getValue() );
boolean dateAxis = Boolean.parseBoolean( messageRoot.getChild( "dateAxis" ).getValue() );
boolean yAxisAutoScale = Boolean.parseBoolean( messageRoot.getChild( "yAxisAutoScale" ).getValue() );
int width = Integer.parseInt( messageRoot.getChild( "width" ).getValue() );
int height = Integer.parseInt( messageRoot.getChild( "height" ).getValue() );
List<?> columnsMessage = (List<?>) messageRoot.getChild( "columns" ).getChildren();
debug.print( 2, "columns insgesamt: " + columnsMessage.size() );
String [] columns = new String [ columnsMessage.size() ];
for ( int k = 0; k < columnsMessage.size(); k++ )
{
Element column = (Element) columnsMessage.get(k);
debug.print( 2 , column.getName() + ": " + column.getValue());
if ( column.getName().equals( "column" ) )
{
columns[k] = column.getValue();
}
}
if ( debug.getDebugLevel() >= 3 )
{
debug.print( 3, "table: " + table );
debug.print( 3, "fromTimestamp: " + fromTimestamp );
debug.print( 3, "toTimestamp: " + toTimestamp );
debug.print( 3, "barGraph: " + String.valueOf( barGraph ));
debug.print( 3, "lineGraph: " + String.valueOf( lineGraph ));
debug.print( 3, "grouped: " + String.valueOf( grouped ));
debug.print( 3, "outputOptions: " + outputOptions );
debug.print( 3, "timeClass: " + timeClass );
debug.print( 3, "verticalLabels: " + String.valueOf( verticalLabels ));
debug.print( 3, "dateAxis: " + String.valueOf( dateAxis ));
debug.print( 3, "yAxisAutoScale: " + String.valueOf( yAxisAutoScale ));
debug.print( 3, "width: " + String.valueOf( width ));
debug.print( 3, "height: " + String.valueOf( height ));
for ( int i = 0; i < columns.length; i++ )
{
debug.print( 3, "columns: " + columns[i] );
}
}
StatistikPictures statPicture = new StatistikPictures ( debug, config );
statPicture.sqlConnect();
ResultSet abfrage = null;
JFreeChart diagram = null;
if ( grouped == true )
{
abfrage = statPicture.getStatistikData( table, fromTimestamp, toTimestamp, columns, AusgabeMöglichkeiten.valueOf( outputOptions ), ZeitKlassen.valueOf( timeClass ));
CategoryDataset dataSet = null;
if ( abfrage != null )
{
dataSet = statPicture.getCategoryDataSet( abfrage );
}
if ( dataSet != null )
{
diagram = statPicture.getDiagramm( dataSet, verticalLabels, yAxisAutoScale, lineGraph, barGraph );
}
}
else
{
abfrage = statPicture.getStatistikData( table, fromTimestamp, toTimestamp, columns );
XYSeriesCollection dataSet = null;
if ( abfrage != null )
{
dataSet = statPicture.getDataSet( abfrage );
}
if ( dataSet != null )
{
diagram = statPicture.getDiagramm( dataSet, verticalLabels, dateAxis, yAxisAutoScale, lineGraph, barGraph );
}
}
statPicture.sqlDisconnect();
int pictureSize = 0;
String pictureCheckSum = "";
int picturePacketSum = 0;
if ( diagram != null )
{
pictureSize = statPicture.convertDiagrammByteArray( diagram, width, height );
//pictureCheckSum = statPicture.convertByteArrayToString();
//picturePacketSum = statPicture.getPictureSplittetLength();
}
debug.print( 2, "Picture Size: " + pictureSize );
debug.print( 2, "Picture Check Sum: " + pictureCheckSum );
debug.print( 2, "Picture Anzahl Pakete: " + picturePacketSum );
if ( picturePacketSum >= 1 )
{
this.sendMessage ( "<StatisticImage2><checkSum>" + pictureCheckSum + "</checkSum><sumPackets>" + picturePacketSum + "</sumPackets></StatisticImage2>" );
/*statPictureContainer = null;
statPictureContainer = new StatistikPictureContainer( debug );
statPictureContainer.setCheckSum( pictureCheckSum );
statPictureContainer.setPictureContainer( statPicture.getPictureSplittet() );*/
}
else
{
this.sendMessage ( "<StatisticImage2>error</StatisticImage2>" );
}
PictureServer ps = new PictureServer( debug, config, 7458, statPicture.getPictureAsByteArray() );
ps.start();
statPicture = null;
state = true;
}
break;
default:
debug.print( 2 , this.clientNo , this.clientAdress , "keine gültiges Telegramm" );
state = false;
break;
}
}
// Default eine leere Zeile senden
if ( state != true )
{
debug.print ( 0 , this.clientNo , this.clientAdress , "Unbekanntes Kommando" );
this.sendMessage ( "" );
}
}
}
try
{
this.sendMessage ( "<Connection>closed</Connection>" );
sslClient.close();
smt.interruptThread();
debug.print ( 0 , this.clientNo , this.clientAdress , "Verbindung geschlossen" );
}
catch ( IOException e )
{
debug.print ( 1 , this.clientNo , this.clientAdress , "schliessen fehlgeschlagen" );
}
if ( con != null )
{
con.close();
con = null;
}
}
/*public synchronized void interrupt()
{
if ( this != null )
{
this.interrupt();
}
}*/
private boolean sendMessage ( String message )
{
boolean state = false;
try
{
sOut.write ( message + "\r\n" );
sOut.flush();
debug.print ( 2 , this.clientNo , this.clientAdress , "Senden von: " + message );
state = true;
}
catch ( IOException e )
{
debug.print ( 1 , this.clientNo , this.clientAdress , "Senden fehlgeschlagen" );
}
return state;
}
private boolean checkSubSystem ( String subSystem , boolean set )
{
boolean erg = false;
if ( set == true )
{
if ( subSystem.equals( "Heizung" ) || subSystem.equals( "Fhem" ) )
{
erg = true;
}
}
else
{
if ( subSystem.equals( "Heizung" ) || subSystem.equals( "Fhem" ) || subSystem.equals( "Seriell" ) || subSystem.equals( "Lager" ) )
{
erg = true;
}
}
debug.print( 2 , "checkSubSystem Ergebnis für: " + subSystem + " -> " + erg );
return erg;
}
private boolean loginCorrect ()
{
return userNameCorrect && passWordCorrect;
}
public int getClientNumber ()
{
return this.clientNo;
}
public String getClientIP ()
{
return this.clientAdress;
}
public void interruptThread ()
{
this.interruptThread = true;
}
}