File Coverage

blib/lib/DMTF/CIM/WSMan.pm
Criterion Covered Total %
statement 22 24 91.6
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 30 32 93.7


line stmt bran cond sub pod time code
1             package DMTF::CIM::WSMan;
2            
3 1     1   26218 use warnings;
  1         2  
  1         30  
4 1     1   6 use strict;
  1         1  
  1         31  
5 1     1   931 use URI;
  1         8384  
  1         41  
6 1     1   13 use URI::Escape;
  1         2  
  1         153  
7             require URI::_server;
8 1     1   1248 use DMTF::WSMan;
  1         56869  
  1         28  
9 1     1   925 use DMTF::CIM;
  1         14244  
  1         42  
10 1     1   12 use DMTF::CIM::Instance;
  1         2  
  1         16  
11 1     1   454 use XML::Twig;
  0            
  0            
12             use DateTime::Duration;
13             use MIME::Base64;
14             use Carp;
15            
16             use version;
17             our $VERSION = qv('0.09');
18            
19             our @ISA=qw(DMTF::CIM);
20            
21             # Custom URI types
22             {
23             package URI::wsman_Owbem;
24             our @ISA=qw(URI::_server);
25             sub default_port { 0 }
26             sub canonical
27             {
28             my $self = shift;
29             my $other = $self->SUPER::canonical;
30            
31             my $slash_path = defined($other->authority) &&
32             !length($other->path) && !defined($other->query);
33            
34             if ($slash_path) {
35             $other = $other->clone if $other == $self;
36             $other->path("/");
37             }
38            
39             my $path=URI::Escape::uri_escape(URI::Escape::uri_unescape($other->path),'?#');
40             if($path=~/([^:]*):([^.]*).(.*)$/) {
41             my ($ns, $class, $selectors)=($1,$2,$3);
42            
43             my @selectors=split(/(?<=[^=\\]"),/, $selectors);
44             my $newselectors=join(",", sort @selectors);
45             if($newselectors ne $selectors) {
46             $other = $other->clone if $other == $self;
47             $path=URI::Escape::uri_escape("$ns:$class.".$newselectors,'?#');
48             $other->path($path);
49             }
50             }
51             if($path ne $other->path) {
52             $other = $other->clone if $other == $self;
53             $other->path($path);
54             }
55            
56             $other;
57             }
58             sub path
59             {
60             my $self = shift;
61             $$self =~ m,^((?:[^:/?\#]+:)?(?://[^/?\#]*)?)([^?\#]*)(.*)$,s or die;
62            
63             if (@_) {
64             $$self = $1;
65             my $rest = $3;
66             my $new_path = shift;
67             $new_path = "" unless defined $new_path;
68             $new_path = URI::Escape::uri_escape($new_path,'?#');
69             utf8::downgrade($new_path);
70             URI::_generic::_check_path($new_path, $$self);
71             $$self .= $new_path . $rest;
72             }
73             $2;
74             }
75             sub namespace {
76             my $self = shift;
77             my $path=$self->path;
78            
79             if($path=~/([^:]*)(?::[^.]*)?(?:\..*)?$/) {
80             return $1;
81             }
82             return;
83             }
84             sub class {
85             my $self = shift;
86             my $path=$self->path;
87            
88             if($path=~/(?:[^:]*):([^.]*)(?:\..*)?$/) {
89             return $1;
90             }
91             return;
92             }
93             }
94             {
95             package URI::wsman_Owbems;
96             our @ISA=qw(URI::wsman_Owbem);
97             sub default_port { 0 }
98             sub secure { 1 }
99             }
100            
101             # Module implementation here
102             sub new
103             {
104             my $class=shift;
105             my $self=DMTF::CIM::new($class);
106             $self->{CURRENTURI}=URI->new('/interop');
107             $self->{AUTHORITIES}={};
108             $self->{TWIG}=XML::Twig->new(
109             keep_spaces=>1,
110             map_xmlns=>{
111             'http://www.w3.org/2003/05/soap-envelope'=>'s',
112             'http://schemas.xmlsoap.org/ws/2004/08/addressing'=>'a',
113             'http://schemas.xmlsoap.org/ws/2004/09/enumeration'=>'n',
114             'http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd'=>'w',
115             'http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd'=>'b',
116             'http://schemas.dmtf.org/wbem/wscim/1/common'=>'c',
117             'http://www.w3.org/2001/XMLSchema-instance'=>'x',
118             'http://schemas.xmlsoap.org/ws/2004/09/transfer'=>'t',
119             },
120             elt_accessors=>[
121             's:Body',
122             ],
123             );
124             $self->{QUIRKS}={
125             'association_object_wrong'=>0,
126             'incorrect_string_octetstring'=>0
127             };
128             bless($self, $self->{CLASS});
129             return($self);
130             }
131            
132             ###############
133             # Generic Ops #
134             ###############
135             sub GetInstance
136             {
137             my $self=shift;
138             my %args=@_;
139             $args{uri}=$args{InstancePath} if(defined $args{InstancePath});
140             $args{ico}=$args{IncludeClassOrigin} if(defined $args{IncludeClassOrigin});
141             $args{ico}=0 if(!defined $args{ico});
142             $args{iq}=$args{IncludeQualifiers} if(defined $args{IncludeQualifiers});
143             $args{iq}=0 if(!defined $args{iq});
144             $args{props}=$args{IncludedProperties} if(defined $args{IncludedProperties});
145            
146             if($args{ico}) {
147             carp("WS-Management does not implement IncludeClassOrigin support");
148             return;
149             }
150             if($args{iq}) {
151             carp("WS-Management does not implement IncludeQualifiers support");
152             return;
153             }
154            
155             $self->current_uri($args{uri});
156             my $epr=$self->current_epr;
157             my $wsman=$self->current_wsman;
158             if(!defined $epr || !defined $wsman) {
159             return;
160             }
161            
162             my $xmlstr=$wsman->get(epr=>$epr);
163             if(!defined $xmlstr) {
164             return;
165             }
166             my $xml=$self->{TWIG}->parse($xmlstr);
167             return if(!defined $xml);
168             if($self->_checkfault($xml->root)) {
169             return;
170             }
171             my $instance=$xml->root->first_child('s:Body')->first_child;
172             if(!defined $instance) {
173             carp("No instance nor fault returned!");
174             return;
175             }
176             my $ret=$self->_parse_instance($instance);
177             $ret->uri($self->current_uri->canonical);
178             return $ret;
179             }
180            
181             sub DeleteInstance
182             {
183             my $self=shift;
184             my %args=@_;
185             $args{uri}=$args{InstancePath} if(defined $args{InstancePath});
186             $args{ico}=$args{IncludeClassOrigin} if(defined $args{IncludeClassOrigin});
187             $args{ico}=0 if(!defined $args{ico});
188             $args{iq}=$args{IncludeQualifiers} if(defined $args{IncludeQualifiers});
189             $args{iq}=0 if(!defined $args{iq});
190            
191             if($args{ico}) {
192             carp("WS-Management does not implement IncludeClassOrigin support");
193             return;
194             }
195             if($args{iq}) {
196             carp("WS-Management does not implement IncludeQualifiers support");
197             return;
198             }
199            
200             $self->current_uri($args{uri});
201             my $epr=$self->current_epr;
202             my $wsman=$self->current_wsman;
203             if(!defined $epr || !defined $wsman) {
204             return;
205             }
206            
207             my $xmlstr=$wsman->delete(epr=>$epr);
208             if(!defined $xmlstr) {
209             return;
210             }
211             my $xml=$self->{TWIG}->parse($xmlstr);
212             return if(!defined $xml);
213             if($self->_checkfault($xml->root)) {
214             return;
215             }
216             return 1;
217             }
218            
219             sub ModifyInstance
220             {
221             my $self=shift;
222             my %args=@_;
223             $args{uri}=$args{InstancePath} if(defined $args{InstancePath});
224             $args{object}=$args{ModifiedInstance} if(defined $args{ModifiedInstance});
225             $args{ico}=$args{IncludeClassOrigin} if(defined $args{IncludeClassOrigin});
226             $args{ico}=0 if(!defined $args{ico});
227             $args{iq}=$args{IncludeQualifiers} if(defined $args{IncludeQualifiers});
228             $args{iq}=0 if(!defined $args{iq});
229             $args{props}=$args{IncludedProperties} if(defined $args{IncludedProperties});
230            
231             if($args{ico}) {
232             carp("WS-Management does not implement IncludeClassOrigin support");
233             return;
234             }
235             if($args{iq}) {
236             carp("WS-Management does not implement IncludeQualifiers support");
237             return;
238             }
239             if(!defined $args{object}) {
240             carp("No ModifiedInstance (object) specified");
241             return;
242             }
243             $args{uri}=$args{object}->uri;
244            
245             $self->current_uri($args{uri});
246             my $epr=$self->current_epr;
247             my $wsman=$self->current_wsman;
248             if(!defined $epr || !defined $wsman) {
249             return;
250             }
251            
252             my $body=$self->_instance_to_XML($args{object});
253             return unless defined $body;
254             my $xmlstr=$wsman->put(epr=>$epr,body=>$body);
255             if(!defined $xmlstr) {
256             return;
257             }
258             my $xml=$self->{TWIG}->parse($xmlstr);
259             return if(!defined $xml);
260             if($self->_checkfault($xml->root)) {
261             return;
262             }
263             my $instance=$xml->root->first_child('s:Body')->first_child;
264             if(!defined $instance) {
265             carp("No instance nor fault returned!");
266             return;
267             }
268             my $ret=$self->_parse_instance($instance);
269             $ret->uri($self->current_uri->canonical);
270             return $ret;
271             }
272            
273             sub CreateInstance
274             {
275             my $self=shift;
276             my %args=@_;
277             $args{uri}=$args{ClassPath} if(defined $args{ClassPath});
278             $args{object}=$args{NewInstance} if(defined $args{NewInstance});
279             $args{ico}=$args{IncludeClassOrigin} if(defined $args{IncludeClassOrigin});
280             $args{ico}=0 if(!defined $args{ico});
281             $args{iq}=$args{IncludeQualifiers} if(defined $args{IncludeQualifiers});
282             $args{iq}=0 if(!defined $args{iq});
283            
284             if($args{ico}) {
285             carp("WS-Management does not implement IncludeClassOrigin support");
286             return;
287             }
288             if($args{iq}) {
289             carp("WS-Management does not implement IncludeQualifiers support");
290             return;
291             }
292             if(!defined $args{object}) {
293             carp("No new instance (object) specified");
294             return;
295             }
296             $args{uri}=$args{object}->uri;
297            
298             $self->current_uri($args{uri});
299             my $epr=$self->current_epr;
300             foreach my $key (keys %{$epr->{SelectorSet}}) {
301             delete $epr->{SelectorSet}{$key} unless $key eq '__cimnamespace';
302             }
303             my $wsman=$self->current_wsman;
304             if(!defined $epr || !defined $wsman) {
305             return;
306             }
307            
308             my $body=$self->_instance_to_XML($args{object});
309             return unless defined $body;
310             my $xmlstr=$wsman->create(epr=>$epr,body=>$body);
311             if(!defined $xmlstr) {
312             return;
313             }
314             my $xml=$self->{TWIG}->parse($xmlstr);
315             return if(!defined $xml);
316             if($self->_checkfault($xml->root)) {
317             return;
318             }
319             my $ref=$xml->root->first_child('s:Body')->first_child('t:ResourceCreated');
320             if(!defined $ref) {
321             carp("No instance nor EPR returned!");
322             return;
323             }
324             my $ret=URI->new($self->_parse_reference($ref));
325             if(defiend $ret->class) {
326             $self->class_tag_alias($ret->class, lc($ret->class));
327             }
328             return $ret->canonical;
329             }
330            
331             sub GetClassInstancesWithPath
332             {
333             my $self=shift;
334             return $self->_get_instances('class','instanceswithpath', @_);
335             }
336            
337             sub GetClassInstancePaths
338             {
339             my $self=shift;
340             return $self->_get_instances('class','paths', @_);
341             }
342            
343             sub GetReferencingInstancesWithPath
344             {
345             my $self=shift;
346             return $self->_get_instances('association','instanceswithpath', @_);
347             }
348            
349             sub GetReferencingInstancePaths
350             {
351             my $self=shift;
352             return $self->_get_instances('association','paths', @_);
353             }
354            
355             sub GetAssociatedInstancesWithPath
356             {
357             my $self=shift;
358             return $self->_get_instances('associated','instanceswithpath', @_);
359             }
360            
361             sub GetAssociatedInstancePaths
362             {
363             my $self=shift;
364             return $self->_get_instances('associated','paths', @_);
365             }
366            
367             sub InvokeMethod
368             {
369             my $self=shift;
370             my %args=@_;
371             my $faking=0;
372            
373             $args{uri}=$args{InstancePath} if(defined $args{InstancePath});
374             $args{method}=$args{MethodName} if(defined $args{MethodName});
375             $args{params}=$args{InParmValues} if(defined $args{InParmValues});
376             $args{ico}=$args{IncludeClassOrigin} if(defined $args{IncludeClassOrigin});
377             $args{ico}=0 if(!defined $args{ico});
378             $args{iq}=$args{IncludeQualifiers} if(defined $args{IncludeQualifiers});
379             $args{iq}=0 if(!defined $args{iq});
380            
381             if($args{ico}) {
382             carp("WS-Management does not implement IncludeClassOrigin support");
383             return;
384             }
385             if($args{iq}) {
386             carp("WS-Management does not implement IncludeQualifiers support");
387             return;
388             }
389             if(!defined $args{method}) {
390             carp("No method argument passed to InvokeMethod()");
391             return;
392             }
393             $self->current_uri($args{uri});
394             my $epr=$self->current_epr;
395             my $wsman=$self->current_wsman;
396             if(!defined $epr || !defined $wsman) {
397             return;
398             }
399            
400             my $classname;
401             if($epr->{ResourceURI} =~ /([^\/]*)$/) {
402             $classname=$1;
403             }
404             else {
405             carp "Unable to extract class from $epr->{ResourceURI}";
406             return;
407             }
408            
409             # We need the model to invoke methods... no half-assing this one.
410             my $model;
411             $model=$self->{MODEL}{indications}{lc($classname)} if defined $self->{MODEL}{indications}{lc($classname)};
412             $model=$self->{MODEL}{associations}{lc($classname)} if defined $self->{MODEL}{associations}{lc($classname)};
413             $model=$self->{MODEL}{classes}{lc($classname)} if defined $self->{MODEL}{classes}{lc($classname)};
414             if(!defined $model) {
415             if(defined $self->GetClass) {
416             my $class=$self->GetClass($classname);
417             if(defined $class && $class->{name} eq lc($args{tag})) {
418             if($class->{qualifiers}{association}{value} eq 'true') {
419             $self->{MODEL}{associations}{lc($class->{name})}=$class;
420             }
421             elsif($class->{qualifiers}{indication}{value} eq 'true') {
422             $self->{MODEL}{indications}{lc($class->{name})}=$class;
423             }
424             else {
425             $self->{MODEL}{classes}{lc($class->{name})}=$class;
426             }
427             $model=$class;
428             }
429             }
430             }
431             # If we don't have a real model, make up one that will work...
432             if(!defined $model) {
433             $faking=1;
434             my $lcm=lc($args{method});
435             $model = {
436             name=>$classname,
437             methods=>{
438             $lcm=>{
439             type=>'string',
440             name=>$args{method},
441             parameters=>{}
442             }
443             }
444             };
445             foreach my $param (keys %{$args{params}}) {
446             $model->{methods}{$lcm}{parameters}{lc($param)}{type}='string';
447             $model->{methods}{$lcm}{parameters}{lc($param)}{name}=$param;
448             if(ref($args{params}->{$param}) eq 'ARRAY') {
449             $model->{methods}{$lcm}{parameters}{lc($param)}{array}='';
450             }
451             }
452             }
453            
454             my $body=$self->_params_to_XML($model, $args{method}, $args{params});
455             return unless defined $body;
456            
457             my $xmlstr=$wsman->invoke(epr=>$epr, method=>$args{method}, body=>$body);
458             if(!defined $xmlstr) {
459             return;
460             }
461             my $xml=$self->{TWIG}->parse($xmlstr);
462             return if(!defined $xml);
463             if($self->_checkfault($xml->root)) {
464             return;
465             }
466            
467             my $outparams;
468             for($outparams=$xml->root->first_child('s:Body')->first_child; defined $outparams; $outparams=$outparams->next_sibling) {
469             if($outparams->local_name eq "$args{method}\_OUTPUT") {
470             if($outparams->namespace eq $epr->{ResourceURI}) {
471             last;
472             }
473             }
474             }
475             if(!defined $outparams) {
476             carp("Unable to locate output parameters in response");
477             return;
478             }
479             my $ret={};
480             for(my $out=$outparams->first_child; defined $out; $out=$out->next_sibling) {
481             next if($out->tag eq '#PCDATA');
482             my $outparam=$out->local_name;
483             my $paramdef;
484             if($outparam eq 'ReturnValue') {
485             $paramdef=$model->{methods}{lc($args{method})};
486             }
487             else {
488             if($faking) {
489             $model->{methods}{lc($args{method})}{parameters}{lc($outparam)}={
490             type=>'string',
491             };
492             }
493             $paramdef=$model->{methods}{lc($args{method})}{parameters}{lc($outparam)};
494             if(!defined $paramdef) {
495             carp("Included output parameter $outparam is not defined in the mode;");
496             return;
497             }
498             }
499             my ($value,$type)=$self->_stringify($out,$paramdef);
500             # Special uint8[] octetString handling here.
501             if(defined $type && $type eq 'bytes') {
502             my @bytes=split(//,$value);
503             $ret->{$outparam}=[@bytes];
504             }
505             else {
506             if(defined $type) {
507             if($faking) {
508             $paramdef->{type}=$type;
509             }
510             if($type ne $paramdef->{type}) {
511             carp("Type mismatch in value of $outparam ($value) $type ne $paramdef->{type}");
512             return;
513             }
514             }
515             if($faking) {
516             if(defined $ret->{outparam}) {
517             $paramdef->{array}='';
518             $ret->{$outparam} = [$ret->{$outparam}];
519             }
520             }
521             if(defined $paramdef->{array}) {
522             $ret->{$outparam} = [] unless defined $ret->{$outparam};
523             push @{$ret->{$outparam}},$value;
524             }
525             else {
526             $ret->{$outparam}=$value;
527             }
528             }
529             }
530            
531             return $ret;
532             }
533            
534             #####################
535             # Utility functions #
536             #####################
537             sub current_wsman
538             {
539             my $self=shift;
540            
541             my $uri=$self->current_uri;
542             if(!defined $uri) {
543             return;
544             }
545            
546             if(!defined $uri->host) {
547             carp("No host in uri");
548             return;
549             }
550            
551             if(!defined $uri->port) {
552             carp("No port in uri");
553             return;
554             }
555            
556             if(!defined $self->{AUTHORITIES}{$uri->host_port}) {
557             my %connect_args;
558             if(!defined $uri->userinfo) {
559             carp("No user info specified for uri");
560             return;
561             }
562             if($uri->scheme =~ /s$/) {
563             $connect_args{protocol}='https';
564             }
565             else {
566             $connect_args{protocol}='http';
567             }
568             if($uri->userinfo =~ /^([^:]*):([^@]*)$/) {
569             my ($user,$pass)=($1,$2);
570             $connect_args{user}=uri_unescape($user);
571             $connect_args{pass}=uri_unescape($pass);
572             }
573             else {
574             carp("Missing password in URI");
575             return;
576             }
577             $connect_args{port}=$uri->port;
578             $connect_args{host}=$uri->host;
579             $self->{AUTHORITIES}{$uri->host_port}={userinfo=>$uri->userinfo};
580             $self->{AUTHORITIES}{$uri->host_port}->{Session}=DMTF::WSMan->new(%connect_args);
581             }
582            
583             return($self->{AUTHORITIES}{$uri->host_port}->{Session});
584             }
585            
586             sub current_uri
587             {
588             my $self=shift;
589             my $URI=shift;
590            
591             if(!defined $URI) {
592             return $self->{CURRENTURI};
593             }
594            
595             my $newuri=URI->new($URI);
596             $self->{CURRENTURI}->scheme($newuri->scheme) if(defined $newuri->scheme);
597             if(defined $newuri->authority) {
598             $self->{CURRENTURI}->host_port($newuri->host_port) if(defined $newuri->host_port);
599             if(defined $newuri->userinfo) {
600             my $newinfo=$newuri->userinfo;
601             my $oldinfo=$self->{CURRENTURI}->userinfo;
602             if($newinfo =~ /^[^:]*:[^@]*$/) {
603             $self->{CURRENTURI}->userinfo($newinfo);
604             }
605             elsif($oldinfo =~ /^[^:]*:([^@]*)$/) {
606             $self->{CURRENTURI}->userinfo("$newinfo:$1");
607             }
608             else {
609             $self->{CURRENTURI}->userinfo($newinfo);
610             }
611             }
612             elsif(defined $self->{AUTHORITIES}{$self->{CURRENTURI}->host_port}{userinfo}) {
613             $self->{CURRENTURI}->userinfo($self->{AUTHORITIES}{$self->{CURRENTURI}->host_port}{userinfo});
614             }
615             }
616             my ($cnamespace);
617             if($self->{CURRENTURI}->path =~ /^(?:\/([^:]*?))?(?::.*)?$/) {
618             $cnamespace=$1;
619             }
620             my ($namespace, $instance, $path);
621             if(defined $newuri->path) {
622             if(ref($newuri) eq 'URI::_generic') {
623             $path=$newuri;
624             }
625             else {
626             $path=$newuri->path;
627             }
628             }
629             if(defined $path) {
630             if($path =~ /^\/([^:]*)$/) { # Starts with a slash, has no colon
631             # no class
632             $namespace=$1;
633             }
634             elsif($path =~ /^([^\/].*)$/) { # Doesn't start with a slash
635             # no namespace
636             $instance=$1;
637             }
638             elsif($path =~ /^\/([^:]*):(.*)$/) { # Starts with a slash, has colon
639             ($namespace, $instance)=($1,$2);
640             }
641             else {
642             carp("Impossible path in new URI");
643             return;
644             }
645             }
646             $namespace = $cnamespace unless defined $namespace;
647             if(defined $instance) {
648             $instance=":$instance";
649             }
650             else {
651             $instance='';
652             }
653             $self->{CURRENTURI}->path("$namespace$instance");
654             if($self->{CURRENTURI}->scheme !~ /^(http|wsman\.wbem)s?$/) {
655             carp("Unsupported scheme: ".$self->{CURRENTURI}->scheme);
656             return;
657             }
658             return $self->{CURRENTURI};
659             }
660            
661             sub current_epr
662             {
663             my $self=shift;
664             return $self->URItoEPR($self->current_uri);
665             }
666            
667             sub URItoEPR
668             {
669             my $self=shift;
670             my $uri=shift;
671             my %ret;
672            
673             my $scheme=$uri->scheme;
674             my $path=$uri->path;
675             if($path =~ /^\/(.*?):(.*?)(?:\.(.*))?$/) {
676             my ($namespace,$class,$keys)=($1,$2,$3);
677             if($class eq '*') {
678             $ret{ResourceURI}='http://schemas.dmtf.org/wbem/wscim/1/*';
679             }
680             else {
681             $ret{ResourceURI}="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/$class";
682             }
683             if(defined $namespace && $namespace ne '') {
684             $ret{SelectorSet}{__cimnamespace}=$namespace;
685             }
686             if(defined $keys && $keys ne '') {
687             my @splitkeys=split(/,/,$keys);
688             my @keys;
689             foreach my $key (@splitkeys) {
690             $key=uri_unescape($key);
691             if($#keys >= 0) {
692             my $last=substr($keys[$#keys], -1);
693             if($last eq '"') {
694             $last = '' if(substr($keys[$#keys], -2) eq '\"');
695             }
696             if($last ne '"') {
697             $keys[$#keys] .= ",$key";
698             next;
699             }
700             }
701             push(@keys,$key);
702             }
703             foreach my $key (@keys) {
704             if($key =~ /^(.*?)="(.*)"$/) {
705             my ($key,$value)=($1,$2);
706             $value =~ s/\\([\\"])/$1/g;
707             if($value =~ m|^wsman.wbems?://[^/]+/[^:]+:[^\.]+\..+|) {
708             my $uri=URI->new($value);
709             $value=$self->URItoEPR($uri);
710             }
711             $ret{SelectorSet}{$key}=$value;
712             }
713             }
714             }
715             }
716             else {
717             carp "Unable to extract namespace and class from $path";
718             return;
719             }
720             return {%ret};
721             }
722            
723             sub quirks
724             {
725             my $self=shift;
726             my $name=shift;
727             my $value=shift;
728            
729             return sort keys %{$self->{QUIRKS}} unless defined $name;
730             return $self->{QUIRKS}{$name} unless defined $value;
731             $self->{QUIRKS}{$name}=$value;
732             }
733            
734             #####################
735             # Private Functions #
736             #####################
737             sub _get_instances
738             {
739             my $self=shift;
740             my $type=shift;
741             my $mode=shift;
742             my %args=@_;
743             if($type eq 'class') {
744             $args{uri}=$args{EnumClassPath} if(defined $args{EnumClassPath});
745             }
746             else {
747             $args{uri}=$args{SourceInstancePath} if(defined $args{SourceInstancePath});
748             }
749             $args{ico}=$args{IncludeClassOrigin} if(defined $args{IncludeClassOrigin});
750             $args{ico}=0 if(!defined $args{ico});
751             $args{iq}=$args{IncludeQualifiers} if(defined $args{IncludeQualifiers});
752             $args{iq}=0 if(!defined $args{iq});
753             $args{props}=$args{IncludedProperties} if(defined $args{IncludedProperties});
754             $args{via}=$args{AssociationClassName} if(defined $args{AssociationClassName});
755             $args{class}=$args{AssociatedClassName} if(defined $args{AssociatedClassName});
756             $args{role}=$args{SourceRoleName} if(defined $args{SourceRoleName});
757             $args{rrole}=$args{AssociatedRoleName} if(defined $args{AssociatedRoleName});
758             $args{esp}=$args{ExcludeSubclassProperties} if(defined $args{ExcludeSubclassProperties});
759            
760             if($args{ico}) {
761             carp("WS-Management does not implement IncludeClassOrigin support");
762             return;
763             }
764             if($args{iq}) {
765             carp("WS-Management does not implement IncludeQualifiers support");
766             return;
767             }
768            
769             my $enum_mode;
770             if($mode eq 'paths') {
771             $enum_mode='EnumerateEPR';
772             }
773             else {
774             $enum_mode='EnumerateObjectAndEPR';
775             }
776            
777             $self->current_uri($args{uri});
778             my $epr=$self->current_epr;
779             my $wsman=$self->current_wsman;
780             if(!defined $epr || !defined $wsman) {
781             return;
782             }
783            
784             my $filterstr='';
785            
786             my $target_epr;
787             if($type eq 'class') {
788             $target_epr=$self->current_epr;
789             }
790             else {
791             my $filteroptions='';
792             if(defined $args{class}) {
793             $filteroptions.="<$wsman->{Context}{xmlns}{cim}{prefix}:ResultClassName>$args{class}{Context}{xmlns}{cim}{prefix}:ResultClassName>";
794             }
795             if(defined $args{role}) {
796             $filteroptions.="<$wsman->{Context}{xmlns}{cim}{prefix}:Role>$args{role}{Context}{xmlns}{cim}{prefix}:Role>";
797             }
798             if(defined $args{props}) {
799             if(ref($args{props})=='ARRAY') {
800             foreach my $prop (@{$args{props}}) {
801             $filteroptions.="<$wsman->{Context}{xmlns}{cim}{prefix}:IncludeResultProperty>$args{role}{Context}{xmlns}{cim}{prefix}:IncludeResultProperty>";
802             }
803             }
804             }
805             if($type eq 'associated') {
806             if(defined $args{via}) {
807             $filteroptions.="<$wsman->{Context}{xmlns}{cim}{prefix}:AssociationClassName>$args{via}{Context}{xmlns}{cim}{prefix}:AssociationClassName>";
808             }
809             if(defined $args{rrole}) {
810             $filteroptions.="<$wsman->{Context}{xmlns}{cim}{prefix}:ResultRole>$args{role}{Context}{xmlns}{cim}{prefix}:ResultRole>";
811             }
812             $filterstr=$self->_associationFilter($wsman,'AssociatedInstances',$epr,$filteroptions);
813             }
814             else {
815             $filterstr=$self->_associationFilter($wsman,'AssociationInstances',$epr,$filteroptions);
816             }
817             my $curi=URI->new($self->current_uri);
818             my $cpath=$curi->path;
819             $cpath =~ s/:.*$//;
820             $cpath .= ':*';
821             $curi->path($cpath);
822             $target_epr=$self->URItoEPR($curi);
823             }
824            
825             # TODO: We need to perform additional filtering on the arguments since WS-Management doesn't support them all.
826             my $rawxml=$wsman->enumerate(epr=>$target_epr, mode=>$enum_mode, filter=>$filterstr);
827             $rawxml=~s/<\?\s*xml.*?\?>[^<]*//;
828             my $xml=$self->{TWIG}->parse(''.$rawxml.'');
829             if(!defined $xml) {
830             carp("Error parsing XML");
831             return;
832             }
833             my $ret=[];
834             for(my $reply=$xml->root->first_child('s:Envelope');defined $reply;$reply=$reply->next_sibling) {
835             next if (!defined $reply->first_child('s:Body'));
836             if($self->_checkfault($reply)) {
837             return;
838             }
839             my $response=$reply->first_child('s:Body')->first_child('n:EnumerateResponse');
840             my $items;
841             $items=$response->first_child('w:Items') if(defined $response);
842             if(!defined $response) {
843             $response=$reply->first_child('s:Body')->first_child('n:PullResponse');
844             $items=$response->first_child('n:Items') if(defined $response);
845             }
846             if(!defined $response) {
847             carp('Unable to locate response object on response');
848             return;
849             }
850             if(!defined $items) {
851             next if($response->local_name eq 'EnumerateResponse'); # The EnumerateResponse may not have an Items in it.
852             return @{$ret};
853             }
854             for(my $item=$items->first_child;defined $item;$item=$item->next_sibling) {
855             next if($item->tag eq '#PCDATA');
856             if($mode eq 'paths') {
857             my $pi=$self->_parse_reference($item);
858             push @{$ret},$pi if(defined $pi);
859             }
860             else {
861             my $object;
862             for($object=$item->first_child; defined $object;$object=$object->next_sibling) {
863             next if($object->tag eq '#PCDATA');
864             last;
865             }
866             if(!defined $object) {
867             carp('Item returned with no object');
868             return;
869             }
870             my $obj=$self->_parse_instance($object);
871             return if(!defined $obj);
872             my $epr=$item->first_child('a:EndpointReference');
873             if(!defined $epr) {
874             carp('Item returned with no EPR');
875             return;
876             }
877             $obj->uri($self->_parse_reference($epr));
878             push @{$ret},$obj;
879             }
880             }
881             }
882             return @{$ret};
883             }
884            
885             sub _XML_escape
886             {
887             my $val=shift;
888             $val=~s/&/&/g;
889             $val=~s/
890             $val=~s/"/"/g;
891             $val=~s/'/'/g;
892             return $val;
893             }
894            
895             sub _instance_to_XML
896             {
897             my $self=shift;
898             my $obj=shift;
899             my $ret='';
900             my $class=$obj->class;
901             my $wsman=$self->current_wsman;
902            
903             $ret.="";
904             foreach my $prop (sort { $a->name cmp $b->name } $obj->defined_properties) {
905             my $val;
906             if($prop->is_array) {
907             $val=[$prop->value];
908             }
909             else {
910             $val=$prop->value;
911             }
912             my $octetstring=$prop->qualifier('octetstring');
913             if(defined $octetstring
914             && $octetstring eq 'true'
915             && $prop->type =~ /(uint8|string)\[\]/) {
916             if($1 eq 'string') {
917             if(ref($val) eq 'ARRAY') {
918             foreach my $value (@$val) {
919             my $v=uc(unpack("H*",$value));
920             $v = sprintf('0x%08X%s',((length($v)/2)+4),$v) if($self->{QUIRKS}{incorrect_string_octetstring});
921             $ret .= "name).">$vname).">";
922             }
923             }
924             else {
925             if($self->{QUIRKS}{incorrect_string_octetstring}) {
926             $val = sprintf('0x%08X%s',(length($val)+4),uc(unpack("H*",$val)));
927             }
928             else {
929             $val = uc(unpack("H*",$val));
930             }
931             $ret .= "name).">".$val."name).">";
932             }
933             }
934             else {
935             my $decoded;
936             if(ref($val) eq 'ARRAY') {
937             $decoded=join('',@{$val});
938             }
939             else {
940             $decoded=$val;
941             }
942             $ret .= "name).">".encode_base64($decoded)."name).">";
943             }
944             }
945             elsif(ref($val) eq 'ARRAY') {
946             foreach my $value (@$val) {
947             if($prop->is_ref) {
948             $value=$wsman->epr_to_xml($self->URItoEPR(URI->new($value)));
949             }
950             elsif($prop->type eq 'datetime') {
951             $value="<$wsman->{Context}{cim}{prefix}:CIM_DateTime>$value{Context}{cim}{prefix}:CIM_DateTime>";
952             }
953             $ret .= "name).">"._XML_escape($value)."name).">";
954             }
955             }
956             else {
957             if($prop->is_ref) {
958             $val=$wsman->epr_to_xml($self->URItoEPR(URI->new($val)));
959             }
960             elsif($prop->type eq 'datetime') {
961             $val="<$wsman->{Context}{cim}{prefix}:CIM_DateTime>$val{Context}{cim}{prefix}:CIM_DateTime>";
962             }
963             $ret .= "name).">"._XML_escape($val)."name).">";
964             }
965             }
966             $ret.="";
967             }
968            
969             sub _params_to_XML
970             {
971             my $self=shift;
972             my $class=shift; # A class definition from the model
973             my $method=shift;
974             my $lcm=lc($method);
975             my $params=shift; # Hashref containg scalars and arrayrefs
976             my $ret='';
977             my $wsman=$self->current_wsman;
978            
979             $ret.="{name}\">";
980             foreach my $param (sort keys %{$params}) {
981             my $paramdef=$class->{methods}{$lcm}{parameters}{lc($param)};
982             if(!defined $paramdef) {
983             carp("Undefined parameter $param passed to $method method of $class->{name}");
984             return;
985             }
986             if(!defined $paramdef->{type}) {
987             carp("Unknown type for parameter $paramdef->{name} passed to $method of $class->{name}");
988             return;
989             }
990            
991             my $val=$params->{$param};
992            
993             if(ref($val) eq 'ARRAY') {
994             foreach my $value (@$val) {
995             if($paramdef->{type} eq 'ref') {
996             $value=$wsman->epr_to_xml($self->URItoEPR(URI->new($value)));
997             }
998             elsif($paramdef->{type} eq 'datetime') {
999             $value="<$wsman->{Context}{cim}{prefix}:CIM_DateTime>$value{Context}{cim}{prefix}:CIM_DateTime>";
1000             }
1001             $ret .= "{name}>$value{name}>";
1002             }
1003             }
1004             else {
1005             if($paramdef->{type} eq 'ref') {
1006             $val=$wsman->epr_to_xml($self->URItoEPR(URI->new($val)));
1007             }
1008             elsif($paramdef->{type} eq 'datetime') {
1009             $val="<$wsman->{Context}{cim}{prefix}:CIM_DateTime>$val{Context}{cim}{prefix}:CIM_DateTime>";
1010             }
1011             $ret .= "{name}>$val{name}>";
1012             }
1013             }
1014             $ret.="";
1015             }
1016            
1017             sub _associationFilter
1018             {
1019             my $self=shift;
1020             my $wsman=shift;
1021             my $filtertag=shift;
1022             my $epr=shift;
1023             my $options=shift;
1024             $options='' if(!defined $options);
1025            
1026             my $selectorset=$wsman->get_selectorset_xml($epr);
1027             my $eprxml=$wsman->epr_to_xml($epr);
1028             # Some implementations incorrectly assume the Object tag in the
1029             # association filter is an EPR so the children would be Address and
1030             # ReferenceParameters directly instead of it *containg* an EPR which
1031             # would have the first child be an EndpointReference
1032             if($self->{QUIRKS}{association_object_wrong}) {
1033             $eprxml =~ s/^\s*<(?:[^:]*:)?EndpointReference(?:\s.*)?>(.*)<\/(?:[^:]*:)?EndpointReference(?:\s*)>\s*$/$1/s;
1034             }
1035            
1036             return <
1037             <$wsman->{Context}{xmlns}{wsman}{prefix}:Filter Dialect="http://schemas.dmtf.org/wbem/wsman/1/cimbinding/associationFilter">
1038             <$wsman->{Context}{xmlns}{cim}{prefix}:$filtertag>
1039             <$wsman->{Context}{xmlns}{cim}{prefix}:Object>
1040             EOF
1041             .$eprxml.<
1042             {Context}{xmlns}{cim}{prefix}:Object>
1043             $options
1044             {Context}{xmlns}{cim}{prefix}:$filtertag>
1045             {Context}{xmlns}{wsman}{prefix}:Filter>
1046             EOF
1047             }
1048            
1049             sub _stringify
1050             {
1051             my $self=shift;
1052             my $twig=shift;
1053             my $model=shift;
1054             my $child;
1055            
1056             my $isnull=$twig->att('x:nil');
1057             if(defined $isnull) {
1058             if($isnull eq 'true' || $isnull eq '1') {
1059             return;
1060             }
1061             elsif($isnull ne 'false' && $isnull ne '0') {
1062             carp("Invalid xsi:nil value of $isnull");
1063             }
1064             }
1065             for($child=$twig->first_child; defined $child;$child=$child->next_sibling) {
1066             next if($child->tag eq '#PCDATA');
1067             last;
1068             }
1069             if(defined $child) {
1070             my $type=$child->tag;
1071             if($type eq 'a:EndpointReference') {
1072             my $ref=$self->_parse_reference($child);
1073             return wantarray ? ($self->_parse_reference($child),'ref') : $ref;
1074             }
1075             elsif($type eq 'a:Address' || $type eq 'a:ReferenceParameters') {
1076             my $ref=$self->_parse_reference($twig);
1077             return wantarray ? ($self->_parse_reference($twig),'ref') : $ref;
1078             }
1079             elsif($type eq 'c:CIM_DateTime') {
1080             return wantarray ? ($child->text,'datetime') : $child->text;
1081             }
1082             elsif($type eq 'c:Interval') {
1083             my $val=$child->text;
1084             $val =~ s/^\s*(.*?)\s*$/$1/;
1085             if($val =~ /^(-?)P(?:([0-9]+)Y)?(?:([0-9]+)M)?(?:([0-9]+)D)?(?:T(?:([0-9]+)H)?(?:([0-9]+)M)?(?:([0-9]+)(.[0-9]+)?S)?)?$/) {
1086             my ($neg,$y,$m,$d,$h,$min,$s,$fs)=($1,$2,$3,$4,$5,$6,$7,$8);
1087             $y=0 unless defined $y;
1088             $m=0 unless defined $m;
1089             $d=0 unless defined $d;
1090             $h=0 unless defined $h;
1091             $min=0 unless defined $min;
1092             $s=0 unless defined $s;
1093             $fs=0 unless defined $fs;
1094             $fs=substr(sprintf("%0.6f",$fs),1);
1095             if(defined $neg && $neg eq '-') {
1096             $y=0-$y;
1097             $m=0-$m;
1098             $d=0-$d;
1099             $h=0-$h;
1100             $min=0-$min;
1101             $s=0-$s;
1102             }
1103             my $duration=DateTime::Duration->new(
1104             years=>$y,
1105             months=>$m,
1106             days=>$d,
1107             hours=>$h,
1108             minutes=>$min,
1109             seconds=>$s,
1110             );
1111             my($dd,$dh,$dm,$ds)=$duration->in_units('days','hours','minutes','seconds');
1112             my $int=sprintf("%08d%02d%02d%02d%s",$dd,$dh,$dm,$ds,$fs);
1113             return wantarray ? ($int,'datetime') : $int;
1114             }
1115             else {
1116             carp("Unrecognized interval representation $val");
1117             return;
1118             }
1119             }
1120             elsif($type eq 'c:Date') {
1121             my $val=$child->text;
1122             $val =~ s/^\s*(.*?)\s*$/$1/;
1123             if($val =~ /^(-?[0-9]{4,})-([0-9]{2})-([0-9]{2})(Z|(?:[-+][0-9]{2}:[0-9]{2}))?$/) {
1124             my ($y,$m,$d,$tz)=($1,$2,$3,$4);
1125             if($y < 0) {
1126             carp("CIM cannot model dates BC ($val)");
1127             return;
1128             }
1129             $tz="+00:00" if $tz eq 'Z';
1130             if($tz=~/^([-+])([0-9]{2}):([0-9]{2})$/) {
1131             my ($sign,$hour,$min)=($1,$2,$3);
1132             $tz=$hour*60+$min;
1133             $tz=0-$tz if $sign eq '-';
1134             my $dt=sprintf("%04d%02d%02d******.******%+02d",$y,$m,$d,$tz);
1135             return wantarray ? ($dt,'datetime') : $dt;
1136             }
1137             else {
1138             carp("Unrecognized timezone $tz");
1139             return;
1140             }
1141             }
1142             else {
1143             carp("Unrecognized date representation $val");
1144             return;
1145             }
1146             }
1147             elsif($type eq 'c:Time') {
1148             my $val=$child->text;
1149             $val =~ s/^\s*(.*?)\s*$/$1/;
1150             if($val =~ /^([0-9]{2}):([0-9]{2}):([0-9]{2})(\.[0-9]+)?(Z|(?:[-+][0-9]{2}:[0-9]{2}))?$/) {
1151             my ($h,$m,$s,$fs,$tz)=($1,$2,$3,$4,$5);
1152             $fs=0 unless defined $fs;
1153             $fs=substr(sprintf("%0.6f",$fs),1);
1154             $tz="+00:00" if $tz eq 'Z';
1155             if($tz=~/^([-+])([0-9]{2}):([0-9]{2})$/) {
1156             my ($sign,$hour,$min)=($1,$2,$3);
1157             $tz=$hour*60+$min;
1158             $tz=0-$tz if $sign eq '-';
1159             my $dt=sprintf("********%02d%02d%02d%s%+02d",$h,$m,$s,$fs,$tz);
1160             return wantarray ? ($dt,'datetime') : $dt;
1161             }
1162             else {
1163             carp("Unrecognized timezone $tz");
1164             return;
1165             }
1166             }
1167             else {
1168             carp("Unrecognized date representation $val");
1169             return;
1170             }
1171             }
1172             elsif($type eq 'c:Datetime') {
1173             my $val=$child->text;
1174             $val =~ s/^\s*(.*?)\s*$/$1/;
1175             if($val =~ /^(-?[0-9]{4,})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(\.[0-9]+)?(Z|(?:[-+][0-9]{2}:[0-9]{2}))?$/) {
1176             my ($y,$m,$d,$h,$min,$s,$fs,$tz)=($1,$2,$3,$4,$5,$6,$7,$8);
1177             if($y < 0) {
1178             carp("CIM cannot model dates BC ($val)");
1179             return;
1180             }
1181             $fs=0 unless defined $fs;
1182             $fs=substr(sprintf("%0.6f",$fs),1);
1183             $tz="+00:00" if $tz eq 'Z';
1184             if($tz=~/^([-+])([0-9]{2}):([0-9]{2})$/) {
1185             my ($sign,$hour,$min)=($1,$2,$3);
1186             $tz=$hour*60+$min;
1187             $tz=0-$tz if $sign eq '-';
1188             my $dt=sprintf("%04d%02d%02d%02d%02d%02d%s%+02d",$y,$m,$d,$h,$min,$s,$fs,$tz);
1189             return wantarray ? ($dt,'datetime') : $dt;
1190             }
1191             else {
1192             carp("Unrecognized timezone $tz");
1193             return;
1194             }
1195             }
1196             else {
1197             carp("Unrecognized date representation $val");
1198             return;
1199             }
1200             }
1201             else {
1202             carp("Unhandled data type $type in EPR Selector");
1203             return;
1204             }
1205             }
1206             else {
1207             if(defined $model
1208             && defined $model->{qualifiers}
1209             && defined $model->{qualifiers}{octetstring}
1210             && $model->{qualifiers}{octetstring} eq 'true') {
1211             if(defined $model->{type}
1212             && $model->{type} eq 'uint8'
1213             && defined $model->{array}) {
1214             my $decoded=decode_base64($twig->text);
1215             return wantarray ? ($decoded, 'bytes') : $decoded;
1216             }
1217             if(defined $model->{type}
1218             && $model->{type} eq 'string'
1219             && defined $model->{array}) {
1220             my $encoded=$twig->text;
1221             $encoded=~s/([0-9A-Fa-f]{2})/chr(hex($1))/eg;
1222             if($self->{QUIRKS}{incorrect_string_octetstring}) {
1223             $encoded =~ s/^0x[0-9a-fA-F]{8}//;
1224             }
1225             return $encoded;
1226             }
1227             }
1228             return $twig->text;
1229             }
1230             }
1231            
1232             sub _parse_reference
1233             {
1234             my $self=shift;
1235             my $reference=shift;
1236             my $ns='interop';
1237             my $authority;
1238             my $scheme='wsman.wbem';
1239             my $path;
1240             my $class;
1241            
1242             my $rp=$reference->first_child('a:ReferenceParameters');
1243             if(!defined $rp) {
1244             carp("No reference parameters in EPR");
1245             return;
1246             }
1247             my $ruri=$rp->first_child('w:ResourceURI')->text;
1248             if(!defined $ruri) {
1249             carp("Unable to locate ResourceURI in EPR");
1250             return;
1251             }
1252             if($ruri=~/^.*\/([^\/]+)$/) {
1253             $class=$1;
1254             }
1255             if(!defined $class) {
1256             carp("Unable to parse class from uri $ruri");
1257             }
1258             $self->class_tag_alias($class, lc($class));
1259             my $ss=$reference->first_child('a:ReferenceParameters')->first_child('w:SelectorSet');
1260             if(defined $ss) {
1261             my %vals;
1262             for(my $sel=$ss->first_child('w:Selector');defined $sel;$sel=$sel->next_sibling('w:Selector')) {
1263             my $name=$sel->att('Name');
1264             if(!defined $name) {
1265             carp("Missing selector name in EPR");
1266             return;
1267             }
1268             if($name eq '__cimnamespace') {
1269             $ns=$sel->text;
1270             }
1271             else {
1272             $vals{$name}=$self->_stringify($sel);
1273             }
1274             }
1275             foreach my $val (sort keys %vals) {
1276             if(defined $path) {
1277             $path .= ',';
1278             }
1279             else {
1280             $path .= '.';
1281             }
1282             $path .= uri_escape("$val=","?#");
1283             my $eq=$vals{$val};
1284             $eq =~ s/\\/\\\\/g;
1285             $eq =~ s/"/\\"/g;
1286             $path .= uri_escape("\"$eq\"","?#");
1287             }
1288             }
1289             $path='' unless defined $path;
1290             $path="$class$path";
1291             $ns =~ s/^[\/]*(.*?)[\/]*$/$1/;
1292             $path="$ns:$path";
1293             my $addr=$reference->first_child('a:Address');
1294             if(defined $addr && $addr->text ne 'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous') {
1295             my $auri=URI->new($addr->text);
1296             $scheme=$auri->scheme if defined $auri->scheme;
1297             $scheme=~s/^http(s?)$/wsman.wbem$1/;
1298             $authority=$auri->authority if defined $auri->authority;
1299             }
1300             if(defined $authority) {
1301             return "$scheme://$authority/$path";
1302             }
1303             return "/$path";
1304             }
1305            
1306             sub _parse_instance
1307             {
1308             my $self=shift;
1309             my $instance=shift;
1310             my $ret={
1311             VALUES=>{},
1312             DATA=>{
1313             properties=>{},
1314             references=>{},
1315             },
1316             };
1317            
1318             my $ns=$instance->namespace;
1319             if($ns =~ m|^http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/(.*)$|) {
1320             $ret->{DATA}{name}=$1;
1321             }
1322             my $ci;
1323             {
1324             local $SIG{__WARN__}=sub {};
1325             $ci=$self->instance_of($ret->{DATA}{name});
1326             }
1327             for(my $tag=$instance->first_child();defined $tag;$tag=$tag->next_sibling) {
1328             next if($tag->namespace ne $ns);
1329             my $prop=$tag->local_name;
1330             my $propref=$ret->{DATA}{properties}{lc($prop)};
1331             if(defined $ret->{DATA}{references}{lc($prop)}) {
1332             if(defined $propref) {
1333             delete $ret->{DATA}{properties}{lc($prop)};
1334             }
1335             $propref=$ret->{DATA}{references}{lc($prop)};
1336             }
1337             if(!defined $propref) {
1338             $ret->{DATA}{properties}{lc($prop)}={};
1339             $propref=$ret->{DATA}{properties}{lc($prop)};
1340             }
1341            
1342             if(!defined $ci) {
1343             if(!defined $propref->{name}) {
1344             $propref->{name}=$prop;
1345             }
1346             }
1347             if(defined $ret->{VALUES}{$prop}) {
1348             if(ref($ret->{VALUES}{$prop}) ne 'ARRAY') {
1349             $propref->{array}='';
1350             $ret->{VALUES}{$prop}=[$ret->{VALUES}{$prop}];
1351             }
1352             }
1353             elsif(defined $ci) {
1354             if($ci->property($prop)->is_array) {
1355             $ret->{VALUES}{$prop}=[];
1356             }
1357             }
1358             my ($value,$type)=$self->_stringify($tag,$propref);
1359             # Special uint8[] octetString handling here.
1360             if(defined $type && $type eq 'bytes') {
1361             my @bytes=split(//,$value);
1362             $ret->{VALUES}{$prop}=[@bytes];
1363             $propref->{type}='uint8' unless defined $propref->{type};
1364             $propref->{array}='' unless defined $propref->{array};
1365             }
1366             else {
1367             if(defined $type) {
1368             if($type eq 'ref') {
1369             if(!defined $ci) {
1370             $ret->{DATA}{qualifiers}{association}{value}='true';
1371             if(defined $ret->{DATA}{properties}{lc($prop)}) {
1372             $ret->{DATA}{references}{lc($prop)}={%$propref};
1373             $propref=$ret->{DATA}{references}{lc($prop)};
1374             delete $ret->{DATA}{properties}{lc($prop)};
1375             }
1376             $propref->{DATA}{references}{lc($prop)}{is_ref}='true';
1377             }
1378             }
1379             $propref->{type}=$type;
1380             }
1381             if(ref($ret->{VALUES}{$prop}) eq 'ARRAY') {
1382             push @{$ret->{VALUES}{$prop}},$value;
1383             }
1384             else {
1385             $ret->{VALUES}{$prop}=$value;
1386             }
1387             }
1388             }
1389            
1390             my $retval;
1391             if(defined $ci) {
1392             $retval=DMTF::CIM::Instance->new(parent=>$self, class=>$ci->{DATA}, values=>$ret->{VALUES});
1393             }
1394             else {
1395             $retval=DMTF::CIM::Instance->new(parent=>$self, class=>$ret->{DATA}, values=>$ret->{VALUES});
1396             }
1397             return $retval;
1398             }
1399            
1400             sub _checkfault
1401             {
1402             my $self=shift;
1403             my $xml=shift;
1404            
1405             my $fault=$xml->first_child('s:Body')->first_child('s:Fault');
1406             if(defined $fault) {
1407             my $value;
1408             my $sc_val;
1409             my $code=$fault->first_child('s:Code');
1410            
1411             if(defined $code) {
1412             $value=$code->first_child('s:Value')->text;
1413             if(defined $code->first_child('s:Subcode')
1414             && defined $code->first_child('s:Subcode')->first_child('s:Value')) {
1415             $sc_val=$code->first_child('s:Subcode')->first_child('s:Value')->text;
1416             }
1417             }
1418             my $reason=$fault->first_child('s:Reason')->first_child('s:Text')->text;
1419             my $detail;
1420             if(defined $fault->first_child('s:Detail')
1421             && defined $fault->first_child('s:Detail')->first_child('w:FaultDetail')) {
1422             $detail=$fault->first_child('s:Detail')->first_child('w:FaultDetail')->text;
1423             }
1424            
1425             my $errstr=$value;
1426             $errstr .= ' (' if(defined $sc_val && $sc_val ne '' && defined $errstr && $errstr ne '');
1427             $errstr .= "$sc_val" if(defined $sc_val && $sc_val ne '');
1428             $errstr .= ') ' if(defined $sc_val && $sc_val ne '' && defined $value && $value ne '');
1429             $errstr .= "\n" if(defined $reason && $reason ne '' && defined $errstr && $errstr ne '');
1430             $errstr .= "$reason " if(defined $reason && $reason ne '');
1431             $errstr .= "\n($detail)" if(defined $detail && $detail ne '');
1432             carp "Fault encountered: $errstr\n";
1433             return 1;
1434             }
1435             return 0;
1436             }
1437            
1438             1; # Magic true value required at end of module
1439             __END__