/*
* #%L
* Talend :: ESB :: Job :: API
* %%
* Copyright (C) 2011 - 2012 Talend Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
// ============================================================================
//
// Copyright (C) 2006-2016 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package routines.system;
import java.io.OutputStream;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class RunStat implements Runnable {
private boolean openSocket = true;
private static boolean debug = false;
public void openSocket(boolean openSocket) {
this.openSocket = openSocket;
}
public static int BEGIN = 0;
public static int RUNNING = 1;
public static int END = 2;
public static int CLEAR = 3;
// it is a dummy default value for jobStat field
public static int JOBDEFAULT = -1;
public static int JOBSTART = 0;
public static int JOBEND = 1;
// this is as an additinal info to test the command type
public static String TYPE0_JOB = "0";
public static String TYPE1_CONNECTION = "1";
private class StatBean {
private String itemId;
private String connectionId;
private int nbLine;
private int state;
private long startTime = 0;
private long endTime = 0;
private String exec = null;
// feature:11356---1="Start Job" and 2="End job", default is -1
private int jobStat = JOBDEFAULT;
public StatBean(int jobStat, String itemId) {
this.jobStat = jobStat;
this.itemId = itemId;
if (jobStat == JOBSTART) {
this.startTime = System.currentTimeMillis();
} else if (jobStat == JOBEND) {
this.endTime = System.currentTimeMillis();
}
}
public StatBean(String connectionId) {
this.connectionId = connectionId;
this.startTime = System.currentTimeMillis();
}
public String getConnectionId() {
return this.connectionId;
}
public void setConnectionId(String connectionId) {
this.connectionId = connectionId;
}
public int getNbLine() {
return this.nbLine;
}
public void setNbLine(int nbLine) {
this.nbLine = nbLine;
}
public int getState() {
return this.state;
}
public void setState(int state) {
this.state = state;
}
public long getStartTime() {
return startTime;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
}
public long getEndTime() {
return endTime;
}
public void setEndTime(long endTime) {
this.endTime = endTime;
}
public String getExec() {
return this.exec;
}
public void setExec(String exec) {
this.exec = exec;
}
public int getJobStat() {
return jobStat;
}
public void setJobStat(int jobStat) {
this.jobStat = jobStat;
}
public String getItemId() {
return itemId;
}
}
private Map<String, StatBean> processStats = new HashMap<String, StatBean>();
private List<String> keysList = new LinkedList<String>();
// private java.util.ArrayList<StatBean> processStats = new java.util.ArrayList<StatBean>();
private java.net.Socket s;
private java.io.PrintWriter pred;
private boolean jobIsFinished = false;
private String str = ""; //$NON-NLS-1$
public void startThreadStat(String clientHost, int portStats) throws java.io.IOException, java.net.UnknownHostException {
if (!openSocket) {
// if go here, it means it is a childJob, it should share the socket opened in parentJob.
Socket s = null;
Object object = GlobalResource.resourceMap.get(portStats);
if (object == null || !(object instanceof Socket)) {
// Here throw an Exception directly, because the ServerSocket only support one client to connect it.
String lastCallerJobName = new Exception().getStackTrace()[1].getClassName();
throw new RuntimeException(
"The socket for statistics function is unavailable in job "
+ lastCallerJobName
+ "."
+ "\nUsually, please check the tRunJob, it should uncheck the option \"Use an independent process to run child job\".");
// todo: if here open another new Socket in childJob, need to close it in the API: stopThreadStat()
// s = new Socket(clientHost, portStats);
} else {
s = (Socket) object;
}
OutputStream output = s.getOutputStream();
if (debug) {
output = System.out;
}
pred = new java.io.PrintWriter(new java.io.BufferedWriter(new java.io.OutputStreamWriter(output)), true);
Thread t = new Thread(this);
t.start();
return;
}
System.out.println("[statistics] connecting to socket on port " + portStats); //$NON-NLS-1$
s = new Socket(clientHost, portStats);
GlobalResource.resourceMap.put(portStats, s);
OutputStream output = s.getOutputStream();
if (debug) {
output = System.out;
}
pred = new java.io.PrintWriter(new java.io.BufferedWriter(new java.io.OutputStreamWriter(output)), true);
System.out.println("[statistics] connected"); //$NON-NLS-1$
Thread t = new Thread(this);
t.start();
}
public void run() {
if (!debug) {
synchronized (this) {
try {
while (!jobIsFinished) {
sendMessages();
wait(1000);
}
} catch (InterruptedException e) {
System.out.println("[statistics] interrupted"); //$NON-NLS-1$
}
}
}
}
public void stopThreadStat() {
if (!openSocket) {
return;
}
jobIsFinished = true;
try {
sendMessages();
if (pred != null) {
pred.close();
}
if (s != null && !s.isClosed()) {
s.close();
}
System.out.println("[statistics] disconnected"); //$NON-NLS-1$
} catch (java.io.IOException ie) {
}
}
public void sendMessages() {
// if (!openSocket) {
// return;
// }
// SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss.SZ");
// System.out.println("############ Sending packets " + sdf.format(new Date()) + " ... #################");
for (String curKey : keysList) {
StatBean sb = processStats.get(curKey);
// it is connection
int jobStat = sb.getJobStat();
if (jobStat == JOBDEFAULT) {
str = TYPE1_CONNECTION + "|" + rootPid + "|" + fatherPid + "|" + pid + "|" + sb.getConnectionId();
// str = sb.getConnectionId();
if (sb.getState() == RunStat.CLEAR) {
str += "|" + "clear"; //$NON-NLS-1$ //$NON-NLS-2$
} else {
if (sb.getExec() == null) {
str += "|" + sb.getNbLine() + "|" + (sb.getEndTime() - sb.getStartTime()); //$NON-NLS-1$ //$NON-NLS-2$
} else {
str += "|" + sb.getExec(); //$NON-NLS-1$
}
if (sb.getState() != RunStat.RUNNING) {
str += "|" + ((sb.getState() == RunStat.BEGIN) ? "start" : "stop"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
} else {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss.SSSZ");
// it is job, for feature:11356
String jobStatStr = "";
String itemId = sb.getItemId();
itemId = itemId == null ? "" : itemId;
if (jobStat == JOBSTART) {
jobStatStr = jobName + "|" + "start job" + "|" + itemId + "|"
+ simpleDateFormat.format(new Date(sb.getStartTime()));
} else if (jobStat == JOBEND) {
jobStatStr = jobName + "|" + "end job" + "|" + itemId + "|"
+ simpleDateFormat.format(new Date(sb.getEndTime()));
}
str = TYPE0_JOB + "|" + rootPid + "|" + fatherPid + "|" + pid + "|" + jobStatStr;
}
// System.out.println(str);
pred.println(str); // envoi d'un message
}
keysList.clear();
// System.out.println("*** data sent ***");
}
long lastStatsUpdate = 0;
public synchronized void updateStatOnConnection(String connectionId, int mode, int nbLine) {
StatBean bean;
String key = connectionId;
if (connectionId.contains(".")) {
String firstKey = null;
String connectionName = connectionId.split("\\.")[0];
int nbKeys = 0;
for (String myKey : keysList) {
if (myKey.startsWith(connectionName + ".")) {
if (firstKey == null) {
firstKey = myKey;
}
nbKeys++;
if (nbKeys == 4) {
break;
}
}
}
if (nbKeys == 4) {
keysList.remove(firstKey);
}
}
if (keysList.contains(key)) {
int keyNb = keysList.indexOf(key);
keysList.remove(key);
keysList.add(keyNb, key);
} else {
keysList.add(key);
}
if (processStats.containsKey(key)) {
bean = processStats.get(key);
} else {
bean = new StatBean(connectionId);
}
bean.setState(mode);
bean.setEndTime(System.currentTimeMillis());
bean.setNbLine(bean.getNbLine() + nbLine);
processStats.put(key, bean);
// if tFileList-->tFileInputDelimited-->tFileOuputDelimited, it should clear the data every iterate
if (mode == BEGIN) {
bean.setNbLine(0);
// Set a maximum interval for each update of 250ms.
// since Iterate can be fast, we try to update the UI often.
long newStatsUpdate = System.currentTimeMillis();
if (lastStatsUpdate == 0 || lastStatsUpdate + 250 < newStatsUpdate) {
sendMessages();
lastStatsUpdate = newStatsUpdate;
}
}
if (debug) {
sendMessages();
}
}
public synchronized void updateStatOnConnection(String connectionId, int mode, String exec) {
StatBean bean;
String key = connectionId + "|" + mode;
if (connectionId.startsWith("iterate")) {
key = connectionId + "|" + mode + "|" + exec;
} else {
if (connectionId.contains(".")) {
String firstKey = null;
String connectionName = connectionId.split(".")[0];
int nbKeys = 0;
for (String myKey : keysList) {
if (myKey.startsWith(connectionName + ".")) {
if (firstKey == null) {
firstKey = myKey;
}
nbKeys++;
if (nbKeys == 4) {
break;
}
}
}
if (nbKeys == 4) {
keysList.remove(firstKey);
}
}
}
if (keysList.contains(key)) {
keysList.remove(key);
}
keysList.add(key);
// System.out.println(connectionId);
if (processStats.containsKey(key)) {
bean = processStats.get(key);
} else {
bean = new StatBean(connectionId);
}
bean.setState(mode);
bean.setExec(exec);
processStats.put(key, bean);
// Set a maximum interval for each update of 250ms.
// since Iterate can be fast, we try to update the UI often.
long newStatsUpdate = System.currentTimeMillis();
if (lastStatsUpdate == 0 || lastStatsUpdate + 250 < newStatsUpdate) {
sendMessages();
lastStatsUpdate = newStatsUpdate;
}
}
public synchronized void updateStatOnJob(int jobStat, String parentNodeName) {
StatBean bean = new StatBean(jobStat, parentNodeName);
String key = jobStat + "";
if (keysList.contains(key)) {
keysList.remove(key);
}
keysList.add(key);
processStats.put(key, bean);
sendMessages();
}
// for feature:10589
private String rootPid = null;
private String fatherPid = null;
private String pid = "0";
private String jobName = null;
// Notice: this API should be invoked after startThreadStat() closely.
public void setAllPID(String rootPid, String fatherPid, String pid, String jobName) {
this.rootPid = rootPid;
this.fatherPid = fatherPid;
this.pid = pid;
this.jobName = jobName;
}
}