1 /*------------------------------------------------------------------------------
  2 Name:      AbstractCallbackExtended.java
  3 Project:   xmlBlaster.org
  4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
  5 ------------------------------------------------------------------------------*/
  6 package org.xmlBlaster.client.protocol;
  7 
  8 import java.util.logging.Logger;
  9 import java.util.logging.Level;
 10 
 11 import org.xmlBlaster.client.key.UpdateKey;
 12 import org.xmlBlaster.client.qos.UpdateQos;
 13 import org.xmlBlaster.util.XmlBlasterException;
 14 import org.xmlBlaster.util.def.Constants;
 15 import org.xmlBlaster.util.def.ErrorCode;
 16 import org.xmlBlaster.util.def.MethodName;
 17 import org.xmlBlaster.util.dispatch.DispatchStatistic;
 18 import org.xmlBlaster.util.Global;
 19 import org.xmlBlaster.authentication.plugins.CryptDataHolder;
 20 import org.xmlBlaster.authentication.plugins.I_ClientPlugin;
 21 import org.xmlBlaster.util.MsgUnitRaw;
 22 
 23 
 24 /**
 25  * This is a little abstract helper class which extends the I_CallbackExtended
 26  * interface to become suited for protocols like xml-rpc. Note that you need to
 27  * extend this class because one of the update methods is abstract.
 28  * <p>
 29  *
 30  * @version $Revision: 1.16 $
 31  * @author <a href="mailto:michele@laghi.eu">Michele Laghi</a>
 32  * @author <a href="mailto:xmlBlaster@marcelruff.info">Marcel Ruff</a>.
 33  */
 34 public abstract class AbstractCallbackExtended implements I_CallbackExtended
 35 {
 36    private String ME = "AbstractCallbackExtended";
 37    protected final Global glob;
 38    private static Logger log = Logger.getLogger(AbstractCallbackExtended.class.getName());
 39    protected boolean updateBulkAck;
 40    
 41    /**
 42     * @param glob If null we use Global.instance()
 43     */
 44    public AbstractCallbackExtended(Global glob) {
 45       this.glob = (glob==null) ? Global.instance() : glob;
 46 
 47    }
 48 
 49    public abstract I_ClientPlugin getSecurityPlugin();
 50    
 51    /**
 52     * Access the statistic holder. 
 53     * Implementing classes should provide a valid statistic handle.
 54     * @return Can be null
 55     */
 56    public DispatchStatistic getDispatchStatistic() {
 57           return null;
 58    }
 59 
 60    /**
 61     * It parses the string literals passed in the argument list and calls
 62     * subsequently the update method with the signature defined in I_Callback.
 63     * <p>
 64     * This method is invoked by certain protocols only. Others might directly
 65     * invoke the update method with the other signature.
 66     *
 67     * @param cbSessionId The session ID specified by the client which registered the callback
 68     * @param updateKeyLiteral The arrived key (as an xml-string)
 69     * @param content   The arrived message content
 70     * @param updateQosLiteral  Quality of Service of the MsgUnitRaw
 71     *                      (as an xml-string)
 72     * @see I_CallbackExtended
 73     */
 74    public String update(String cbSessionId, String updateKeyLiteral, byte[] content,
 75                       String updateQosLiteral) throws XmlBlasterException
 76    {
 77       // import (decrypt) message
 78       I_ClientPlugin secPlgn = getSecurityPlugin();
 79       if (secPlgn != null) {
 80          MsgUnitRaw in = new MsgUnitRaw(updateKeyLiteral, content, updateQosLiteral);
 81          CryptDataHolder dataHolder = new CryptDataHolder(MethodName.UPDATE, in, null);
 82          MsgUnitRaw msg = secPlgn.importMessage(dataHolder);
 83          updateKeyLiteral = msg.getKey();
 84          content = msg.getContent();
 85          updateQosLiteral = msg.getQos();
 86       }
 87 
 88       // parse XML key and QoS
 89       UpdateKey updateKey = null;
 90       UpdateQos updateQos = null;
 91       try {
 92          updateKey = new UpdateKey(glob, updateKeyLiteral);
 93          //updateKey.init(updateKeyLiteral); // does the parsing
 94          updateQos = new UpdateQos(glob, updateQosLiteral); // does the parsing
 95       }
 96       catch (XmlBlasterException e) {
 97          log.severe("Parsing error: " + e.toString());
 98          throw new XmlBlasterException(glob, ErrorCode.USER_UPDATE_ILLEGALARGUMENT, ME+".update", "Parsing error", e);
 99       }
100 
101       // invoke client code
102       try {
103          // Now we know all about the received message, dump it or do some checks
104          /*
105          if (log.isLoggable(Level.FINEST)) log.dump(ME+".UpdateKey", "\n" + updateKey.toXml());
106          if (log.isLoggable(Level.FINEST)) log.dump(ME+".content", "\n" + new String(content));
107          if (log.isLoggable(Level.FINEST)) log.dump(ME+".UpdateQos", "\n" + updateQos.toXml());
108          */
109          if (log.isLoggable(Level.FINE)) log.fine("Received message [" + updateKey.getOid() + "] from publisher " + updateQos.getSender());
110 
111          String ret = update(cbSessionId, updateKey, content, updateQos);
112 
113          DispatchStatistic statistic = getDispatchStatistic();
114          if (statistic != null) statistic.incrNumUpdate(1);
115          
116          // export (encrypt) return value
117          if (secPlgn != null) {
118             MsgUnitRaw msg = new MsgUnitRaw(null, (byte[])null, ret);
119             CryptDataHolder dataHolder = new CryptDataHolder(MethodName.UPDATE, msg, null);
120             dataHolder.setReturnValue(true);
121             ret = secPlgn.exportMessage(dataHolder).getQos();
122          }
123 
124          return ret;
125       }
126       catch (XmlBlasterException e) {
127          throw e;
128       }
129       catch (Throwable e) {
130          e.printStackTrace();
131          log.warning("Error in client user code of update("+
132                       ((updateKey!=null)?updateKey.getOid():"")+
133                       ((updateQos!=null)?", "+updateQos.getRcvTime():"")+
134                       "): " + e.toString());
135          throw new XmlBlasterException(glob, ErrorCode.USER_UPDATE_INTERNALERROR, ME+".update", "Error in client code, please check your clients update() implementation.", e);
136       }
137    }
138 
139    /**
140     * The oneway variant without a return value or exception
141     * <p />
142     * We match it to the blocking variant. Implement this in your code on demand.
143     */
144    public void updateOneway(String cbSessionId, String updateKeyLiteral, byte[] content, String updateQosLiteral)
145    {
146       try {
147          I_ClientPlugin secPlgn = getSecurityPlugin();
148          if (secPlgn != null) {
149             MsgUnitRaw in = new MsgUnitRaw(updateKeyLiteral, content, updateQosLiteral);
150             CryptDataHolder dataHolder = new CryptDataHolder(MethodName.UPDATE_ONEWAY, in, null);
151             MsgUnitRaw msg = secPlgn.importMessage(dataHolder);
152 
153             updateKeyLiteral = msg.getKey();
154             content = msg.getContent();
155             updateQosLiteral = msg.getQos();
156          }
157 
158          UpdateKey updateKey = new UpdateKey(glob, updateKeyLiteral);
159          UpdateQos updateQos = new UpdateQos(glob, updateQosLiteral);
160          if (log.isLoggable(Level.FINE)) log.fine("Received message [" + updateKey.getOid() + "] from publisher " + updateQos.getSender());
161 
162          update(cbSessionId, updateKey, content, updateQos);
163 
164          DispatchStatistic statistic = getDispatchStatistic();
165          if (statistic != null) statistic.incrNumUpdateOneway(1);
166       }
167       catch (Throwable e) {
168          log.severe("Caught exception, can't deliver it to xmlBlaster server as we are in oneway mode: " + e.toString());
169       }
170    }
171 
172    /**
173     * This is the callback method invoked natively
174     * informing the client in an asynchronous mode about new messages.
175     * <p />
176     * It implements the interface I_CallbackRaw.
177     * <p />
178     * It nicely converts the raw MsgUnitRaw with raw Strings and arrays
179     * in corresponding objects and calls for every received message
180     * the I_Callback.update(), which you need to implement in your code.
181     *
182     * @param msgUnitArr Contains MsgUnitRaw structs (your message) in native form
183     */
184    public String[] update(String cbSessionId, MsgUnitRaw [] msgUnitArr) throws XmlBlasterException
185    {
186       if (msgUnitArr == null) {
187          log.warning("Entering update() with null array.");
188          return new String[0];
189       }
190       if (msgUnitArr.length == 0) {
191          log.warning("Entering update() with 0 messages.");
192          return new String[0];
193       }
194       if (log.isLoggable(Level.FINER)) log.finer("Receiving update of " + msgUnitArr.length + " messages ...");
195 
196       String[] retArr = new String[msgUnitArr.length];
197       for (int ii=0; ii<msgUnitArr.length; ii++) {
198          MsgUnitRaw msgUnit = msgUnitArr[ii];
199          retArr[ii] = update(cbSessionId, msgUnit.getKey(), msgUnit.getContent(), msgUnit.getQos());
200       }
201       if (this.updateBulkAck && retArr.length > 1) {
202          for (int i=0; i < retArr.length; i++) {
203             if (!Constants.RET_OK.equals(retArr[i]) && !"OK".equals(retArr[i]))
204                return new String[] { retArr[i] };
205             return new String[] { retArr[0]};
206          }
207       }
208       return retArr;
209    }
210 
211    /**
212     * The oneway variant without a return value or exception
213     */
214    public void updateOneway(String cbSessionId, org.xmlBlaster.util.MsgUnitRaw[] msgUnitArr)
215    {
216       if (msgUnitArr == null) {
217          log.warning("Entering updateOneway() with null array.");
218          return;
219       }
220       if (msgUnitArr.length == 0) {
221          log.warning("Entering updateOneway() with 0 messages.");
222          return;
223       }
224       if (log.isLoggable(Level.FINER)) log.finer("Receiving updateOneway of " + msgUnitArr.length + " messages ...");
225 
226       for (int ii=0; ii<msgUnitArr.length; ii++) {
227          MsgUnitRaw msgUnit = msgUnitArr[ii];
228          updateOneway(cbSessionId, msgUnit.getKey(), msgUnit.getContent(), msgUnit.getQos());
229       }
230    }
231 
232    /**
233     * The class which extends AbstractCallbackExtended must implement this
234     * method.
235     * <p />
236     * You receive one message, which is completely parsed and checked.
237     *
238     * @param cbSessionId The session ID specified by the client which registered the callback
239     * @param updateKey   The arrived key (as an xml-string)
240     * @param content     The arrived message content
241     * @param updateQos   Quality of Service of the MsgUnitRaw as an xml-string
242     * @see org.xmlBlaster.client.I_Callback
243     */
244    public abstract String update(String cbSessionId, UpdateKey updateKey, byte[] content,
245                                UpdateQos updateQos) throws XmlBlasterException;
246 }


syntax highlighted by Code2HTML, v. 0.9.1