File Coverage

blib/lib/SRS/EPP/Command.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             # vim: filetype=perl:noexpandtab:ts=3:sw=3
2             #
3             # Copyright (C) 2009 NZ Registry Services
4             #
5             # This program is free software: you can redistribute it and/or modify
6             # it under the terms of the Artistic License 2.0 or later. You should
7             # have received a copy of the Artistic License the file COPYING.txt.
8             # If not, see <http://www.perlfoundation.org/artistic_license_2_0>
9              
10             package SRS::EPP::Command;
11             {
12             $SRS::EPP::Command::VERSION = '0.22';
13             }
14              
15 3     3   56978 use Moose;
  3         989684  
  3         29  
16 3     3   23948 use MooseX::Params::Validate;
  3         23911  
  3         30  
17 3     3   2165 use Moose::Util::TypeConstraints qw(subtype coerce as where class_type);
  3         6  
  3         35  
18 3     3   2329 use Carp;
  3         5  
  3         239  
19              
20             extends 'SRS::EPP::Message';
21              
22             with 'MooseX::Log::Log4perl::Easy';
23              
24 3     3   3102 use XML::EPP;
  0            
  0            
25             use XML::SRS::Error;
26              
27             has "+message" =>
28             isa => "XML::EPP",
29             ;
30              
31             use Module::Pluggable search_path => [__PACKAGE__];
32              
33             sub rebless_class {
34             my $object = shift;
35             our $map;
36             if ( !$map ) {
37             $map = {
38             map {
39             $_->can("match_class")
40             ? ( $_->match_class => $_ )
41             : ();
42             }# map { print "rebless_class checking plugin $_\n"; $_ }
43             grep m{${\(__PACKAGE__)}::[^:]*$},
44             __PACKAGE__->plugins,
45             };
46             }
47             $map->{ref $object};
48             }
49              
50             sub action_class {
51             my $action = shift;
52             our $action_classes;
53             if ( !$action_classes ) {
54             $action_classes = {
55             map {
56             $_->can("action")
57             ? ($_->action => $_)
58             : ();
59             }# map { print "action_class checking plugin $_\n"; $_ }
60             grep m{^${\(__PACKAGE__)}::[^:]*$},
61             __PACKAGE__->plugins,
62             };
63             }
64             $action_classes->{$action};
65             }
66              
67             sub REBLESS {
68              
69             }
70              
71             sub BUILD {
72             my $self = shift;
73             if ( my $epp = $self->message ) {
74             my $class;
75             $class = rebless_class( $epp->message );
76             if (
77             !$class
78             and $epp->message
79             and
80             $epp->message->can("action")
81             )
82             {
83             $class = action_class($epp->message->action);
84             }
85             if ($class) {
86              
87             #FIXME: use ->meta->rebless_instance
88             bless $self, $class;
89             $self->REBLESS;
90             }
91             }
92             }
93              
94             sub simple { 0 }
95             sub authenticated { 1 }
96             sub done { 1 }
97              
98             # Indicates whether we'd normally expect multiple responses to be returned to the client
99             # e.g. check domain allows multiple domains to be checked at once, and therefore multiple
100             # responses, whereas info domain is only one response. This is used to decide whether we
101             # return multiple SRS errors back to the client (as some actions that map to multiple
102             # SRS queries only want to return at most one error to the client)
103             sub multiple_responses { 0 }
104              
105             BEGIN {
106             class_type "SRS::EPP::Session";
107             class_type "SRS::EPP::SRSResponse";
108             }
109              
110             has 'session' =>
111             is => "rw",
112             isa => "SRS::EPP::Session",
113             weak_ref => 1,
114             ;
115              
116             has 'server_id' =>
117             is => "rw",
118             isa => "XML::EPP::trIDStringType",
119             lazy => 1,
120             predicate => "has_server_id",
121             default => sub {
122             my $self = shift;
123             my $session = $self->session;
124             if ($session) {
125             $session->new_server_id;
126             }
127             else {
128             our $counter = "aaaa";
129             $counter++;
130             }
131             }
132             ;
133              
134             BEGIN {
135             class_type "SRS::EPP::Session";
136             }
137              
138             # process a simple message - the $session is for posting back events
139             sub process {
140             my $self = shift;
141            
142             my ( $session ) = pos_validated_list(
143             \@_,
144             { isa => 'SRS::EPP::Session' },
145             );
146            
147             $self->session($session);
148              
149             # default handler is to return an unimplemented message
150             return $self->make_response(code => 2101);
151             }
152              
153             sub notify {
154             my $self = shift;
155            
156             return $self->make_response(code => 2400);
157             }
158              
159             sub make_response {
160             my $self = shift;
161             my $type = "SRS::EPP::Response";
162             if ( @_ % 2 ) {
163             $type = shift;
164             $type = "SRS::EPP::Response::$type" if $type !~ /^SRS::/;
165             }
166             my %fields = @_;
167             $fields{client_id} ||= $self->client_id if $self->has_client_id;
168             $fields{server_id} ||= $self->server_id;
169             $self->log_debug("making a response: @{[%fields]}")
170             if $self->log->is_debug;
171             $type->new(
172             %fields,
173             );
174             }
175              
176             # this one is for convenience in returning errors
177             sub make_error {
178             my $self = shift;
179            
180             my ( $code, $message, $value, $reason, $exception ) = validated_list(
181             \@_,
182             code => { isa => 'Int' },
183             message => { isa => 'Str', optional => 1 },
184             value => { isa => 'Str', optional => 1 },
185             reason => { isa => 'Str', optional => 1 },
186             exception => { optional => 1 },
187             );
188            
189             if ( defined $reason ) {
190             $exception ||= XML::EPP::Error->new(
191             value => $value//"",
192             reason => $reason,
193             );
194             }
195              
196             return $self->make_response(
197             Error => (
198             ($code ? (code => $code) : ()),
199             ($exception ? (exception => $exception) : ()),
200             ($message ? (extra => $message) : ()),
201             ),
202             );
203             }
204              
205             # this one is intended for commands to override particular error
206             # cases, so must use a simpler calling convention.
207             sub make_error_response {
208             my $self = shift;
209            
210             my ( $srs_error ) = pos_validated_list(
211             \@_,
212             { isa => 'XML::SRS::Error|ArrayRef[XML::SRS::Error]' },
213             );
214            
215             return SRS::EPP::Response::Error->new(
216             server_id => $self->server_id,
217             ($self->client_id ? (client_id => $self->client_id) : () ),
218             exception => $srs_error,
219             );
220             }
221              
222             has "client_id" =>
223             is => "rw",
224             isa => "XML::EPP::trIDStringType",
225             predicate => "has_client_id",
226             ;
227              
228             after 'message_trigger' => sub {
229             my $self = shift;
230             my $message = $self->message;
231             if ( my $client_id = eval { $message->message->client_id } ) {
232             $self->client_id($client_id);
233             }
234             };
235              
236             use Module::Pluggable
237             require => 1,
238             search_path => [__PACKAGE__],
239             ;
240              
241             sub ids {
242             my $self = shift;
243             return (
244             $self->server_id,
245             $self->client_id||(),
246             );
247             }
248              
249             __PACKAGE__->plugins;
250              
251             no Moose;
252             __PACKAGE__->meta->make_immutable;
253              
254             1;
255              
256             __END__
257              
258             =head1 NAME
259              
260             SRS::EPP::Command - encapsulation of received EPP commands
261              
262             =head1 SYNOPSIS
263              
264             my $cmd = SRS::EPP::Command::SubClass->new
265             (
266             xmlschema => ...
267             xmlstring => ...
268             );
269              
270             my $response = $cmd->process;
271              
272             =head1 DESCRIPTION
273              
274             This module is a base class for EPP commands; these are messages sent
275             from the client to the server.
276              
277             =head1 ATTRIBUTES
278              
279             =over
280              
281             =item xmlschema
282              
283             The XML schema for this message, as a string. (XXX - this should be a
284             class data variable)
285              
286             =item xmlstring
287              
288             The data of the message.
289              
290             =back
291              
292             =head1 SEE ALSO
293              
294             L<SRS::EPP::Command::Login>, L<SRS::EPP::Message>,
295             L<SRS::EPP::Response>
296              
297             =cut
298              
299             # Local Variables:
300             # mode:cperl
301             # indent-tabs-mode: t
302             # tab-width: 8
303             # cperl-continued-statement-offset: 8
304             # cperl-brace-offset: 0
305             # cperl-close-paren-offset: 0
306             # cperl-continued-brace-offset: 0
307             # cperl-continued-statement-offset: 8
308             # cperl-extra-newline-before-brace: nil
309             # cperl-indent-level: 8
310             # cperl-indent-parens-as-block: t
311             # cperl-indent-wrt-brace: nil
312             # cperl-label-offset: -8
313             # cperl-merge-trailing-else: t
314             # End: