首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > Eclipse开发 >

《Eclipse插件门外汉怎么搞掂插件升级》续集:为西子换心

2013-09-11 
《Eclipse插件门外汉如何搞掂插件升级》续集:为西子换心SLink升级到能支持Eclipse 3.4.1(Ganymede)的版本,虽

《Eclipse插件门外汉如何搞掂插件升级》续集:为西子换心

SLink升级到能支持Eclipse 3.4.1(Ganymede)的版本,虽然改动SLink的代码较多,但都不算是核心的修改,充其量只是给她穿衣洗脸梳头抹胭脂。

?

如果把SLink比作西施,那么现在我就要把病歪歪的西子做个换心术,彻底根治她的先天性心脏病(当然,这样西施就不是西施了)。

?

之所以说SLink病若西子,是因为她还不够powerful,目前SLink还不支持远程SAS编程,只能在SAS服务器上用插了SLink的Eclipse来写SAS代码。

?

改变能改变的,接受不能改变的。SLink的这个局限性我无法接受,我要改变她。

?

做换心术之前最重要的就是找到她的心。这个不难,只须循着她血液的流向(跟随代码的走向)就能找到。西子之心在这儿:

com.anaxima.slink.server.internal.ServerConnection

原作者Thomas Vater 的代码风格很好,可读性很强。现在我们可以观察一下西子之心:

/*                                                                                                                                       * $Id: ServerConnection.java,v 1.1 2005/12/09 15:58:28 tv Exp $ * Copyright 2005 anaxima GmbH, Germany - All Rights Reserved.                                                                           *                                                                                                                                       * This software is the proprietary information of                                                                                       * anaxima GmbH, Germany. Use is subject to license terms.                                                                               */                                                                                                                                     package com.anaxima.slink.server.internal;import java.io.IOException;import java.io.PrintStream;import java.net.InetSocketAddress;import java.net.Socket;import java.text.DecimalFormat;import org.eclipse.core.runtime.CoreException;import org.eclipse.core.runtime.IStatus;import org.eclipse.core.runtime.Status;import com.anaxima.slink.server.ServerPlugin;import com.anaxima.slink.tools.LogHelper;import com.anaxima.slink.tools.log.ILogger;/** * Make a connection to a SAS Server. *  * @author Thomas Vater */public class ServerConnection {// log objectprivate static final ILogger log = ServerPlugin.getLogger();    /** * Format for ports. */private static final DecimalFormat PORTFMT = new DecimalFormat("00000");/** * Connect retries before failure. */private static final int CONNECT_RETRY = 20;/** * Connect wait before next retry. */private static final int CONNECT_WAIT = 5000;/** * Host name to connect to. */private String _host;/** * Port number to connect with. */private int _port;/** * Start port number for result connection. */private int _startResultPort;/** * Maximum port number for result connection. */private int _endResultPort;/** * Current result port. */private int _resultPort;/** * SLink server communication socket. */private static Socket _sasSocket;/** * SLink server communication print stream. */private PrintStream _out;/** * Result data collector. */private ResultCollector _resultCollector;/** * Log data collector. */private ResultCollector _logCollector;/** * Output data collector. */private ResultCollector _printCollector;public ServerConnection() {}/** * Creates a new server connection object for *  * @param argHost; * @param argPort; */public ServerConnection(String argHost, int argPort, int argStartResultPort, int argEndResultPort) {_host = argHost;_port = argPort;_startResultPort = argStartResultPort;_endResultPort = argEndResultPort;_resultPort = argStartResultPort;// set up connection to SLink serverint retry = 0;while (retry < CONNECT_RETRY && _out == null) {try {_sasSocket = new Socket();if (log.isDebugEnabled()) log.debug("Trying to connect " + _host + ":" + _port + "...");_sasSocket.connect(new InetSocketAddress(_host, _port), 0);_out = new PrintStream(_sasSocket.getOutputStream());} catch (IOException ioe) {if (log.isDebugEnabled()) log.debug(ServerPlugin.getMessage("slinkserver.connection.error.backend", new Integer(retry)), ioe);_sasSocket = null;_out = null;try {Thread.sleep(CONNECT_WAIT);} catch (InterruptedException ir) {// ignore;}retry++;}}// TODO: Notify user if connection to SLink backend failedif (_out == null) {log.error(ServerPlugin.getMessage("slinkserver.connection.error.backend.final"));}}/** * Format port numer into 5 digits. * @param argPortNo * @return Formatet port number. */private String _formatPort(int argPortNo) {return PORTFMT.format(argPortNo);}/** * Returns the next result port. This method implements a round robin * distribution of ports. *  * @return Next result port. */private int _nextPort() {int next = _resultPort++;if (_resultPort >= _endResultPort) _resultPort = _startResultPort;return next;}/** * Evaluate results. */private boolean _evaluateResults(int argResultPort) {boolean retOk = _resultCollector != null && !_resultCollector.isAlive() && !_resultCollector.hasError();boolean logOk = _logCollector != null && !_logCollector.isAlive() && !_logCollector.hasError();boolean prnOk = _printCollector != null && !_printCollector.isAlive() && !_printCollector.hasError();if (!retOk) {System.out.println("RET result FAILED.");if (_resultCollector != null) System.out.println(_resultCollector.getException());}if (argResultPort == 99999) return retOk;if (!logOk) {System.out.println("LOG result FAILED.");if (_logCollector != null) System.out.println(_logCollector.getException());}if (!prnOk) {System.out.println("PRINT result FAILED.");if (_printCollector != null) System.out.println(_printCollector.getException());}return (retOk && logOk && prnOk);}/** * Send a command to the server and returns the result. *  * @paramargCmd * Command to execute. *  * @paramargs * Array of arguments. May be <code>null</code>. *  * @return<code>true</code> if all results were successfully collected. <code>false</code> otherwise. */public boolean sendCommand(String argCmd, String[] args) throws CoreException {int resultPort;int logPort;int printPort;try {if ("SHUTDOWN".equalsIgnoreCase(argCmd)) {resultPort = 99999;logPort = 99999;printPort = 99999;} else {resultPort = _nextPort();logPort = _nextPort();printPort = _nextPort();// Code added by Sam Chen on 12/12/2008 10:24 ==>if (log.isDebugEnabled()) {log.debug("resultPort: " + resultPort + "; logPort: " + logPort + "; printPort: " + printPort);}// Code added by Sam Chen on 12/12/2008 10:24 <==}// send ports: resultPort, logPort and printPort_out.println(_formatPort(resultPort));_out.println(_formatPort(logPort));_out.println(_formatPort(printPort));// send command_out.println(argCmd.toUpperCase());// send number of args_out.println((args==null)?"0":""+args.length);// send argumentsif (args != null) {for (int i=0; i<args.length; i++) {_out.println(args[i]);}}// send SYNC_out.println("SYNC");_out.flush();if (resultPort != 99999) {// setup result collectors_resultCollector = new ResultCollector("RET", resultPort);_logCollector = new ResultCollector("LOG", logPort);_printCollector = new ResultCollector("OUT", printPort);// start them all_resultCollector.start();_logCollector.start();_printCollector.start();// wait collectors to finish thier jobstry {_logCollector.join();_printCollector.join();_resultCollector.join();} catch (InterruptedException ie) {// ignore}}} catch (Exception e) {        throw new CoreException(new Status(IStatus.ERROR, ServerPlugin.PLUGIN_ID, IStatus.OK,                                ServerPlugin.getMessage("slinkserver.connection.error.cmd"), e));}return _evaluateResults(resultPort);}/** * Sends a shutdown command to the server. */public void doShutdown() throws CoreException {// send shutdown commandsendCommand("SHUTDOWN", (String[])null);// close down sockettry {if (_sasSocket != null) _sasSocket.close();if (_out != null) _out.close();} catch (IOException ioe) {        throw new CoreException(new Status(IStatus.ERROR, ServerPlugin.PLUGIN_ID, IStatus.OK,                    ServerPlugin.getMessage("slinkserver.connection.error.shutdown"), ioe));}_sasSocket = null;}/** * Returns the result data as String. */public String getResult() {if (_resultCollector == null) return null;return _resultCollector.getResultAsString();}/** * Returns the log data as String. */public String getLog() {if (_logCollector == null) return null;// we will skip the first and last three lines// as they contain the log output of the PROC PRINT// log redirectionString logText = _logCollector.getResultAsString(3, 3);// finally we filter out doubled linesreturn LogHelper.filter(logText);}/** * Returns the output data as String. */public String getOutput() {if (_printCollector == null) return null;return _printCollector.getResultAsString();}}

?private的域和方法我们不用管,只要看public的,这些东西在我们研读之列:构造器, 方法sendCommand, doShutdown, getResult, getLog, getOutput

?

好,西子之心解读完毕。给她准备更换用的心脏:

package com.anaxima.slink.server.internal;import org.eclipse.core.runtime.CoreException;import com.anaxima.slink.server.ServerPlugin;import com.anaxima.slink.tools.log.ILogger;/** * Make a connection to a SAS Server. *  * @author Thomas Vater * @author Sam Chen * @version 1.0 2008/12/15 15:38:28 */public class RemoteServerConnection extends ServerConnection {// log objectprivate static final ILogger log = ServerPlugin.getLogger();/** * Creates a new server connection object for *  * @param argHost; * @param argPort; */public RemoteServerConnection() {super();boolean connected = SLinkWebServicesClient.connect();if (log.isDebugEnabled()) {log.debug(connected ? "Connected to remote server." : "Failed to connect to remote server.");}}/** * Send a command to the server and returns the result. *  * @paramargCmd * Command to execute. *  * @paramargs * Array of arguments. May be <code>null</code>. *  * @return<code>true</code> if all results were successfully collected. <code>false</code> otherwise. */public boolean sendCommand(String argCmd, String[] args) throws CoreException {return SLinkWebServicesClient.sendCommand(argCmd, args);}/** * Sends a shutdown command to the server. */public void doShutdown() throws CoreException {SLinkWebServicesClient.doShutdown();}/** * Returns the result data as String. */public String getResult() {return SLinkWebServicesClient.getResult();}/** * Returns the log data as String. */public String getLog() {return SLinkWebServicesClient.getLog();}/** * Returns the output data as String. */public String getOutput() {return SLinkWebServicesClient.getOutput();}}

这颗心不同于西子的那颗多愁善感的心,它显得非常轻巧,无忧无虑,把活儿都交给SLinkWebServicesClient干。

?

SLinkWebServicesClient是何许人也?是我专门为新心而造的,他长得也比较清爽:

?

package com.anaxima.slink.server.internal;import java.net.MalformedURLException;import java.util.List;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.codehaus.xfire.annotations.AnnotationServiceFactory;import org.codehaus.xfire.client.XFireProxyFactory;import org.codehaus.xfire.service.Service;import org.eclipse.jface.preference.IPreferenceStore;import com.anaxima.slink.server.IServerPluginConstants;import com.anaxima.slink.server.ServerPlugin;import com.grs.slink.webservices.ISLinkService;import com.grs.slink.webservices.SLinkServiceImpl;/** * SLink Web Services Client *  * @author Sam Chen  * @version 1.0 12/15/2008 14:44:29 */public class SLinkWebServicesClient {public static String getSLinkWebServicesUrl() {// this supports hot swappingIPreferenceStore store = ServerPlugin.getPlugin().getPreferenceStore();return store.getString(IServerPluginConstants.PREFKEY_SLINKWEBSERVICESURL);}private static ISLinkService getSLinkService() {ISLinkService service = null;Service serviceModel = new AnnotationServiceFactory().create(SLinkServiceImpl.class);    try {     service = (ISLinkService) new XFireProxyFactory().create(serviceModel, getSLinkWebServicesUrl()); } catch (MalformedURLException e) {e.printStackTrace();}return service;}private static Log log = LogFactory.getLog(SLinkWebServicesClient.class);private SLinkWebServicesClient(){}public static boolean connect() {return getSLinkService().connect();}public static boolean sendCommand(String argCmd, String[] args) {return getSLinkService().sendCommand(argCmd, args);}public static void doShutdown() {getSLinkService().doShutdown();}public static String getResult() {return getSLinkService().getResult();}public static String getLog() {return getSLinkService().getLog();}public static String getOutput() {return getSLinkService().getOutput();}public static String createFile(List<String> lines) {return getSLinkService().createFile(lines);}}

?

都是些不干重活的,那真正的重活谁干呢?你说对了:既然这儿有个WebServices的Client - SLinkWebServicesClient,肯定背后有个Web Service!

这是他的档案:

package com.grs.slink.webservices;import java.util.List;import javax.jws.WebService;@WebService public interface ISLinkService {public boolean connect();public void doShutdown();public boolean sendCommand(String argCmd, String[] args);public String getResult();public String getLog();public String getOutput();public String createFile(List<String> lines);}

让我们来看他的庐山真面:

package com.grs.slink.webservices;import java.io.File;import java.io.FileWriter;import java.io.IOException;import java.io.PrintStream;import java.io.PrintWriter;import java.net.InetSocketAddress;import java.net.Socket;import java.text.DecimalFormat;import java.util.Iterator;import java.util.List;import javax.jws.WebService;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import com.anaxima.slink.server.internal.ResultCollector;import com.anaxima.slink.tools.LogHelper;@WebService( serviceName = "SLinkService", endpointInterface = "com.grs.slink.webservices.ISLinkService" ) /** * SLink service implementation *  * @author Sam Chen * @version 1.0 12/15/2008 13:33 */public class SLinkServiceImpl implements ISLinkService {private static boolean connected;/** * Format for ports. */private static final DecimalFormat PORTFMT = new DecimalFormat("00000");/** * Connect retries before failure. */private static final int CONNECT_RETRY = 20;/** * Connect wait before next retry. */private static final int CONNECT_WAIT = 5000;/** * Host name to connect to. */private String _host = "localhost";/** * Port number to connect with. */private int _port = 5999;public void setPort(int port) {_port = port;}/** * Start port number for result connection. */private int _startResultPort = 20000;public void setStartResultPort(int startResultPort) {_startResultPort = startResultPort;}/** * Maximum port number for result connection. */private int _endResultPort = 29999;public void setEndResultPort(int endResultPort) {_endResultPort = endResultPort;}/** * Current result port. */private int _resultPort;/** * SLink server communication socket. */private static Socket _sasSocket;/** * SLink server communication print stream. */private PrintStream _out;/** * Result data collector. */private ResultCollector _resultCollector;/** * Log data collector. */private ResultCollector _logCollector;/** * Output data collector. */private ResultCollector _printCollector;private static final Log log = LogFactory.getLog(SLinkServiceImpl.class);/** * Format port numer into 5 digits. * @param argPortNo * @return Formatet port number. */private String _formatPort(int argPortNo) {return PORTFMT.format(argPortNo);}/** * Returns the next result port. This method implements a round robin * distribution of ports. *  * @return Next result port. */private int _nextPort() {int next = _resultPort++;if (_resultPort >= _endResultPort) _resultPort = _startResultPort;return next;}/** * Evaluate results. */private boolean _evaluateResults(int argResultPort) {boolean retOk = _resultCollector != null && !_resultCollector.isAlive() && !_resultCollector.hasError();boolean logOk = _logCollector != null && !_logCollector.isAlive() && !_logCollector.hasError();boolean prnOk = _printCollector != null && !_printCollector.isAlive() && !_printCollector.hasError();if (!retOk) {System.out.println("RET result FAILED.");if (_resultCollector != null) System.out.println(_resultCollector.getException());}if (argResultPort == 99999) return retOk;if (!logOk) {System.out.println("LOG result FAILED.");if (_logCollector != null) System.out.println(_logCollector.getException());}if (!prnOk) {System.out.println("PRINT result FAILED.");if (_printCollector != null) System.out.println(_printCollector.getException());}return (retOk && logOk && prnOk);}public boolean connect() {if (this.connected) {return true;}_resultPort = _startResultPort;// set up connection to SLink serverint retry = 0;while (retry < CONNECT_RETRY && _out == null) {try {_sasSocket = new Socket();if (log.isInfoEnabled()) {log.info("Trying to connect " + _host + ":" + _port + "...");}_sasSocket.connect(new InetSocketAddress(_host, _port), 0);_out = new PrintStream(_sasSocket.getOutputStream());} catch (IOException ioe) {if (log.isDebugEnabled()) {log.debug("slinkserver.connection.error.backend", ioe);}_sasSocket = null;_out = null;try {Thread.sleep(CONNECT_WAIT);} catch (InterruptedException ir) {// ignore;}retry++;}}// TODO: Notify user if connection to SLink backend failedif (_out == null) {log.error("slinkserver.connection.error.backend.final");} else {if (log.isInfoEnabled()) {log.info("Connected to " + _host + ":" + _port + ".");}this.connected = true;}return this.connected;}public void doShutdown() {// send shutdown commandsendCommand("SHUTDOWN", (String[])null);// close down sockettry {if (_sasSocket != null) _sasSocket.close();if (_out != null) _out.close();} catch (IOException ioe) {        throw new RuntimeException("slinkserver.connection.error.shutdown", ioe);}_sasSocket = null;}public String getLog() {if (_logCollector == null) return null;// we will skip the first and last three lines// as they contain the log output of the PROC PRINT// log redirectionString logText = _logCollector.getResultAsString(3, 3);// finally we filter out doubled linesreturn LogHelper.filter(logText);}public String getOutput() {if (_printCollector == null) return null;return _printCollector.getResultAsString();}public String getResult() {if (_resultCollector == null) return null;return _resultCollector.getResultAsString();}public boolean sendCommand(String argCmd, String[] args) {int resultPort;int logPort;int printPort;try {if ("SHUTDOWN".equalsIgnoreCase(argCmd)) {resultPort = 99999;logPort = 99999;printPort = 99999;} else {resultPort = _nextPort();logPort = _nextPort();printPort = _nextPort();// Code added by Sam Chen on 12/12/2008 10:24 ==>if (log.isInfoEnabled()) {log.info("resultPort: " + resultPort + "; logPort: " + logPort + "; printPort: " + printPort);}// Code added by Sam Chen on 12/12/2008 10:24 <==}// send ports: resultPort, logPort and printPort_out.println(_formatPort(resultPort));_out.println(_formatPort(logPort));_out.println(_formatPort(printPort));// send command_out.println(argCmd.toUpperCase());// send number of args_out.println((args==null)?"0":""+args.length);// send argumentsif (args != null) {for (int i=0; i<args.length; i++) {_out.println(args[i]);}}// send SYNC_out.println("SYNC");_out.flush();if (resultPort != 99999) {// setup result collectors_resultCollector = new ResultCollector("RET", resultPort);_logCollector = new ResultCollector("LOG", logPort);_printCollector = new ResultCollector("OUT", printPort);// start them all_resultCollector.start();_logCollector.start();_printCollector.start();// wait collectors to finish thier jobstry {_logCollector.join();_printCollector.join();_resultCollector.join();} catch (InterruptedException ie) {// ignore}}} catch (Exception e) {        throw new RuntimeException("slinkserver.connection.error.cmd", e);}return _evaluateResults(resultPort);}public String createFile(List<String> lines) {String ret = "";try {File dest = File.createTempFile("sas_tmp_", ".sas");PrintWriter pw = new PrintWriter(new FileWriter(dest));for (Iterator<String> it = lines.iterator(); it.hasNext(); ) {pw.println(it.next());}            pw.flush();            pw.close();log.info("SAS src code copied to " + dest.getAbsolutePath());ret = dest.getAbsolutePath();} catch (Exception x) {log.error("Error occurred creating temporary SAS src file.");}return ret;}}

?我已经把西子脆弱的心里装的那些忧愁全部转移到了这里。(关于java webservices的开发,可参见拙作《Web Services应用实例 -- Java Web App远程调用SAS程序的解决方案》http://sam-ds-chen.iteye.com/blog/180905?)

?

?

在SAS服务器上部署好web services并启动之后,执行换心术最后一步:

_connection = new ServerConnection("localhost", _port, _portReplyStart, _portReplyEnd);

?换成

_connection = new RemoteServerConnection();

?

编译,打包,覆盖旧插件,启动Ganymede... 终于可以在自己的机器上做SAS开发了。下班,回家。

?

?

?

?

热点排行