001package com.killcoding.jsplus; 002 003import java.util.concurrent.ExecutorService; 004import com.killcoding.jsplus.ScriptConsole; 005import java.util.concurrent.Executors; 006import com.killcoding.log.LoggerFactory; 007import com.killcoding.log.Logger; 008import com.killcoding.datasource.CacheDriverExecutor; 009import java.sql.Connection; 010import com.killcoding.datasource.DriverConnection; 011import com.killcoding.datasource.DriverDataSource; 012import java.sql.SQLException; 013import com.killcoding.cache.CacheArray; 014import java.util.HashMap; 015import java.util.Map; 016import com.killcoding.cache.CacheArrayFilter; 017import com.killcoding.tool.ConfigProperties; 018import java.io.File; 019import java.io.IOException; 020import com.killcoding.datasource.Clock; 021import java.sql.Timestamp; 022import com.killcoding.tool.CommonTools; 023 024/** 025 * 026 CREATE TABLE ghost_remote_command ( 027 id CHAR(16) PRIMARY KEY, 028 ghost_name VARCHAR(200), 029 request_script VARCHAR(500), 030 response_message VARCHAR(500), 031 processed INT, 032 requested INT, 033 responsed INT, 034 created_at TIMESTAMP, 035 updated_at TIMESTAMP, 036 deleted_at TIMESTAMP, 037 deleted SMALLINT 038 ); 039 * 040 */ 041public class GhostConsole extends ScriptConsole { 042 043 public static int RESULT_SIZE = 500; 044 045 private static String GHOST_REQUESTED_SQL = "SELECT * FROM %s WHERE deleted = 0 AND requested = 1 AND responsed = 0 AND processed = 0 AND ghost_name = :ghost_name ORDER BY created_at ASC"; 046 private static String GHOST_GET_PROCESSED_SQL = "SELECT * FROM %s WHERE deleted = 0 AND requested = 1 AND responsed = 0 AND processed = 1 AND ghost_name = :ghost_name ORDER BY created_at ASC"; 047 private static String GHOST_PROCESSED_SQL = "UPDATE %s SET responsed = 0,processed = 1,response_message = :response_message,updated_at = :updated_at WHERE id = :id"; 048 private static String GHOST_RESPONSED_SQL = "UPDATE %s SET responsed = 1,updated_at = :updated_at WHERE id = :id"; 049 private static String GHOST_REQUEST_SQL = "INSERT INTO %s (id,ghost_name,request_script,response_message,requested,responsed,processed,created_at,updated_at,deleted_at,deleted) VALUES (:id,:ghost_name,:request_script,:response_message,:requested,:responsed,:processed,:created_at,:updated_at,:deleted_at,:deleted)"; 050 private static String GHOST_CLEAN_SQL = "DELETE FROM %s WHERE responsed = 1 AND processed = 1 AND deleted = 0 AND ghost_name = :ghost_name"; 051 private static String GHOST_CLEAN_ALL_SQL = "DELETE FROM %s WHERE ghost_name = :ghost_name"; 052 053 private ConfigProperties config = null; 054 private DriverDataSource ghostDs = null; 055 056 private String ghostTable = null; 057 private String ghostName = null; 058 private long ghostTimer = 200L; 059 private CacheArray requestRows = null; 060 private CacheArray responseRows = null; 061 private ScriptConsole console = null; 062 private boolean autoClean = true; 063 064 private boolean exit = false; 065 private boolean firstStart = true; 066 067 public GhostConsole(ScriptConsole console,String ghostName) { 068 super(); 069 this.console = console; 070 this.ghostName = ghostName; 071 this.setUseGhostEnv(); 072 CacheDriverExecutor.COLUMN_NAME_CASE_MODE = CacheDriverExecutor.COLUMN_NAME_CASE_LOWER; 073 String ghostDsPropFile = this.console.getJsPlusPath() + "/config/GhostDataSource.properties"; 074 init(ghostDsPropFile); 075 } 076 077 private void init(String ghostDsPropFile) { 078 try{ 079 config = new ConfigProperties(); 080 ghostDs = new DriverDataSource(new File(ghostDsPropFile)); 081 config = ghostDs.getConfigProperties(); 082 ghostTable = config.getString("GhostTable","ghost_remote_command"); 083 ghostTimer = config.getMilliSeconds("GhostTimer",200L); 084 }catch(Exception e){ 085 Logger.systemError(GhostConsole.class,e.getMessage(),e); 086 } 087 } 088 089 public boolean isAutoClean(){ 090 return this.autoClean; 091 } 092 093 public void submit(String executeCommand){ 094 String sql = String.format(GHOST_REQUEST_SQL,ghostTable); 095 CacheDriverExecutor cde = null; 096 try{ 097 Map<String,Object> params = new HashMap<String,Object>(); 098 Timestamp currentTime = new Clock().getSqlTimestamp(); 099 params.put("ghost_name",ghostName); 100 params.put("requested",1); 101 params.put("responsed",0); 102 params.put("processed",0); 103 params.put("request_script",executeCommand); 104 params.put("response_message",null); 105 params.put("created_at",currentTime); 106 params.put("updated_at",currentTime); 107 params.put("deleted",0); 108 params.put("id",CommonTools.generateId(16)); 109 Connection conn = ghostDs.getConnection(); 110 cde = new CacheDriverExecutor(conn); 111 cde.execute(sql,params); 112 }catch(Exception e){ 113 Logger.systemError(GhostConsole.class,e.getMessage(),e); 114 }finally{ 115 if(cde != null) try{cde.close();}catch(Exception e){} 116 } 117 } 118 119 private Runnable getExecuteRun(){ 120 return new Runnable(){ 121 @Override 122 public void run(){ 123 CacheDriverExecutor cde = null; 124 try{ 125 Object o = requestRows.getObject(); 126 if(o != null){ 127 Map<String,Object> ghostRecord = (Map<String,Object>)o; 128 String requestScript = (String)ghostRecord.get("request_script"); 129 Object id = ghostRecord.get("id"); 130 Object result = null; 131 try{ 132 result = console.evalScript(requestScript); 133 }catch(Exception e){ 134 result = e.getMessage(); 135 Logger.systemError(GhostConsole.class,e.getMessage(),e); 136 } 137 result = (result == null ? null : result + ""); 138 if(result != null && result.toString().length() > RESULT_SIZE){ 139 result = result.toString().substring(0,RESULT_SIZE - 1); 140 } 141 Map<String,Object> params = new HashMap<String,Object>(); 142 String sql = String.format(GHOST_PROCESSED_SQL,ghostTable); 143 params = new HashMap<String,Object>(); 144 params.put("response_message",result); 145 params.put("updated_at",new Clock().getSqlTimestamp()); 146 params.put("id",id); 147 Connection conn = ghostDs.getConnection(); 148 cde = new CacheDriverExecutor(conn); 149 cde.execute(sql,params); 150 } 151 }catch(Exception e){ 152 Logger.systemError(GhostConsole.class,e.getMessage(),e); 153 }finally{ 154 if(cde != null) try{cde.close();}catch(Exception e){} 155 } 156 } 157 }; 158 } 159 160 private Runnable getCompletedRun(){ 161 final GhostConsole the = this; 162 return new Runnable(){ 163 @Override 164 public void run(){ 165 try{ 166 the.requestRows = null; 167 168 if(!exit) Thread.sleep(ghostTimer); 169 170 if(!exit) the.start(the.autoClean); 171 }catch(Exception e){ 172 Logger.systemError(GhostConsole.class,e.getMessage(),e); 173 174 if(!exit) try {Thread.sleep(ghostTimer);} catch(Exception ee) {}; 175 176 if(!exit) the.start(the.autoClean); 177 } 178 } 179 }; 180 } 181 182 private Runnable getDetectExecuteRun(){ 183 return new Runnable(){ 184 @Override 185 public void run(){ 186 CacheDriverExecutor cde = null; 187 try{ 188 Object o = responseRows.getObject(); 189 if(o != null){ 190 Map<String,Object> ghostRecord = (Map<String,Object>)o; 191 String responseMessge = (String)ghostRecord.get("response_message"); 192 Object id = ghostRecord.get("id"); 193 String sql = String.format(GHOST_RESPONSED_SQL,ghostTable); 194 Map<String,Object> params = new HashMap<String,Object>(); 195 params.put("response_message",null); 196 params.put("updated_at",new Clock().getSqlTimestamp()); 197 params.put("id",id); 198 Connection conn = ghostDs.getConnection(); 199 cde = new CacheDriverExecutor(conn); 200 cde.execute(sql,params); 201 if((responseMessge + "").equals("undefined")){ 202 responseMessge = null; 203 } 204 if(responseMessge == null){ 205 System.out.println("The command has been executed remotely but no message has been returned."); 206 }else{ 207 String[] responseMessgeArray = responseMessge.split("\n"); 208 int len = responseMessgeArray.length; 209 for(int i = 0;i < len;i++){ 210 System.out.println(responseMessgeArray[i]); 211 Thread.sleep(200L); 212 } 213 } 214 } 215 }catch(Exception e){ 216 Logger.systemError(GhostConsole.class,e.getMessage(),e); 217 }finally{ 218 if(cde != null) try{cde.close();}catch(Exception e){} 219 } 220 } 221 }; 222 } 223 224 private Runnable getDetectCompletedRun(){ 225 final GhostConsole the = this; 226 return new Runnable(){ 227 @Override 228 public void run(){ 229 try{ 230 the.responseRows = null; 231 232 if(!exit) Thread.sleep(ghostTimer); 233 234 if(!exit) the.detect(); 235 }catch(Exception e){ 236 Logger.systemError(GhostConsole.class,e.getMessage(),e); 237 238 if(!exit) try {Thread.sleep(ghostTimer);} catch(Exception ee) {}; 239 240 if(!exit) the.detect(); 241 } 242 } 243 }; 244 } 245 246 public synchronized void detect() { 247 GhostConsole the = this; 248 if(responseRows == null){ 249 CacheDriverExecutor cde = null; 250 try{ 251 String sql = String.format(GHOST_GET_PROCESSED_SQL,ghostTable); 252 responseRows = new CacheArray(); 253 Runnable executeRun = getDetectExecuteRun(); 254 Runnable completedRun = getDetectCompletedRun(); 255 responseRows.filter(ghostTimer,executeRun,completedRun,null); 256 Map<String,Object> params = new HashMap<String,Object>(); 257 params.put("ghost_name",ghostName); 258 Connection conn = ghostDs.getConnection(); 259 cde = new CacheDriverExecutor(conn); 260 cde.find(0,100,sql,params,responseRows); 261 }catch(Exception e){ 262 Logger.systemError(GhostConsole.class,e.getMessage(),e); 263 264 if(!exit) try {Thread.sleep(ghostTimer);} catch(Exception ee) {}; 265 266 if(!exit) the.detect(); 267 }finally{ 268 if(cde != null) try {cde.close();}catch(Exception ee){}; 269 } 270 } 271 } 272 273 public void start() throws Exception { 274 start(true); 275 } 276 277 public synchronized void start(boolean autoClean) { 278 this.autoClean = autoClean; 279 GhostConsole the = this; 280 if(requestRows == null){ 281 CacheDriverExecutor cde = null; 282 try{ 283 String sql = String.format(GHOST_REQUESTED_SQL,ghostTable); 284 String cleanSql = String.format(GHOST_CLEAN_SQL,ghostTable); 285 requestRows = new CacheArray(); 286 Runnable executeRun = getExecuteRun(); 287 Runnable completedRun = getCompletedRun(); 288 requestRows.filter(ghostTimer,executeRun,completedRun,null); 289 Map<String,Object> params = new HashMap<String,Object>(); 290 params.put("ghost_name",ghostName); 291 Connection conn = ghostDs.getConnection(); 292 cde = new CacheDriverExecutor(conn); 293 if(firstStart){ 294 firstStart = false; 295 if(this.autoClean){ 296 String cleanAllSql = String.format(GHOST_CLEAN_ALL_SQL,ghostTable); 297 cde.execute(cleanAllSql,params); 298 } 299 } 300 cde.execute(cleanSql,params); 301 cde.find(0,100,sql,params,requestRows); 302 }catch(Exception e){ 303 Logger.systemError(GhostConsole.class,e.getMessage(),e); 304 305 if(!exit) try {Thread.sleep(ghostTimer);} catch(Exception ee) {}; 306 307 if(!exit) the.start(the.autoClean); 308 }finally{ 309 if(cde != null) try {cde.close();}catch(Exception ee){}; 310 } 311 } 312 } 313 314 public synchronized void stop(){ 315 exit = true; 316 } 317}