📄 xmlscriptaccess.java
字号:
/*------------------------------------------------------------------------------Name: XmlScriptAccess.javaProject: xmlBlaster.orgCopyright: xmlBlaster.org, see xmlBlaster-LICENSE fileComment: Bean to export with Windows ActiveX bridge------------------------------------------------------------------------------*/package org.xmlBlaster.client.activex;import java.io.ByteArrayOutputStream;import java.io.StringReader;import java.io.OutputStream;import java.io.Reader;import java.util.Properties;import java.beans.SimpleBeanInfo;import EDU.oswego.cs.dl.util.concurrent.Latch; // http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.htmlimport java.util.logging.Logger;import java.util.logging.Level;import org.xmlBlaster.util.Global;import org.xmlBlaster.util.XmlBlasterException;import org.xmlBlaster.util.def.ErrorCode;import org.xmlBlaster.client.script.XmlScriptClient;import org.xmlBlaster.client.script.XmlScriptInterpreter;import org.xmlBlaster.client.I_Callback;import org.xmlBlaster.client.SynchronousCache;import org.xmlBlaster.client.protocol.I_CallbackServer;import org.xmlBlaster.client.qos.ConnectQos;import org.xmlBlaster.client.qos.ConnectReturnQos;import org.xmlBlaster.client.qos.DisconnectQos;import org.xmlBlaster.client.key.UpdateKey;import org.xmlBlaster.client.qos.UpdateQos;import org.xmlBlaster.client.key.GetKey;import org.xmlBlaster.client.key.SubscribeKey;import org.xmlBlaster.client.key.UnSubscribeKey;import org.xmlBlaster.client.key.EraseKey;import org.xmlBlaster.client.qos.GetQos;import org.xmlBlaster.client.qos.PublishReturnQos;import org.xmlBlaster.client.qos.SubscribeQos;import org.xmlBlaster.client.qos.SubscribeReturnQos;import org.xmlBlaster.client.qos.EraseQos;import org.xmlBlaster.client.qos.EraseReturnQos;import org.xmlBlaster.client.qos.UnSubscribeQos;import org.xmlBlaster.client.qos.UnSubscribeReturnQos;import org.xmlBlaster.util.MsgUnit;/** * This bean can be exported to a Microsoft dll (ActiveX component) and * be accessed by C# or Visual Basic.Net * <p> * Here we support XML scripting access as described in the <i>client.script</i> requirement * by calling <code>sendRequest()</code> or alternatively you can use the methods * like <code>publishStr()</code> or <code>subscribe()</code> directly. The latter * methods have the advantage to return a ready parsed object to the ActiveX component, * for example Visual Basic can directly call all methods of <code>SubscribeReturnQos</code> * which is returned by <code>subscribe()</code>. * </p> * <p> * Compile the ActiveX control with <code>build activex</code> and see Visual Basic * and C# samples in directory <code>xmlBlaster/demo/activex</code>. * </p> * <p> * As events into ActiveX can't have a return value and can't throw * an exception back to us we handle it here as a callback, for example * Visual Basic needs to call <code>sendUpdateReturn()</code> or <code>sendUpdateException()</code> after * processing a message received by <code>update()</code>. * Our update thread blocks until one of those two methods is called, however * the blocking times out after 10 minutes which is adjustable with * the property <code>client/activex/responseWaitTime</code> given in milli seconds. * </p> * <p> * One instance of this can hold one permanent connection to the xmlBlaster server, * multi threaded access is supported. * </p> * * @see <a href="http://www.xmlblaster.org/xmlBlaster/doc/requirements/client.script.html">client.script requirement</a> * @see <a href="http://java.sun.com/j2se/1.4.2/docs/guide/beans/axbridge/developerguide/index.html">ActiveX Bridge Developer Guide</a> * @author <a href="mailto:xmlBlaster@marcelruff.info">Marcel Ruff</a> */public class XmlScriptAccess extends SimpleBeanInfo implements I_Callback { private static String ME = "XmlScriptAccess"; private final Global glob; private static Logger log = Logger.getLogger(XmlScriptAccess.class.getName()); private XmlScriptInterpreter interpreter; private Reader reader; private OutputStream outStream; private UpdateListener updateListener; // As events into ActiveX can't have a return value and can't throw // an exception back to us we handle it here as a callback private Latch updateReturnLatch; private String updateReturnQos; private XmlBlasterException updateReturnException; private long responseWaitTime; /** * Create a new access bean. * We read a xmlBlaster.properties file if one is found */ public XmlScriptAccess() { this.glob = new Global(); // Reads xmlBlaster.properties // Wait max 10 minutes for update() method in C#/VB to return: this.responseWaitTime = this.glob.getProperty().get("client/activex/responseWaitTime", 1000L * 60L * 10L); if (log.isLoggable(Level.FINER)) log.finer("Calling ctor of XmlScriptAccess, responseWaitTime=" + this.responseWaitTime); // Use socket protocol as default setting String protocol = this.glob.getProperty().get("protocol", ""); if ("".equals(protocol)) { try { this.glob.getProperty().set("protocol", "SOCKET"); } catch (XmlBlasterException e) { log.severe("Failed setting SOCKET protocol, we continue nevertheless: " + e.toString()); } } } /** * Add a C# / VisualBasic listener over the ActiveX bridge. * This method is called automatically when activating the bridge */ public void addUpdateListener(UpdateListener updateListener) /* throws java.util.TooManyListenersException */ { log.info("Registering update listener"); if (log.isLoggable(Level.FINEST)) Thread.dumpStack(); this.updateListener = updateListener; } /** * Remove a C# / VisualBasic listener. * This method is called automatically when deactivating the bridge */ public void removeUpdateListener(UpdateListener updateListener) { log.info("Removing update listener"); if (log.isLoggable(Level.FINEST)) Thread.dumpStack(); this.updateListener = null; } /** * Fire an event into C# / VisualBasic containing an updated message. * <br /> * Note: The ActiveX event can't convey a return value or an exception back * to us. There for we block the thread and wait until the * activeX component has delivered us a return value or an exception by * calling setUpdateReturn() or setUpdateException() */ protected synchronized String notifyUpdateEvent(String cbSessionId, UpdateKey key, byte[] content, UpdateQos qos) throws XmlBlasterException { if (this.updateListener == null) { log.warning("No updateListener is registered, ignoring " + key.toXml()); return "<qos><state id='WARNING'/></qos>"; } UpdateEvent ev = new UpdateEvent(this, cbSessionId, key, content, qos); if (log.isLoggable(Level.FINE)) log.fine("Notifying updateListener with new message " + key.toXml()); this.updateReturnLatch = new Latch(); this.updateListener.update(ev); boolean awaikened = false; while (true) { try { if (log.isLoggable(Level.FINE)) log.fine("notifyUpdateEvent() Entering wait ..."); awaikened = this.updateReturnLatch.attempt(this.responseWaitTime); // block max. milliseconds break; } catch (InterruptedException e) { log.warning("Waking up (waited on " + key.getOid() + " update response): " + e.toString()); // try again } } try { if (awaikened) { if (this.updateReturnQos != null) { if (log.isLoggable(Level.FINE)) log.fine("Notifying updateListener done: returned '" + this.updateReturnQos + "'"); return this.updateReturnQos; } else if (this.updateReturnException != null) { log.warning("Update failed: " + this.updateReturnException.getMessage()); throw this.updateReturnException; } else { log.severe("Update failed, no return available"); throw new XmlBlasterException(this.glob, ErrorCode.USER_UPDATE_ERROR, ME, "Update to ActiveX failed, no return available"); } } else { String str = "Timeout of " + this.responseWaitTime + " milliseconds occured when waiting on " + key.getOid() + " return value"; log.warning(str); throw new XmlBlasterException(glob, ErrorCode.USER_UPDATE_ERROR, ME, str); } } finally { this.updateReturnLatch = null; } } /** * ActiveX code needs to call this method to set the return value * for the current update message. * Alternatively you can call setUpdateException() to pass back * an exception. * <br /> * Note: You have to call setUpdateReturn() OR setUpdateException() * for each update message to release the blocking thread! * * @param updateReturnQos for example "<qos><state id='OK'/></qos>" * @see <a href="http://www.xmlBlaster.org/xmlBlaster/doc/requirements/interface.update.html">The interface.update requirement</a> */ public void setUpdateReturn(String updateReturnQos) { if (this.updateReturnLatch == null) { log.warning("Ignoring setUpdateReturn(), updateReturnLatch == null, probably a timeout occurred"); return; } this.updateReturnQos = updateReturnQos; this.updateReturnException = null; this.updateReturnLatch.release(); if (log.isLoggable(Level.FINER)) log.finer("setUpdateReturn() called"); } /** * ActiveX code can call this method to return an exception for * the current update message * @param errorCode Only known ErrorCode strings of type "user.*" are allowed * @see org.xmlBlaster.util.def.ErrorCode */ public void setUpdateException(String errorCode, String message) { if (this.updateReturnLatch == null) { log.warning("Ignoring setUpdateException(), updateReturnLatch == null, probably a timeout occurred"); return; } this.updateReturnQos = null; ErrorCode code = null; try { code = ErrorCode.toErrorCode(errorCode); } catch (IllegalArgumentException e) { log.warning("Don't know error code '" + errorCode + "', changing it to " + ErrorCode.USER_UPDATE_ERROR.toString()); message += ": original errorCode=" + errorCode; code = ErrorCode.USER_UPDATE_ERROR; } this.updateReturnException = new XmlBlasterException(this.glob, code, ME, message); this.updateReturnLatch.release(); if (log.isLoggable(Level.FINER)) log.finer("setUpdateException() called"); } /** * Access a Properties object to be used later for initialize(). * @return We create a new instance for you */ public Properties createPropertiesInstance() { return new Properties(); } /** * Initialize the environment. */ public void initialize(Properties properties) { this.glob.init(properties); } /** * Initialize the environment. * If you use the initialize(Properties) variant or this method makes no difference. * @param args Command line arguments for example { "-protocol", SOCKET, "-logging", "FINE" }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -