debugging cruft removal
[Net-Soma.git] / Soma.pm
1 package Net::Soma;
2
3 use strict;
4 use vars qw($DEBUG $VERSION @uris $AUTOLOAD %schemas);
5 use SOAP::Lite 0.71 #+trace => debug, objects
6 ;
7
8 $VERSION = '0.02';
9
10 $DEBUG = 0;
11
12 @uris = qw( CPECollection AppCatalog AdminService CPESearch Version Applications
13             CPEAccess ApplicationsV2 
14         );
15
16 =head1 NAME
17
18 Net::Soma - Perl client interface to SOMA iWireless platform
19
20 =head1 SYNOPSIS
21
22 use Net::Soma;
23 use Net::Soma qw( AttributeInstance FeatureInstance ApplicationInstance
24                   ChoiceItem AttributeDef FeatureDef ApplicationDef
25                   ApplicationDefV2 FeatureDefV2 AttributeDefV2 CPEInfoDefV2
26                   CPESearchStruct CPESearchResult CPEInfo CPEInfoDef
27                   HardwarePort
28                   NoSuchCPEException DataAccessException InternalFault
29                   BadAppParameterException BadAppParameterExceptionV2
30                   NoSuchAppException NoSuchFeatureException
31                   NoSuchAttributeException BadCPEParameterException
32                   ActiveApplicationsException );
33
34 $soma = new Net::Soma { url => 'https://soma.example.net:8088/ossapi/services',
35                         namespace => 'AppCatalog',
36                       }
37   
38 $err_or_som = $soma->getApplicationDefinitions();
39
40 if (ref($err_or_som)){
41   my $result = $err_or_som->result;
42   foreach my $definition (@$result) {
43     print $definition->name, "\n";
44   }
45 }else{
46   print "$err_or_som\n";
47 }
48  
49 =head1 DESCRIPTION
50
51 Net::Soma is a module implementing a Perl interface to SOMA's iWireless
52 SOAP interface (ossapi).  It is compatible with release 1.5 of that software
53 and requires the WSDLs from SOMA.
54
55 Net::Soma enables you to simply access the SOAP interface of your SOMA
56 networks softair platform server.  
57
58 =head1 BASIC USAGE
59
60 Import the Net::Soma module with
61
62 use Net::Soma (@list_of_classes);
63
64 Net::Soma will create any of the following classes for you
65
66 AttributeInstance FeatureInstance ApplicationInstance ChoiceItem
67 AttributeDef FeatureDef ApplicationDef ApplicationDefV2 FeatureDefV2
68 AttributeDefV2 CPEInfoDefV2 CPESearchStruct CPESearchResult CPEInfo
69 CPEInfoDef HardwarePort NoSuchCPEException DataAccessException InternalFault
70 BadAppParameterException BadAppParameterExceptionV2 NoSuchAppException
71 NoSuchFeatureException NoSuchAttributeException BadCPEParameterException
72 ActiveApplicationsException 
73     
74 =cut
75
76 sub import {
77   my $class = shift;
78   my @classes = @_;
79   my $me = __PACKAGE__;
80   my @classlist = qw( AttributeInstance FeatureInstance ApplicationInstance
81                       ChoiceItem AttributeDef FeatureDef ApplicationDef
82                       ApplicationDefV2 FeatureDefV2 AttributeDefV2 CPEInfoDefV2
83                       CPESearchStruct CPESearchResult CPEInfo CPEInfoDef
84                       HardwarePort
85                       NoSuchCPEException DataAccessException InternalFault
86                       BadAppParameterException BadAppParameterExceptionV2
87                       NoSuchAppException NoSuchFeatureException
88                       NoSuchAttributeException BadCPEParameterException
89                       ActiveApplicationsException
90                    );
91   my (%EXPORT_OK) = map { $_ => 1 } @classlist;
92
93   {
94     no strict 'refs';         #hmmm force 'use' of all to be serialized?
95     foreach my $class (@classlist) { 
96
97       *{"SOAP::Serializer::as_$class"} = sub {
98         my ($self, $value, $name, $type, $attr) = @_;
99
100         $self->register_ns("urn:ossapi.services.core.soma.com", "netsoma");
101         $self->encode_object( \SOAP::Data->value(
102           SOAP::Data->name($name => map { SOAP::Data->name($_ => $value->{$_}) }
103                                            keys %$value
104                           )
105         ), $name, $type, {'xsi:type' => "netsoma:$class", %$attr});
106       };
107
108       *{"SOAP::Serializer::as_ArrayOf$class"} = sub {
109         my ($self, $value, $name, $type, $attr) = @_;
110
111         $self->register_ns("urn:ossapi.services.core.soma.com", "netsoma");
112         if (@$value) {
113           $self->encode_object( \SOAP::Data->value(
114             SOAP::Data->name($name => map { SOAP::Data->name(item => $_) }
115                                              @$value
116                             )
117           ), $name, $type, {'xsi:type' => "netsoma:ArrayOf$class", %$attr});
118         } else {
119           $self->encode_object( [], $name, $type, {'xsi:type' => "netsoma:ArrayOf$class", %$attr});
120         }
121
122       };
123
124     }
125
126   }
127
128   foreach $class ( map { $_, "ArrayOf$_" }
129                    grep { exists( $EXPORT_OK{$_} )
130                           or die "$_ is not exported by module $me"
131                         }
132                    @classes)
133   {
134     no strict 'refs';
135
136     *{"$class\::NEW"} = sub {
137                          my $proto = shift;
138                          my $class = ref($proto) || $proto;
139                          my $self = { @_ };
140                          return bless($self, $class);
141                        };
142     *{"$class\::AUTOLOAD"} = sub {
143                               my $field = $AUTOLOAD;
144                               $field =~ s/.*://;
145                               return if $field eq 'DESTROY';
146                               if ( defined($_[1]) ) {
147                                 $_[0]->{$field} = $_[1];
148                               } else {
149                                 $_[0]->{$field};
150                               }
151                             };
152   }
153
154   # $me =~ s/::/\//g;
155   # $INC{"$me.pm"} =~ /^(.*)\.pm$/;
156   # $me = $1;
157   # for (@uris){
158   #   $schemas{$_."Service"} = SOAP::Schema
159   #     ->schema_url("file:$me/wsdls/$_.wsdl")
160   #     ->parse->services->{$_."Service"};
161   # }
162
163 }
164
165 =head1 CONSTRUCTOR
166
167 =over 4
168
169 =item new HASHREF
170
171 Creates a new Soma object.  HASHREF should contain the keys url and namespace
172 for the URL of the Soma SOAP proxy and the namespace of the methods you would
173 like to call.  You may optionally define the key die_on_fault to cause that
174 behavior for methods.
175
176 =cut 
177
178 sub new {
179   my $proto = shift;
180   my $class = ref($proto) || $proto;
181   my $self = { @_ };
182
183   for (@uris){
184     $schemas{$_."Service"} = SOAP::Schema
185       ->schema_url($self->{url}."$_?wsdl")
186        ->parse->services->{$_."Service"};
187   }
188
189   return bless($self, $class);
190 }
191
192 =head1 METHODS
193
194 All Soma methods may be invoked as methods of the Net::Soma object.
195 The return value is either the fault string in the event of an error
196 or a SOAP::SOM object.
197
198 If the option die_on_fault was set for the Net::Soma object, then
199 instead the method dies on error and returns the result component
200 of the SOAP::SOM object on success.
201
202 =cut 
203
204 sub AUTOLOAD {
205   my $self = shift;   #hmmm... test this?
206
207   my $method = $AUTOLOAD;
208   $method =~ s/.*://;
209   return if $method eq 'DESTROY';
210
211   my $nscount = 1;
212   my $uri = $self->{namespace};
213   $uri =~ s/Service$//;
214   my $soap = SOAP::Lite
215     -> autotype(1)
216     -> readable(1)
217     -> uri($uri)
218     -> proxy($self->{url});
219
220 #  local *SOAP::Transport::HTTP::Client::get_basic_credentials = sub {
221 #    return $self->{user} => $self->{password};
222 #  };
223
224   my $param = 0;
225   my $som =
226     $soap->$method( map {
227       my $paramdata =
228         $schemas{$self->{namespace}}{$method}{'parameters'}[$param++];
229       my ($pre,$type) = SOAP::Utils::splitqname($paramdata->type);
230       SOAP::Data->name($paramdata->name => $_ )
231         ->type(${[SOAP::Utils::splitqname($paramdata->type)]}[1]) } @_
232     );
233
234   if ($som) {
235     if ($som->fault){
236       if ($self->{die_on_fault}){
237         die $som->faultstring;
238       } else {
239         return $som->faultstring;
240       }
241     }else{
242       if ($self->{die_on_fault}){
243         return $som->result;
244       } else {
245         return $som;
246       }
247     }
248   }
249
250   die "Net::Soma failed to $method for $self->{namespace} at " . $self->{url};
251 }
252
253
254 =back
255
256 =head1 SEE ALSO
257
258   SOAP::Lite, SOAP::SOM
259
260   http://www.somanetworks.com/ for information about SOMA and iWireless.
261
262   http://www.sisd.com/freeside/ for the ISP billing and provisioning system
263   which provoked the need for this module.
264
265 =head1 BUGS
266
267 Namespace promiscuous.
268 Lax handling of arguments and return values.
269 In fact, calling a bogus method with arguments causes complaints about
270 accessing methods on undefined values (at line 233, paramdata->name)
271
272 Quite probably others.  Use at your own risk.
273
274 =head1 AUTHOR AND COPYRIGHT
275
276 Copyright (c) 2008 Jeff Finucane jeff-net-soma@weasellips.com
277
278 This library is free software; you can redistribute it and/or modify
279 it under the same terms as Perl itself.
280
281 This software is neither authorized, sponsored, endorsed, nor supported
282 by Soma Networks.
283
284 =cut
285
286 1;