001 package creditReport;
002
003 /**
004 * <p>Credit reporting service. This service simulates constructing
005 * a credit report from multiple secondary sources of information.
006 * It uses two external services, one representing a bank and the
007 * other representing the Internal Revenue Service (IRS).</p>
008 *
009 * <p>The @jws:conversation-lifetime max-idle-time tag controls how
010 * long a conversational instance of this service will survive without
011 * seeing activity.</p>
012 *
013 * <p>Conversations represent resources: they shouldn't be left around.</p>
014 * @common:target-namespace namespace="http://workshop.bea.com/CreditReport"
015 * @jws:conversation-lifetime max-age="1 hour" max-idle-time="30 minutes"
016 * @common:xmlns namespace="http://openuri.org/bea/samples/workshop/creditReport" prefix="ns0"
017 */
018
019
020 public class CreditReport implements com.bea.jws.WebService
021 {
022 /**
023 * @common:control
024 */
025 private creditReport.IRSControl irsControl;
026
027 /**
028 * @common:control
029 */
030 private creditReport.BankControl bankControl;
031
032 /*
033 * <p>ReportResult is an inner class used to represent a complete
034 * credit report. It is used to return report responses to
035 * the client.</p>
036 *
037 * <p>Inner classes that are used outside the parent class
038 * MUST be declared "public static" and they MUST have
039 * a public no-argument constructor.</p>
040 */
041 public static class ReportResult implements java.io.Serializable
042 {
043 public String bank;
044 public String tax;
045
046 public ReportResult() {}
047 }
048
049
050
051
052
053 /**
054 * <p>Here we declare some persistent storage used
055 * to store intermediate results.<p>
056 *
057 * <p>All member variables of the Java class become
058 * persistent in the presence of a @common:conversation
059 * start tag on one or more methods.</p>
060 */
061 public String taxReport = null;
062 public String bankReport = null;
063
064 public Callback callback;
065
066 /**
067 * <p>A Service can have an inner interface called
068 * Callback if it wants to have automatic (and WSDL)
069 * support for sending asynchronous messages back to
070 * the client.</p>
071 *
072 * <p>The methods in the callback interface are published in
073 * the .wsdl file for this service.</p>
074 *
075 * <p>Note that callbacks are asynchronous messages to the
076 * client. It may not be possible for these messages
077 * to pass through firewalls.</p>
078 */
079 public interface Callback
080 {
081 /**
082 * <p>We call this method whenever we get some new data, to
083 * tell our client what kind of new data we have. We
084 * don't transmit the complete data, just a status
085 * message.</p>
086 *
087 * <p>We've declared this as a buffered method so that
088 * it's queued when we send it. That way we don't sit
089 * around waiting for the client to process it. Only
090 * methods that return 'void' may be buffered.</p>
091 *
092 * @jws:conversation phase="continue"
093 * @common:message-buffer enable="true"
094 */
095 void onProgressNotify(String progressMsg);
096
097 /**
098 * <p>We call this method to deliver the final credit
099 * report once we're completely done (both external
100 * services have completed).</p>
101 *
102 * <p>We define the format of the message this
103 * callback contains by using a custom XQuery map.
104 * An XQuery map is like an XML map, except that it
105 * uses XQuery expressions to retrieve values that should
106 * be inserted into the message. </p>
107 *
108 * @jws:conversation phase="finish"
109 *
110 * @common:message-buffer enable="true"
111 * @jws:parameter-xml schema-element="ns0:creditReport" xquery::
112 * declare namespace ns0="http://workshop.bea.com/CreditReport"
113 * declare namespace ns1="http://openuri.org/bea/samples/workshop/creditReport"
114
115 * <ns1:creditReport>
116 * <ns1:bankReport>{data($input//ns0:bank)}</ns1:bankReport>
117 * <ns1:taxReport>{data($input//ns0:tax)}</ns1:taxReport>
118 * </ns1:creditReport>
119 * ::
120 */
121 void onReportDone(ReportResult resultMsg);
122 }
123
124 /**
125 * <p>Request a credit report from our service.</p>
126 *
127 * <p>Since it may take some time for us to complete
128 * the report (we have to wait until both of our
129 * requests to external services complete), this
130 * methods has no return value. We will return the
131 * result to the client at a later time via the
132 * onReportDone() callback, above.</p>
133 *
134 * <p>We start a conversation so that per-client
135 * information will be persisted and correlated.
136 * There may be several clients using this service
137 * simultaneously. Conversations keep track of
138 * data and message traffic on a per-client basis
139 * automatically.</p>
140 *
141 * <p>We add the @common:message-buffer tag so the client
142 * doesn't syncrhonously wait for a return from
143 * this request.</p>
144 *
145 * @common:operation
146 * @jws:conversation phase="start"
147 * @common:message-buffer enable="true"
148 */
149 public void requestReport(String ssn)
150 {
151 // Request information from the bank
152 bankControl.startCustomerAnalysis(ssn);
153
154 // Request information from the IRS
155 irsControl.requestTaxReport(ssn);
156
157 /*
158 * Both of the external services will return
159 * their responses to us via callbacks that
160 * we will recieve via the handlers
161 * bank_onDeliverAnalysis and irs_onDeliverTaxReport,
162 * below. So we're done initiating the request.
163 */
164 return;
165 }
166
167 /**
168 * <p>Request the current status of the request.</p>
169 *
170 * <p>For our impatient customers, we can give them
171 * partial results whenever they ask for them.</p>
172 *
173 * <p>Since this only makes sense after a request
174 * is initiated (ie., a conversation is started),
175 * this is a continue method that runs
176 * in the context of an existing conversation.</p>
177 *
178 * <p>The current result is delivered as an XML
179 * message with its format controlled by
180 * an XQuery map.</p>
181 *
182 * @common:operation
183 * @jws:conversation phase="continue"
184 * @jws:return-xml schema-element="ns0:creditReportReturn" xquery::
185 * declare namespace ns0="http://workshop.bea.com/CreditReport"
186 * declare namespace ns1="http://openuri.org/bea/samples/workshop/creditReport"
187
188 * <ns1:creditReportReturn>
189 * <ns1:bankReport>{data($input//ns0:bank)}</ns1:bankReport>
190 * <ns1:taxReport>{data($input//ns0:tax)}</ns1:taxReport>
191 * </ns1:creditReportReturn>
192 * ::
193 */
194 public ReportResult getCurrentStatus()
195 {
196 /*
197 * Call an internal helper method to construct
198 * an intermediate result.
199 */
200 return assembleResult();
201 }
202
203 /**
204 * <p>Cancel the credit report request.</p>
205 *
206 * <p>This is marked as a finish method so that the
207 * conversation is automatically ended when we
208 * finish processing this message.</p>
209 *
210 * <p>We've declared this as a buffered method so the
211 * client doesn't sit around waiting for a return.</p>
212 *
213 * @common:operation
214 * @jws:conversation phase="finish"
215 * @common:message-buffer enable="true"
216 */
217 public void cancelReport()
218 {
219 /*
220 * If we haven't heard form the bank, cancel
221 * the request to the bank.
222 */
223 if (bankReport == null)
224 {
225 bankControl.cancelAnalysis();
226 }
227
228 /*
229 * If we haven't heard form the IRS, cancel
230 * the request to the IRS.
231 */
232 if (taxReport == null)
233 {
234 irsControl.cancelReport();
235 }
236 }
237
238 /**
239 * <p>Handler for the onDeliverAnalysis callback of the Bank.jws
240 * web service.</p>
241 *
242 * <p>The name of the handler is always the variable name of the
243 * service control ('bank' in this case), followed by an
244 * underscore and the name of the callback.</p>
245 */
246 public void bankControl_onDeliverAnalysis(String analysisResult)
247 {
248 /*
249 * Store the bank result in persistent storage.
250 */
251 bankReport = analysisResult;
252
253 /*
254 * Notify the client that we have recieved results
255 * from the bank.
256 */
257 callback.onProgressNotify("Bank Report Received");
258
259 /*
260 * Check to see if all results have been received.
261 * If so, checkIfDone will send the completed
262 * results.
263 */
264 checkIfDone();
265 }
266
267 /**
268 * <p>Handler for the onDeliverTaxReport callback of the IRS.jws
269 * web service.</p>
270 *
271 * <p>The name of the handler is always the variable name of the
272 * service control ('irs' in this case), followed by an
273 * underscore and the name of the callback.</p>
274 */
275 public void irsControl_onDeliverTaxReport(String report)
276 {
277 /*
278 * Store the IRS result in persistent storage.
279 */
280 taxReport = report;
281
282 /*
283 * Notify the client that we have recieved results
284 * from the IRS.
285 */
286 callback.onProgressNotify("Tax Report Received");
287
288 /*
289 * Check to see if all results have been received.
290 * If so, checkIfDone will send the completed
291 * results.
292 */
293 checkIfDone();
294 }
295
296 /**
297 * A private helper that builds our simple credit report,
298 * using the current (possibly incomplete) results.
299 */
300 private ReportResult assembleResult()
301 {
302 ReportResult result = new ReportResult();
303
304 /*
305 * Java includes the ?: construct as a shorthand way of
306 * coding if-then-else. The statement takes the form:
307 *
308 * value = condition ? value-if-true : value-if-false
309 *
310 * If condition evaluates to true, the value-if-true
311 * expression is evaluated and the result is assigned
312 * to value. If condition evaluates to false, the
313 * value-if-false expression is evaluated and the
314 * result is assigned to value.
315 */
316 result.bank = (bankReport == null) ? "Not Received" : bankReport;
317 result.tax = (taxReport == null) ? "Not Received" : taxReport;
318
319 return result;
320 }
321
322 /**
323 * A private helper that may call "callback.onReportDone" if
324 * we're actually done.
325 */
326 private void checkIfDone()
327 {
328 /*
329 * If all results are back from external services...
330 */
331 if (bankReport != null && taxReport != null)
332 {
333 /*
334 * ... call the client with the completed results.
335 */
336 callback.onReportDone(assembleResult());
337 }
338 return;
339 }
340 }
|