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