7 # Instead of 'use'ing freeside modules on the fly below, just preload them now.
22 FS::XMLRPC - Object methods for handling XMLRPC requests
28 $xmlrpc = new FS::XMLRPC;
30 ($error, $response_xml) = $xmlrpc->serve($request_xml);
34 The FS::XMLRPC object is a mechanisim to access read-only data from freeside's subroutines. It does not, at least not at this point, give you the ability to access methods of freeside objects remotely. It can, however, be used to call subroutines such as FS::cust_main::smart_search and FS::Record::qsearch.
36 See the serve method below for calling syntax.
44 Provides a FS::XMLRPC object used to handle incoming XMLRPC requests.
54 $self->{_coder} = new Frontier::RPC2;
60 =item serve REQUEST_XML_SCALAR
62 The serve method takes a scalar containg an XMLRPC request for one of freeside's subroutines (not object methods). Parameters passed in the 'methodCall' will be passed as a list to the subroutine untouched. The return value of the called subroutine _must_ be a freeside object reference (eg. qsearchs) or a list of freeside object references (eg. qsearch, smart_search), _and_, the object(s) returned must support the hashref method. This will be checked first by calling UNIVERSAL::can('FS::class::subroutine', 'hashref').
64 Return value is an XMLRPC methodResponse containing the results of the call. The result of the subroutine call itself will be coded in the methodResponse as an array of structs, regardless of whether there was many or a single object returned. In other words, after you decode the response, you'll always have an array.
70 my ($self, $request_xml) = (shift, shift);
73 my $coder = $self->{_coder};
74 my $call = $coder->decode($request_xml);
76 warn "Got methodCall with method_name='" . $call->{method_name} . "'"
79 $response_xml = $coder->encode_response(&_serve($call->{method_name}, $call->{value}));
81 return ('', $response_xml);
85 sub _serve { #Subroutine, not method
87 my ($method_name, $params) = (shift, shift);
90 #die 'Called _serve without parameters' unless ref($params) eq 'ARRAY';
91 $params = [] unless (ref($params) eq 'ARRAY');
93 if ($method_name =~ /^(\w+)\.(\w+)/) {
95 #my ($class, $sub) = split(/\./, $method_name);
96 my ($class, $sub) = ($1, $2);
97 my $fssub = "FS::${class}::${sub}";
98 warn "fssub: ${fssub}" if $DEBUG;
99 warn "params: " . Dumper($params) if $DEBUG;
103 if ($class eq 'Conf') { #Special case for FS::Conf because we need an obj.
105 if ($sub eq 'config') {
106 my $conf = new FS::Conf;
107 @result = ($conf->config(@$params));
109 warn "FS::XMLRPC: Can't call undefined subroutine '${fssub}'";
114 unless (UNIVERSAL::can("FS::${class}", $sub)) {
115 warn "FS::XMLRPC: Can't call undefined subroutine '${fssub}'";
116 # Should we encode an error in the response,
117 # or just break silently to the remote caller and complain locally?
123 my $fssub = "FS::${class}::${sub}";
124 @result = (&$fssub(@$params));
128 warn "FS::XMLRPC: Error while calling '${fssub}': $@";
134 if ( scalar(@result) == 1 && ref($result[0]) eq 'HASH' ) {
136 } elsif (grep { UNIVERSAL::can($_, 'hashref') ? 0 : 1 } @result) {
137 #warn "FS::XMLRPC: One or more objects returned from '${fssub}' doesn't " .
138 # "support the 'hashref' method.";
140 # If they're not FS::Record decendants, just return the results unmap'd?
141 # This is more flexible, but possibly more error-prone.
144 return [ map { $_->hashref } @result ];
146 } elsif ($method_name eq 'version') {
147 return [ $FS::VERSION ];
150 warn "Unhandled XMLRPC request '${method_name}'";