/src/agent/lib/Frontier/RPC2.pm

http://keywatch.googlecode.com/ · Perl · 824 lines · 635 code · 130 blank · 59 comment · 42 complexity · 4c0a28fea4623d7f5a270c8033959499 MD5 · raw file

  1. # ----------------------------------------------------------------------------
  2. # Copyright (C) 1998, 1999 Ken MacLeod
  3. # Frontier::RPC is free software; you can redistribute it
  4. # and/or modify it under the same terms as Perl itself.
  5. #
  6. # $Id: RPC2.pm,v 1.18 2002/08/02 18:35:21 ivan420 Exp $
  7. #
  8. #
  9. # SRS: Added support for SAX parsing in pure Perl (i.e. no expat dependency)
  10. #
  11. # ----------------------------------------------------------------------------
  12. use strict;
  13. package Frontier::RPC2;
  14. use XML::SAX::PurePerl;
  15. #use vars qw{%scalars %char_entities};
  16. my %char_entities = (
  17. '&' => '&',
  18. '<' => '&lt;',
  19. '>' => '&gt;',
  20. '"' => '&quot;',
  21. );
  22. # FIXME I need a list of these
  23. my %scalars = (
  24. 'base64' => 1,
  25. 'boolean' => 1,
  26. 'dateTime.iso8601' => 1,
  27. 'double' => 1,
  28. 'int' => 1,
  29. 'i4' => 1,
  30. 'string' => 1,
  31. );
  32. # Constructor
  33. sub new
  34. {
  35. my $class = shift;
  36. my $self = ($#_ == 0) ? { %{ (shift) } } : { @_ };
  37. bless $self, $class;
  38. if (defined $self->{'encoding'}) {
  39. $self->{'encoding_'} = " encoding=\"$self->{'encoding'}\"";
  40. } else {
  41. $self->{'encoding_'} = "";
  42. }
  43. return $self;
  44. }
  45. sub encode_call
  46. {
  47. my $self = shift; my $proc = shift;
  48. my @text;
  49. push @text, <<EOF;
  50. <?xml version="1.0"$self->{'encoding_'}?>
  51. <methodCall>
  52. <methodName>$proc</methodName>
  53. <params>
  54. EOF
  55. push @text, $self->_params([@_]);
  56. push @text, <<EOF;
  57. </params>
  58. </methodCall>
  59. EOF
  60. return join('', @text);
  61. }
  62. sub encode_response {
  63. my $self = shift;
  64. my @text;
  65. push @text, <<EOF;
  66. <?xml version="1.0"$self->{'encoding_'}?>
  67. <methodResponse>
  68. <params>
  69. EOF
  70. push @text, $self->_params([@_]);
  71. push @text, <<EOF;
  72. </params>
  73. </methodResponse>
  74. EOF
  75. return join('', @text);
  76. }
  77. sub encode_fault {
  78. my $self = shift; my $code = shift; my $message = shift;
  79. my @text;
  80. push @text, <<EOF;
  81. <?xml version="1.0"$self->{'encoding_'}?>
  82. <methodResponse>
  83. <fault>
  84. EOF
  85. push @text, $self->_item({faultCode => $code, faultString => $message});
  86. push @text, <<EOF;
  87. </fault>
  88. </methodResponse>
  89. EOF
  90. return join('', @text);
  91. }
  92. sub serve
  93. {
  94. my $self = shift; my $xml = shift; my $methods = shift;
  95. my $call;
  96. # FIXME bug in Frontier's XML
  97. $xml =~ s/(<\?XML\s+VERSION)/\L$1\E/;
  98. eval { $call = $self->decode($xml) };
  99. if ($@)
  100. {
  101. print "error 1 in server()\n";
  102. return $self->encode_fault(1, "error decoding RPC.\n" . $@);
  103. }
  104. if ($call->{'type'} ne 'call')
  105. {
  106. print "error 2 in server()\n";
  107. return $self->encode_fault(2,"expected RPC \`methodCall', got \`$call->{'type'}'\n");
  108. }
  109. my $method = $call->{'method_name'};
  110. if (!defined $methods->{$method})
  111. {
  112. print "error 3 in server()\n";
  113. return $self->encode_fault(3, "no such method \`$method'\n");
  114. }
  115. my $result;
  116. my $eval = eval { $result = &{ $methods->{$method} }(@{ $call->{'value'} }) };
  117. if ($@)
  118. {
  119. print "error 4 in server()\n";
  120. return $self->encode_fault(4, "error executing RPC \`$method'.\n" . $@);
  121. }
  122. my $response_xml = $self->encode_response($result);
  123. return $response_xml;
  124. }
  125. sub _params
  126. {
  127. my $self = shift; my $array = shift;
  128. my @text;
  129. if(!defined $array)
  130. {
  131. print "Undefined array in _params\n";
  132. }
  133. my $item;
  134. foreach $item (@$array)
  135. {
  136. push (@text, "<param>",
  137. $self->_item($item),
  138. "</param>\n");
  139. }
  140. return @text;
  141. }
  142. sub _item
  143. {
  144. my $self = shift; my $item = shift;
  145. my @text;
  146. my $ref = ref($item);
  147. if (!$ref)
  148. {
  149. push (@text, $self->_scalar ($item));
  150. }
  151. elsif ($ref eq 'ARRAY')
  152. {
  153. push (@text, $self->_array($item));
  154. }
  155. elsif ($ref eq 'HASH')
  156. {
  157. push (@text, $self->_hash($item));
  158. }
  159. elsif ($ref eq 'Frontier::RPC2::Boolean')
  160. {
  161. push @text, "<value><boolean>", $item->repr, "</boolean></value>\n";
  162. }
  163. elsif ($ref eq 'Frontier::RPC2::String')
  164. {
  165. push @text, "<value><string>", $item->repr, "</string></value>\n";
  166. }
  167. elsif ($ref eq 'Frontier::RPC2::Integer')
  168. {
  169. push @text, "<value><int>", $item->repr, "</int></value>\n";
  170. }
  171. elsif ($ref eq 'Frontier::RPC2::Double')
  172. {
  173. push @text, "<value><double>", $item->repr, "</double></value>\n";
  174. }
  175. elsif ($ref eq 'Frontier::RPC2::DateTime::ISO8601')
  176. {
  177. push @text, "<value><dateTime.iso8601>", $item->repr, "</dateTime.iso8601></value>\n";
  178. }
  179. elsif ($ref eq 'Frontier::RPC2::Base64')
  180. {
  181. push @text, "<value><base64>", $item->repr, "</base64></value>\n";
  182. }
  183. elsif ($ref =~ /=HASH\(/)
  184. {
  185. push @text, $self->_hash($item);
  186. }
  187. elsif ($ref =~ /=ARRAY\(/)
  188. {
  189. push @text, $self->_array($item);
  190. }
  191. elsif ($ref eq 'SCALAR')
  192. {
  193. push @text, $self->_scalar($$item);
  194. }
  195. else
  196. {
  197. # Evil hack: assume it's a struct or hash of some sort; this handles
  198. # Struct types as well.
  199. push (@text, $self->_hash($item));
  200. }
  201. return @text;
  202. }
  203. sub _hash
  204. {
  205. my $self = shift; my $hash = shift;
  206. my @text = "<value><struct>\n";
  207. if(!defined $hash)
  208. {
  209. print "Undefined hash in _hash\n";
  210. }
  211. my ($key, $value);
  212. while (($key, $value) = each %$hash)
  213. {
  214. push (@text,
  215. "<member><name>$key</name>",
  216. $self->_item($value),
  217. "</member>\n");
  218. }
  219. push @text, "</struct></value>\n";
  220. return @text;
  221. }
  222. sub _array
  223. {
  224. my $self = shift; my $array = shift;
  225. my @text = "<value><array><data>\n";
  226. if(!defined $array)
  227. {
  228. print "Undefined array in _array\n";
  229. }
  230. my $item;
  231. foreach $item (@$array)
  232. {
  233. push @text, $self->_item($item);
  234. }
  235. push @text, "</data></array></value>\n";
  236. return @text;
  237. }
  238. sub _scalar
  239. {
  240. # Turn off bogus warnings in this scope
  241. local $^W = 0;
  242. my $self = shift; my $value = shift;
  243. if(!defined $value)
  244. {
  245. #print "Undefined element in _scalar\n";
  246. #return "";
  247. # note: <value></nil></value> doesn't seem to be supported
  248. return "<value><string></string></value>";
  249. }
  250. # these are from `perldata(1)'
  251. if ($value =~ /^[+-]?\d+$/)
  252. {
  253. return ("<value><i4>$value</i4></value>");
  254. }
  255. elsif ($value =~ /^(-?(?:\d+(?:\.\d*)?|\.\d+)|([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?)$/)
  256. {
  257. return ("<value><double>$value</double></value>");
  258. }
  259. else
  260. {
  261. $value =~ s/([&<>\"])/$char_entities{$1}/ge;
  262. return ("<value><string>$value</string></value>");
  263. }
  264. }
  265. sub decode
  266. {
  267. my $self = shift; my $string = shift;
  268. # Get a SAX parser. This will fall back to PurePerl.pm if nothing
  269. # else is available.
  270. if(!defined $self->{'handler'})
  271. {
  272. $self->{'handler'} = Frontier::RPC2::SAXHandler->new;
  273. }
  274. #if(!defined $self->{'parser'})
  275. {
  276. $self->{'parser'} = XML::SAX::ParserFactory->parser(Handler => $self->{'handler'});
  277. }
  278. return $self->{'parser'}->parse_string($string);
  279. }
  280. # shortcuts
  281. sub base64 {
  282. my $self = shift;
  283. return Frontier::RPC2::Base64->new(@_);
  284. }
  285. sub boolean
  286. {
  287. my $self = shift;
  288. my $elem = shift;
  289. if(defined $elem && ($elem == 0 or $elem == 1))
  290. {
  291. return Frontier::RPC2::Boolean->new($elem);
  292. }
  293. else
  294. {
  295. print "error in rendering RPC type \`$elem\' not a boolean\n";
  296. return Frontier::RPC2::Boolean->new(0);
  297. #die "error in rendering RPC type \`$elem\' not a boolean\n";
  298. }
  299. }
  300. sub double
  301. {
  302. my $self = shift;
  303. my $elem = shift;
  304. # this is from `perldata(1)'
  305. if(defined $elem && $elem =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/) {
  306. return Frontier::RPC2::Double->new($elem);
  307. } else {
  308. die "error in rendering RPC type \`$elem\' not a double\n";
  309. }
  310. }
  311. sub int {
  312. my $self = shift;
  313. my $elem = shift;
  314. # this is from `perldata(1)'
  315. if(defined $elem && $elem =~ /^[+-]?\d+$/) {
  316. return Frontier::RPC2::Integer->new($elem);
  317. }
  318. else
  319. {
  320. print "error in rendering RPC type \`$elem\' not an int\n";
  321. return Frontier::RPC2::Integer->new($elem);
  322. #die "error in rendering RPC type \`$elem\' not an int\n";
  323. }
  324. }
  325. sub string {
  326. my $self = shift;
  327. return Frontier::RPC2::String->new(@_);
  328. }
  329. sub date_time {
  330. my $self = shift;
  331. return Frontier::RPC2::DateTime::ISO8601->new(@_);
  332. }
  333. ######################################################################
  334. ###
  335. ### XML::Parser callbacks
  336. ###
  337. package Frontier::RPC2::SAXHandler;
  338. use vars qw{%scalars %char_entities %expat};
  339. #use vars qw{%scalars %char_entities};
  340. use base qw(XML::SAX::Base);
  341. %char_entities = (
  342. '&' => '&amp;',
  343. '<' => '&lt;',
  344. '>' => '&gt;',
  345. '"' => '&quot;',
  346. );
  347. # FIXME I need a list of these
  348. %scalars = (
  349. 'base64' => 1,
  350. 'boolean' => 1,
  351. 'dateTime.iso8601' => 1,
  352. 'double' => 1,
  353. 'int' => 1,
  354. 'i4' => 1,
  355. 'string' => 1,
  356. );
  357. #%expat = ();
  358. # C'tor
  359. sub new
  360. {
  361. my $package = shift;
  362. my $self = bless { @_ }, $package;
  363. #my $expat = {};
  364. bless \%expat, $package;
  365. return $self;
  366. }
  367. # D'tor
  368. sub DESTROY
  369. {
  370. my $self = shift;
  371. $self->{expat}->{'rpc_state'} = [];
  372. $self->{expat}->{'rpc_container'} = [ [] ];
  373. $self->{expat}->{'rpc_member_name'} = [];
  374. $self->{expat}->{'rpc_type'} = undef;
  375. $self->{expat}->{'rpc_args'} = undef;
  376. $self->{expat} = {};
  377. }
  378. sub die
  379. {
  380. my ($self, $message) = @_;
  381. my $expat = $self->{expat};
  382. die $message, "\n";
  383. }
  384. # START DOC
  385. sub start_document
  386. {
  387. my ($self, $doc) = @_;
  388. # We call the state hash expat to easy Frontier migration from XML::Parser
  389. # to XML::SAX
  390. #my $expat = $self->{expat};
  391. $self->{expat} = {};
  392. $self->{expat}->{'rpc_state'} = [];
  393. $self->{expat}->{'rpc_container'} = [ [] ];
  394. $self->{expat}->{'rpc_member_name'} = [];
  395. $self->{expat}->{'rpc_type'} = undef;
  396. $self->{expat}->{'rpc_args'} = undef;
  397. }
  398. sub end_document
  399. {
  400. my ($self) = @_;
  401. #my $expat = $self->{expat};
  402. $self->{expat}->{'rpc_value'} = pop @{ $self->{expat}->{'rpc_container'} };
  403. return
  404. {
  405. value => $self->{expat}->{'rpc_value'},
  406. type => $self->{expat}->{'rpc_type'},
  407. method_name => $self->{expat}->{'rpc_method_name'},
  408. };
  409. }
  410. # START ELEMENT
  411. sub start_element
  412. {
  413. my ($self, $el) = @_;
  414. #my $expat = $self->{expat};
  415. my $tag = $el->{"LocalName"};
  416. # process element start event
  417. my $state = $self->{expat}->{'rpc_state'}[-1];
  418. if (!defined $state)
  419. {
  420. if ($tag eq 'methodCall')
  421. {
  422. $self->{expat}->{'rpc_type'} = 'call';
  423. push @{ $self->{expat}->{'rpc_state'} }, 'want_method_name';
  424. }
  425. elsif ($tag eq 'methodResponse')
  426. {
  427. push @{ $self->{expat}->{'rpc_state'} }, 'method_response';
  428. }
  429. else
  430. {
  431. Frontier::RPC2::SAXHandler::die($self->{expat}, "unknown RPC type \`$tag'\n");
  432. }
  433. }
  434. elsif ($state eq 'want_method_name')
  435. {
  436. Frontier::RPC2::SAXHandler::die($self->{expat}, "wanted \`methodName' tag, got \`$tag'\n")
  437. if ($tag ne 'methodName');
  438. push @{ $self->{expat}->{'rpc_state'} }, 'method_name';
  439. $self->{expat}->{'rpc_text'} = "";
  440. }
  441. elsif ($state eq 'method_response')
  442. {
  443. if ($tag eq 'params')
  444. {
  445. $self->{expat}->{'rpc_type'} = 'response';
  446. push @{ $self->{expat}->{'rpc_state'} }, 'params';
  447. }
  448. elsif ($tag eq 'fault')
  449. {
  450. $self->{expat}->{'rpc_type'} = 'fault';
  451. push @{ $self->{expat}->{'rpc_state'} }, 'want_value';
  452. }
  453. }
  454. elsif ($state eq 'want_params')
  455. {
  456. Frontier::RPC2::SAXHandler::die($self->{expat}, "wanted \`params' tag, got \`$tag'\n")
  457. if ($tag ne 'params');
  458. push @{ $self->{expat}->{'rpc_state'} }, 'params';
  459. }
  460. elsif ($state eq 'params')
  461. {
  462. Frontier::RPC2::SAXHandler::die($self->{expat}, "wanted \`param' tag, got \`$tag'\n")
  463. if ($tag ne 'param');
  464. push @{ $self->{expat}->{'rpc_state'} }, 'want_param_name_or_value';
  465. }
  466. elsif ($state eq 'want_param_name_or_value')
  467. {
  468. if ($tag eq 'value')
  469. {
  470. $self->{expat}->{'may_get_cdata'} = 1;
  471. $self->{expat}->{'rpc_text'} = "";
  472. push @{ $self->{expat}->{'rpc_state'} }, 'value';
  473. }
  474. elsif ($tag eq 'name')
  475. {
  476. push @{ $self->{expat}->{'rpc_state'} }, 'param_name';
  477. }
  478. else
  479. {
  480. Frontier::RPC2::die($self->{expat}, "wanted \`value' or \`name' tag, got \`$tag'\n");
  481. }
  482. }
  483. elsif ($state eq 'param_name')
  484. {
  485. Frontier::RPC2::SAXHandler::die($self->{expat}, "wanted parameter name data, got tag \`$tag'\n");
  486. }
  487. elsif ($state eq 'want_value')
  488. {
  489. Frontier::RPC2::SAXHandler::die($self->{expat}, "wanted \`value' tag, got \`$tag'\n")
  490. if ($tag ne 'value');
  491. $self->{expat}->{'rpc_text'} = "";
  492. $self->{expat}->{'may_get_cdata'} = 1;
  493. push @{ $self->{expat}->{'rpc_state'} }, 'value';
  494. }
  495. elsif ($state eq 'value')
  496. {
  497. $self->{expat}->{'may_get_cdata'} = 0;
  498. if ($tag eq 'array')
  499. {
  500. push @{ $self->{expat}->{'rpc_container'} }, [];
  501. push @{ $self->{expat}->{'rpc_state'} }, 'want_data';
  502. }
  503. elsif ($tag eq 'struct')
  504. {
  505. push @{ $self->{expat}->{'rpc_container'} }, {};
  506. push @{ $self->{expat}->{'rpc_member_name'} }, undef;
  507. push @{ $self->{expat}->{'rpc_state'} }, 'struct';
  508. }
  509. elsif ($scalars{$tag})
  510. {
  511. $self->{expat}->{'rpc_text'} = "";
  512. push @{ $self->{expat}->{'rpc_state'} }, 'cdata';
  513. }
  514. else
  515. {
  516. Frontier::RPC2::SAXHandler::die($self->{expat}, "wanted a data type, got \`$tag'\n");
  517. }
  518. }
  519. elsif ($state eq 'want_data')
  520. {
  521. Frontier::RPC2::SAXHandler::die($self->{expat}, "wanted \`data', got \`$tag'\n")
  522. if ($tag ne 'data');
  523. push @{ $self->{expat}->{'rpc_state'} }, 'array';
  524. }
  525. elsif ($state eq 'array')
  526. {
  527. Frontier::RPC2::SAXHandler::die($self->{expat}, "wanted \`value' tag, got \`$tag'\n")
  528. if ($tag ne 'value');
  529. $self->{expat}->{'rpc_text'} = "";
  530. $self->{expat}->{'may_get_cdata'} = 1;
  531. push @{ $self->{expat}->{'rpc_state'} }, 'value';
  532. }
  533. elsif ($state eq 'struct')
  534. {
  535. Frontier::RPC2::SAXHandler::die($self->{expat}, "wanted \`member' tag, got \`$tag'\n")
  536. if ($tag ne 'member');
  537. push @{ $self->{expat}->{'rpc_state'} }, 'want_member_name';
  538. }
  539. elsif ($state eq 'want_member_name')
  540. {
  541. Frontier::RPC2::SAXHandler::die($self->{expat}, "wanted \`name' tag, got \`$tag'\n")
  542. if ($tag ne 'name');
  543. push @{ $self->{expat}->{'rpc_state'} }, 'member_name';
  544. $self->{expat}->{'rpc_text'} = "";
  545. }
  546. elsif ($state eq 'member_name')
  547. {
  548. Frontier::RPC2::SAXHandler::die($self->{expat}, "wanted data, got tag \`$tag'\n");
  549. }
  550. elsif ($state eq 'cdata')
  551. {
  552. Frontier::RPC2::SAXHandler::die($self->{expat}, "wanted data, got tag \`$tag'\n");
  553. }
  554. else
  555. {
  556. Frontier::RPC2::SAXHandler::die($self->{expat}, "internal error, unknown state \`$state'\n");
  557. }
  558. }
  559. # START ELEMENT
  560. sub end_element
  561. {
  562. my ($self, $el) = @_;
  563. #my $expat = $self->{expat};
  564. my $tag = $el->{"LocalName"};
  565. # Process
  566. my $state = pop @{ $self->{expat}->{'rpc_state'} };
  567. if ($state eq 'cdata')
  568. {
  569. my $value = $self->{expat}->{'rpc_text'};
  570. if ($tag eq 'base64')
  571. {
  572. $value = Frontier::RPC2::Base64->new($value);
  573. }
  574. elsif ($tag eq 'boolean')
  575. {
  576. $value = Frontier::RPC2::Boolean->new($value);
  577. }
  578. elsif ($tag eq 'dateTime.iso8601')
  579. {
  580. $value = Frontier::RPC2::DateTime::ISO8601->new($value);
  581. }
  582. elsif ($self->{expat}->{'use_objects'})
  583. {
  584. if ($tag eq 'i4' or $tag eq 'int')
  585. {
  586. $value = Frontier::RPC2::Integer->new($value);
  587. }
  588. elsif ($tag eq 'float')
  589. {
  590. $value = Frontier::RPC2::Float->new($value);
  591. }
  592. elsif ($tag eq 'string')
  593. {
  594. $value = Frontier::RPC2::String->new($value);
  595. }
  596. }
  597. $self->{expat}->{'rpc_value'} = $value;
  598. }
  599. elsif ($state eq 'member_name')
  600. {
  601. $self->{expat}->{'rpc_member_name'}[-1] = $self->{expat}->{'rpc_text'};
  602. $self->{expat}->{'rpc_state'}[-1] = 'want_value';
  603. }
  604. elsif ($state eq 'method_name')
  605. {
  606. $self->{expat}->{'rpc_method_name'} = $self->{expat}->{'rpc_text'};
  607. $self->{expat}->{'rpc_state'}[-1] = 'want_params';
  608. }
  609. elsif ($state eq 'struct')
  610. {
  611. $self->{expat}->{'rpc_value'} = pop @{ $self->{expat}->{'rpc_container'} };
  612. pop @{ $self->{expat}->{'rpc_member_name'} };
  613. }
  614. elsif ($state eq 'array')
  615. {
  616. $self->{expat}->{'rpc_value'} = pop @{ $self->{expat}->{'rpc_container'} };
  617. }
  618. elsif ($state eq 'value')
  619. {
  620. # the rpc_text is a string if no type tags were given
  621. if ($self->{expat}->{'may_get_cdata'})
  622. {
  623. $self->{expat}->{'may_get_cdata'} = 0;
  624. if ($self->{expat}->{'use_objects'})
  625. {
  626. $self->{expat}->{'rpc_value'}
  627. = Frontier::RPC2::String->new($self->{expat}->{'rpc_text'});
  628. }
  629. else
  630. {
  631. $self->{expat}->{'rpc_value'} = $self->{expat}->{'rpc_text'};
  632. }
  633. }
  634. my $container = $self->{expat}->{'rpc_container'}[-1];
  635. if (ref($container) eq 'ARRAY')
  636. {
  637. push @$container, $self->{expat}->{'rpc_value'};
  638. }
  639. elsif (ref($container) eq 'HASH')
  640. {
  641. $container->{ $self->{expat}->{'rpc_member_name'}[-1] } = $self->{expat}->{'rpc_value'};
  642. }
  643. }
  644. }
  645. sub characters
  646. {
  647. my ($self, $text) = @_;
  648. #my $expat = $self->{expat};
  649. $self->{expat}->{'rpc_text'} .= $text->{"Data"};
  650. }
  651. # ----------------------------------------------------------------------------
  652. # RPC2 DATA TYPES
  653. # ----------------------------------------------------------------------------
  654. package Frontier::RPC2::DataType;
  655. sub new {
  656. my $type = shift; my $value = shift;
  657. return bless \$value, $type;
  658. }
  659. # `repr' returns the XML representation of this data, which may be
  660. # different [in the future] from what is returned from `value'
  661. sub repr {
  662. my $self = shift;
  663. return $$self;
  664. }
  665. # sets or returns the usable value of this data
  666. sub value {
  667. my $self = shift;
  668. @_ ? ($$self = shift) : $$self;
  669. }
  670. package Frontier::RPC2::Base64;
  671. use vars qw{@ISA};
  672. @ISA = qw{Frontier::RPC2::DataType};
  673. package Frontier::RPC2::Boolean;
  674. use vars qw{@ISA};
  675. @ISA = qw{Frontier::RPC2::DataType};
  676. package Frontier::RPC2::Integer;
  677. use vars qw{@ISA};
  678. @ISA = qw{Frontier::RPC2::DataType};
  679. package Frontier::RPC2::String;
  680. use vars qw{@ISA};
  681. @ISA = qw{Frontier::RPC2::DataType};
  682. sub repr {
  683. my $self = shift;
  684. my $value = $$self;
  685. $value =~ s/([&<>\"])/$Frontier::RPC2::char_entities{$1}/ge;
  686. $value;
  687. }
  688. package Frontier::RPC2::Double;
  689. use vars qw{@ISA};
  690. @ISA = qw{Frontier::RPC2::DataType};
  691. package Frontier::RPC2::DateTime::ISO8601;
  692. use vars qw{@ISA};
  693. @ISA = qw{Frontier::RPC2::DataType};
  694. 1;