NAME
Business::cXML - Perl implementation of cXML messaging
SYNOPSIS
Respond to an incoming request:
use Business::cXML;
$cxml = new Business::cXML (
local => 'https://example.com/our/cxml',
handlers => {
PunchOutSetup => {
__handler => sub { ... },
operationAllowed => 'create',
},
},
);
# Calls $res->reply_to($req), so to/from/sender are probably OK.
$output_xml_string = $cxml->process($input_xml_string);
# Send output to requestor...
Send a request to a server:
use Business::cXML;
$cxml = new Business::cXML (
remote => 'https://example.com/rest/cxml',
secret => 'somesecrettoken',
);
$req = $cxml->new_request('PunchOutSetup');
$req->from(id => '123456', domain => 'DUNS'); # Also sets Sender by default
$req->to(id => '654321', domain => 'NetworkId');
# Populate request, see Business::cXML::Transmission documentation...
$res = $cxml->send($req);
# Do something with $res, the Business::cXML::Transmission response received...
Create a one-way message:
use Business::cXML;
$cxml = new Business::cXML;
$msg = $cxml->new_message('PunchOutOrder');
$msg->from(id => '123456', domain => 'DUNS'); # Also sets Sender by default
$msg->to(id => '654321', domain => 'NetworkId');
# Populate message, see Business::cXML::Transmission documentation...
print $cxml->stringify($msg, url => '...'); # Transmission in cXML-Base64 in an HTML FORM
DESCRIPTION
Dispatch incoming HTTP/HTTPS requests and respond to them. Send outgoing requests and parse responses. Prepare and parse one-way messages.
As a convention, cXML refers to overall messages as "transmissions" to distinguish from Message
type payloads. This library includes native Perl modules for the following transmission types:
Business::cXML::Request::PunchOutSetup / Business::cXML::Response::PunchOutSetup
Planned: Request::Order / Response::Order
Specifically NOT implemented are:
Attachments
Cryptographic signatures
Requesting the remote side's capabilities profile and restricting ourselves to it
Motivation & Future Development
While the above may implement a relatively small portion of the whole cXML specification, which is designed to describe every business-to-business transaction imaginable world-wide, it does fully satisfy our need (see "ACKNOWLEDGEMENTS") to act as a "punch-out" supplier to our Ariba/PeopleSoft/SAP/etc corporate clients.
The design is completely modular (see Business::cXML::Object) and uses XML::LibXML under the hood, to help simplify future efforts to cover more of the standard.
METHODS
new( %options )
-
Returns a fresh cXML handler.
Options useful to send requests and receive responses:
remote
-
HTTP/HTTPS URL where to POST requests
Options useful to process requests and emit responses:
local
-
HTTP/HTTPS URL to publish where clients can reach this handler
secret
-
Secret keyword expected by remote server
sender_callback
-
Subroutine, passed to "sender_callback()".
- log_level
-
One of:
CXML_LOG_NOTHING
(default),CXML_LOG_ERR
,CXML_LOG_WARN
,CXML_LOG_INFO
,CXML_LOG_DEBUG
,CXML_LOG_TRACE
. AlternatesCXML_LOG_ERROR
andCXML_LOG_WARNING
are also available. - log_callback
-
Subroutine, passed to "log_callback()".
- handlers
-
Hash of handlers, dereferenced and passed to "on()".
sender_callback( $sub )
-
By default, a request's From/Sender credentials are only used to guess response credentials. If you specify a callback here, it will be invoked immediately after XML parsing, before passing to transaction handlers, giving you an opportunity to authenticate the caller.
Your subroutine will be passed 3 arguments:
- 1. The current Business::cXML object
- 2. The Sender Business::cXML::Credential object
- 3. The From Business::cXML::Credential object
If you return a false value, the request will be deemed unauthorized and no handler will be invoked.
If you return anything else, it will be stored and available in the request sender's
_note
property. (See Business::cXML::Credential for details.)Note that cXML From/Sender headers contain information about an entire company you're doing business with. The identity of the specific person triggering the request, if applicable, will be somewhere in contact or extrinsic data in the payload itself.
log_callback( $sub )
-
By default, basic details about log-worthy events are dumped to
STDERR
(filtered according to the current log level). By specifying your own handler, you can do anything else you'd like when informative events occur.Your subroutine will be passed 5 arguments:
- 1. The current Business::cXML object
- 2. The level
-
- CXML_LOG_ERR = 1 = fatal error (on our side)
- CXML_LOG_WARN = 2 = warning (errors on the other end, network issues, etc.)
- CXML_LOG_INFO = 3 = normal operations like receiving or sending transmissions
- CXML_LOG_DEBUG = 4 = additional debugging information about processing requests
- CXML_LOG_TRACE = 5 = full trace logging in some areas
- 3. A possible long-form message describing the event
- 4. A possible cXML transmission string (untouched if input)
- 5. A possible Business::cXML::Transmission object
Successful parsing of a new transmission triggers a level 3 log, whereas failure is a level 2. Failure to produce valid XML from our internal data (which should never occur) is a level 1.
NOTE: Logging is limited to this module. Thus, be sure to use process(), send() and stringify() to trap interesting events in the handling of
Request
,Response
andMessage
transmissions. on( %handlers )
-
Each key in
%handlers
is the bare name of a supported transaction type. For example, if you want to supportPunchOutSetupRequest
, the key isPunchOutSetup
. Each key should point to a hashref specifying any options to declare in ourProfile
.Special key
__handler
is mandatory and should point to a sub which will be called if its type of request is received, valid and optionally authenticated. Your handler will be passed 3 arguments:- 1. The current Business::cXML object
- 2. The Business::cXML::Transmission request
- 3. A ready-to-fill Business::cXML::Transmission response
Be sure to change the response's status, which is a 500 error by default.
The response's to/from/sender is initialized in reciprocity to the request's, so your handler might not need to change much in those.
Keys represent the case-sensitive name of the cXML request without the redundant suffix. For example, a
PunchOutSetupRequest
is our typePunchOutSetup
. Possible keys include:Order
,PunchOutSetup
,StatusUpdate
,GetPending
,Confirmation
,ShipNotice
,ProviderSetup
,PaymentRemittance
.Pings and
Profile
requests are built-in, although you can override the handling of the latter with your own handler if you'd like. process( [$input] )
-
Decodes the
$input
XML string which is expected to be a complete cXML transmission. May invoke one of your handlers declared with on() if appropriate.Returns a string containing a valid cXML document at all times. This document includes any relevant status information determined during processing.
Note that an omitted or empty
$input
is actually valid and results in a "pong" response. new_request( [$type] )
-
Returns a fresh Business::cXML::Transmission ready to be used as a request. Optional
$type
is a convenience shortcut to Business::cXML::Transmission::type(). The request's sender secret will be pre-filled. send( $request )
-
Freeze
$request
, a Business::cXML::Transmission, and attempt sending it to the configured remote server. Returns the received response Business::cXML::Transmission on success,undef
on failure. Note that as per Business::cXML::Transmission::new(), it is also possible that an error arrayref be returned instead of a transmission if parsing failed.In case of failure, you may want to wait a certain amount of time and try again. To give you more options to that effect,
$request
can be either a Business::cXML::Transmission or a string. new_message( [$type] )
-
Returns a fresh Business::cXML::Transmission ready to be used as a stand-alone message. Optional
$type
is passed on to Business::cXML::Transmission::type(). stringify( $message, %args )
-
Convenience wrapper around Business::cXML::Transmission::toForm() which allows you to trap logging events.
VERSION
0.6.11 based on cXML DTD 1.2.036
AUTHOR
Stéphane Lavergne https://github.com/vphantom
ACKNOWLEDGEMENTS
Graph X Design Inc. https://www.gxd.ca/ sponsored this project.
COPYRIGHT & LICENSE
Copyright (c) 2017-2018 Stéphane Lavergne https://github.com/vphantom
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.