File Coverage

blib/lib/ODO/Ontology/RDFS.pm
Criterion Covered Total %
statement 27 377 7.1
branch 0 130 0.0
condition 0 59 0.0
subroutine 9 33 27.2
pod 22 22 100.0
total 58 621 9.3


line stmt bran cond sub pod time code
1             #
2             # Copyright (c) 2005-2006 IBM Corporation.
3             #
4             # All rights reserved. This program and the accompanying materials
5             # are made available under the terms of the Eclipse Public License v1.0
6             # which accompanies this distribution, and is available at
7             # http://www.eclipse.org/legal/epl-v10.html
8             #
9             # File: $Source: /var/lib/cvs/ODO/lib/ODO/Ontology/RDFS.pm,v $
10             # Created by: Stephen Evanchik( evanchik@us.ibm.com )
11             # Created on: 03/02/2005
12             # Revision: $Id: RDFS.pm,v 1.54 2009-11-25 17:58:25 ubuntu Exp $
13             #
14             # Contributors:
15             # IBM Corporation - initial API and implementation
16             #
17             package ODO::Ontology::RDFS;
18              
19 2     2   2871 use strict;
  2         6  
  2         75  
20 2     2   11 use warnings;
  2         4  
  2         89  
21              
22 2     2   12 use Data::Dumper;
  2         4  
  2         124  
23              
24 2     2   13 use ODO::Statement;
  2         4  
  2         89  
25              
26 2     2   1324 use ODO::Ontology::RDFS::PerlEntity;
  2         7  
  2         328  
27 2     2   20 use ODO::Ontology::RDFS::Vocabulary;
  2         5  
  2         4272  
28 2     2   7152 use ODO::Ontology::RDFS::ObjectWriter;
  2         6  
  2         69  
29              
30 2     2   12 use base qw/ODO::Ontology/;
  2         4  
  2         1013  
31              
32 2     2   16 use vars qw /$VERSION/;
  2         4  
  2         16142  
33             $VERSION = sprintf "%d.%02d", q$Revision: 1.54 $ =~ /: (\d+)\.(\d+)/;
34              
35             our $BASECLASS_URI = 'http://ibm-slrp.sourceforge.net/uris/odo/#base_class';
36             our $BOOTSTRAPPED_TYPE = "(?:${ODO::Ontology::RDFS::Vocabulary::RDF}|${ODO::Ontology::RDFS::Vocabulary::RDFS})";
37              
38             our $CLASS_SYMTAB_URI = 'http://ibm-slrp.sourceforge.net/uris/odo/2007/01/rdfs/classes/';
39             our $PROPERTY_SYMTAB_URI = 'http://ibm-slrp.sourceforge.net/uris/odo/2007/01/rdfs/properties/';
40              
41             our $CLASS_IMPL_SYMTAB_URI = 'http://ibm-slrp.sourceforge.net/uris/odo/2007/01/rdfs/classes/impls';
42             our $PROPERTY_IMPL_SYMTAB_URI = 'http://ibm-slrp.sourceforge.net/uris/odo/2007/01/rdfs/properties/impls';
43             our $PROPERTY_ACC_IMPL_SYMTAB_URI = 'http://ibm-slrp.sourceforge.net/uris/odo/2007/01/rdfs/properties/accessors/impls';
44              
45             __PACKAGE__->mk_accessors(qw/property_namespace class_impls class_property_accessor_impls property_impls/);
46              
47             =head1 NAME
48              
49             ODO::Ontology::RDFS - RDFS to Perl code generator frontend.
50              
51             =head1 SYNOPSIS
52              
53             use ODO::Node;
54             use ODO::Graph::Simple;
55             use ODO::Ontology::RDFS;
56            
57             my $schema = ODO::Graph::Simple->Memory(name=> 'Schema Model');
58             my $source_data = ODO::Graph::Simple->Memory(name=> 'Source Data model');
59            
60             my ($statements, $imports) = ODO::Parser::XML->parse_file('/path/to/a/file.xml');
61             $schema->add($statements);
62            
63             print STDERR "Generating Perl schema\n";
64             my $SCHEMA = ODO::Ontology::RDFS->new(graph=> $source_data, schema_graph=> $schema);
65            
66             # $SCHEMA is_a ODO::Ontology::RDFS::PerlEntity
67             my $resource = RDFS::Resource->new(ODO::Node::Resource->new('http://tempuri.org/someResource'), $source_data);
68              
69             my $klass = RDFS::Class->new(ODO::Node::Resource->new('http://tempuri.org/someClassDefinition'), $source_data);
70            
71             =head1 DESCRIPTION
72              
73             =head1 CONSTRUCTOR
74              
75             =head1 METHODS
76              
77             =over
78              
79             =item define_schema_objects( )
80              
81             Get all class data:
82              
83             1. Get all subjects with type Class
84             - the name of the class is provided by the label
85             - the comment is a description of the class
86             - the definition is a URI where you can find the actual definition of the the object (definition and isDefinedBy should be methods)
87             - record any explicit subclasses with the subClassOf triple
88             2. Get all properties with their domain being in the class from step 1
89             - Access them with a general property( $name, [ $value ] ) method ?
90             3. Build objects
91              
92             =cut
93              
94             sub define_schema_objects {
95 0     0 1   my $self = shift;
96            
97 0           my $class_list = $self->get_class_uris();
98 0           my $property_list = $self->get_property_uris();
99              
100 0           $self->forward_declare_classes( $class_list );
101 0           $self->foward_declare_properties( $property_list );
102              
103 0           $self->define_class_objects( $class_list );
104 0           $self->define_property_objects( $property_list );
105             }
106              
107              
108             =item define_class_objects( )
109              
110             =cut
111              
112             sub define_class_objects {
113 0     0 1   my ($self, $class_uri_list) = @_;
114            
115             # The components of a Perl class object from an RDFS #Class type are the following:
116             # 1. Perl Package
117             # 2. Constructor
118             # 3. Property container
119             #
120 0           foreach my $rdfs_class (@{ $class_uri_list }) {
  0            
121            
122 0           my $class_uri = $rdfs_class->value();
123            
124             next # skip already defined classes
125 0 0         if($self->get_symtab_entry($CLASS_IMPL_SYMTAB_URI, $class_uri));
126            
127 0           my $constructorData = $self->get_constructor_data($class_uri);
128            
129 0 0         throw ODO::Exception::Runtime(error=> "Could not get constructor data for class URI: $class_uri")
130             unless($constructorData);
131            
132             # Add the object's URI to the contstructor's data
133 0           $constructorData->{'URI'} = $class_uri;
134            
135            
136 0           my $perl_class_data = $self->get_class_data($class_uri);
137              
138 0 0         throw ODO::Exception::Runtime(error=> "Could not get class data for class URI: $class_uri")
139             unless($perl_class_data);
140            
141             #
142             # Now make the objects that will eventually serialze to
143             # the textual representation
144             #
145            
146 0           my $constructor = ODO::Ontology::RDFS::ObjectWriter::Constructor->new(%{ $constructorData });
  0            
147 0 0         throw ODO::Exception::Runtime(error=> "Could not create ODO::Ontology::RDFS::ObjectWriter::Constructor object for class URI: $class_uri")
148             unless(UNIVERSAL::isa($constructor, 'ODO::Ontology::RDFS::ObjectWriter::Constructor'));
149            
150 0           $perl_class_data->{'constructor'} = $constructor;
151            
152 0           my $package = ODO::Ontology::RDFS::ObjectWriter::Package->new(%{ $perl_class_data } );
  0            
153 0 0         throw ODO::Exception::Runtime(error=> "Could not create class definition for class URI: $class_uri")
154             unless(UNIVERSAL::isa($package, 'ODO::Ontology::RDFS::ObjectWriter::Package'));
155            
156 0           $self->add_symtab_entry($CLASS_IMPL_SYMTAB_URI, $class_uri, $package);
157            
158             # Remove the base_class URI because it does not have an associated
159             # PropertiesContainer
160 0 0 0       delete($perl_class_data->{'inheritanceMap'}->{ $BASECLASS_URI })
161             if( exists($perl_class_data->{'inheritanceMap'})
162             && exists($perl_class_data->{'inheritanceMap'}->{ $BASECLASS_URI })) ;
163            
164 0           my $superProperties = {};
165 0           foreach my $sp (keys(%{ $perl_class_data->{'inheritanceMap'} })) {
  0            
166 0 0         unless (defined $perl_class_data->{'inheritanceMap'}->{$sp}) {
167 0           delete $perl_class_data->{'inheritanceMap'}->{$sp};
168 0           next;
169             }
170 0           my $cn = $self->make_perl_package_name($self->get_symtab_entry($CLASS_SYMTAB_URI, $sp), 'PropertiesContainer');
171 0 0         if ($cn eq 'PropertiesContainer') {
172 0           $cn = "ODO::RDFS::Container";
173             }
174 0           $superProperties->{ $cn } = $cn;
175             }
176            
177 0           my $propertyContainerData = {
178             packageName=> $package->packageName(),
179             inheritanceMap=> $superProperties,
180             properties=> $package->properties(),
181             };
182            
183             # We can't have a blank ISA
184 0 0         if(scalar(values(%{ $superProperties })) > 0) {
  0            
185 0           $propertyContainerData->{'ISA'} = [ values(%{ $superProperties }) ];
  0            
186             }
187            
188 0           my $classPropertyContainer = ODO::Ontology::RDFS::ObjectWriter::PropertiesContainer->new(%{ $propertyContainerData });
  0            
189 0           $self->add_symtab_entry($PROPERTY_ACC_IMPL_SYMTAB_URI, $class_uri, $classPropertyContainer);
190             }
191             }
192              
193              
194             =item define_property_objects( )
195              
196             =cut
197              
198             sub define_property_objects {
199 0     0 1   my ($self, $property_uri_list) = @_;
200            
201 0           foreach my $property (@{ $property_uri_list }) {
  0            
202            
203 0           my $property_uri = $property->value();
204            
205             next # skip previously defined properties
206 0 0         if($self->get_symtab_entry($PROPERTY_IMPL_SYMTAB_URI, $property_uri));
207              
208             #
209             # CREATE A PROPERTY
210             #
211             # Gather and format all of the necessary data to create
212             # the definition for the Property named by $property_uri
213             #
214            
215 0           my $constructorData = $self->get_constructor_data($property_uri);
216 0 0         throw ODO::Exception::Runtime(error=> "Could not get constructor data for property URI: $property_uri")
217             unless(UNIVERSAL::isa($constructorData, 'HASH'));
218            
219 0           $constructorData->{'URI'} = $property_uri;
220            
221            
222 0           my $propertyData = $self->get_property_data($property_uri);
223 0 0         throw ODO::Exception::Runtime(error=> "Could not get property data for: $property_uri")
224             unless(UNIVERSAL::isa($propertyData, 'HASH'));
225            
226            
227             # High level objects now
228            
229            
230 0           my $constructor = ODO::Ontology::RDFS::ObjectWriter::Constructor->new(%{ $constructorData });
  0            
231 0 0         throw ODO::Exception::Runtime(error=> "Could not create ODO::Ontology::RDFS::ObjectWriter::Constructor object for property URI: $property_uri")
232             unless(UNIVERSAL::isa($constructor, 'ODO::Ontology::RDFS::ObjectWriter::Constructor'));
233            
234 0           $propertyData->{'constructor'} = $constructor;
235            
236            
237 0           my $package = ODO::Ontology::RDFS::ObjectWriter::Package->new( %{ $propertyData } );
  0            
238 0 0         throw ODO::Exception::Runtime(error=> "Could not create Property definition for: $property_uri")
239             unless($package);
240            
241 0           $self->add_symtab_entry($PROPERTY_IMPL_SYMTAB_URI, $property_uri, $package);
242            
243            
244             #
245             # CREATE A CONTAINER
246             #
247             # Now, gather and format all of the necessary data to create the
248             # PropertiesContainer that holds all of the propeties for a the
249             # URI, $property_uri
250             #
251            
252             #
253             # We need to create an inheritance path that is similar to the
254             # rdf:Property itself except that this path is for its PropertiesContainer
255             # object.
256             #
257            
258 0           my $superProperties = {};
259 0           foreach my $sp (keys(%{ $propertyData->{'inheritanceMap'} })) {
  0            
260 0 0         unless (defined $propertyData->{'inheritanceMap'}->{$sp}) {
261 0           delete $propertyData->{'inheritanceMap'}->{$sp};
262 0           next;
263             }
264             # FIXME: Properties that directly inherit from rdf:Property must use getClassName instead
265             # because rdf:Property isa rdf:Class and was or will be defined as such
266 0           my $propertyName = $self->get_symtab_entry($CLASS_SYMTAB_URI, $sp) ;
267 0 0 0       if(0 && $sp eq $ODO::Ontology::RDFS::Vocabulary::Property->value()
    0 0        
268             || $sp eq $ODO::Ontology::RDFS::Vocabulary::Class->value()
269             || $sp eq $ODO::Ontology::RDFS::Vocabulary::Literal->value()
270             || $sp eq $ODO::Ontology::RDFS::Vocabulary::Resource->value()) {
271 0           $propertyName = $self->get_symtab_entry($CLASS_SYMTAB_URI, $sp);
272             }
273             elsif(!$propertyName) {
274 0           $propertyName = $self->get_symtab_entry($PROPERTY_SYMTAB_URI, $sp);
275             }
276            
277             # unless($propertyName) {
278             # die("Could not get property name for URI: $sp while creating property: $property_uri");
279             # }
280            
281 0           my $cn = $self->make_perl_package_name($propertyName, 'PropertiesContainer');
282 0           $superProperties->{ $cn } = $cn;
283             }
284              
285 0           my $propertyContainerData = {
286             packageName=> $package->packageName(),
287             properties=> $package->properties(),
288             };
289              
290             # We can't have a blank ISA
291 0 0         if(scalar(values(%{ $superProperties })) > 0) {
  0            
292 0           $propertyContainerData->{'ISA'} = [ values(%{ $superProperties }) ];
  0            
293             }
294              
295 0           my $propertyContainer = ODO::Ontology::RDFS::ObjectWriter::PropertiesContainer->new(%{ $propertyContainerData });
  0            
296 0 0         throw ODO::Exception::Runtime(error=> "Could not create PropertyContainer definition for: $property_uri")
297             unless($propertyContainer);
298            
299 0           $self->add_symtab_entry($PROPERTY_ACC_IMPL_SYMTAB_URI, $property_uri, $propertyContainer);
300              
301             }
302             }
303              
304              
305             =item eval_schema_objects( )
306              
307             =cut
308              
309             sub eval_schema_objects {
310 0     0 1   my $self = shift;
311            
312 0           my %evald;
313            
314 0           my @uri_list = keys( %{ $self->get_symbol_table($CLASS_SYMTAB_URI)->{'uris'} } );
  0            
315 0           foreach my $uri (@uri_list) {
316             next
317 0 0 0       unless($self->get_symtab_entry($CLASS_IMPL_SYMTAB_URI, $uri)
      0        
318             && !exists($evald{$uri})
319             && !defined($evald{$uri}));
320 0 0         throw ODO::Exception::Runtime(error=> "Failed to evaluate object: $uri")
321             unless($self->eval_object($uri, \%evald, $CLASS_IMPL_SYMTAB_URI));
322             }
323            
324 0           @uri_list = keys( %{ $self->get_symbol_table($PROPERTY_SYMTAB_URI)->{'uris'} } );
  0            
325              
326 0           foreach my $uri (@uri_list) {
327            
328             next
329 0 0 0       unless($self->get_symtab_entry($PROPERTY_IMPL_SYMTAB_URI, $uri)
      0        
330             && !exists($evald{$uri})
331             && !defined($evald{$uri}));
332            
333 0 0         throw ODO::Exception::Runtime(error=> "Failed to evaluate object: $uri")
334             unless($self->eval_object($uri, \%evald, $PROPERTY_IMPL_SYMTAB_URI));
335             }
336             }
337              
338              
339             =item eval_object( )
340              
341             =cut
342              
343             sub eval_object {
344 0     0 1   my ($self, $uri, $evald_hash, $impl_source) = @_;
345            
346 0           my $isa = $self->get_symtab_entry($impl_source, $uri)->inheritanceMap();
347            
348 0 0         if($isa) {
349 0           my %parents = %{ $isa };
  0            
350            
351 0           foreach my $p_uri (keys(%parents)) {
352            
353             next # Ignore already eval'd objects
354 0 0 0       if( !$self->get_symtab_entry($CLASS_IMPL_SYMTAB_URI, $p_uri)
      0        
355             || (exists($evald_hash->{$p_uri}) && defined($evald_hash->{$p_uri})) );
356            
357 0 0         throw ODO::Exception::Runtime(error=> "Failed to evaluate parent object: $p_uri for URI: $uri")
358             unless($self->eval_object($p_uri, $evald_hash, $impl_source));
359             }
360             }
361 0           eval ($self->get_symtab_entry($impl_source, $uri)->serialize());
362 0 0         throw ODO::Exception::Runtime(error=> "Failed in evaluation for object defined by: $uri -> $@")
363             if($@);
364            
365 0           eval ($self->get_symtab_entry($PROPERTY_ACC_IMPL_SYMTAB_URI, $uri)->serialize());
366 0 0         throw ODO::Exception::Runtime(error=> "Failed in evaluation for PropertyContainer object defined by: $uri -> $@")
367             if($@);
368            
369 0           $evald_hash->{$uri} = 1;
370            
371 0           return 1;
372             }
373              
374              
375             =item getObjectProperties( $objectURI )
376              
377             Finding properties of a particular class means finding all triples that
378             have the class's subject URI and the form
379              
380             =cut
381              
382             sub getObjectProperties {
383 0     0 1   my $self = shift;
384            
385 0           my $objectURI = shift;
386            
387 0           my $property_uris = $self->getPropertiesInDomain($objectURI);
388            
389             return undef
390 0 0         unless(UNIVERSAL::isa($property_uris, 'ARRAY'));
391            
392 0           my @property_list;
393            
394             # TODO: Don't need to have two arrays here just one is enough
395 0           foreach my $p (@{ $property_uris }) {
  0            
396            
397 0           my $property_uri = $p->value();
398            
399 0           my $name = $self->get_symtab_entry($PROPERTY_SYMTAB_URI, $property_uri );
400            
401             # Duplicate properties mean that the property is used in multiple Classes
402             # which is why we don't check the return value of add_property_name.
403 0 0         throw ODO::Ontology::DuplicatePropertyException("Could not find property name for URI: $property_uri")
404             unless($name);
405            
406 0           my $property = {
407             objectURI=> $property_uri,
408             packageName=> $name,
409             shortName=> $name,
410             };
411            
412 0 0         if($name =~ /.*\:\:(.*)$/) {
413 0           $property->{'shortName'} = $1;
414             }
415            
416 0           push @property_list, $property;
417             }
418            
419 0           return \@property_list;
420             }
421              
422              
423             =item get_constructor_data( $uri )
424              
425             =cut
426              
427             sub get_constructor_data {
428 0     0 1   my ($self, $object_uri) = @_;
429            
430 0   0       my $class_name = ($self->get_symtab_entry($CLASS_SYMTAB_URI, $object_uri) || $self->get_symtab_entry($PROPERTY_SYMTAB_URI, $object_uri));
431 0           my $property_container_package = $self->make_perl_package_name($class_name, 'PropertiesContainer');
432            
433 0           my $schema_uri = $self->getSchemaData($object_uri, $ODO::Ontology::RDFS::Vocabulary::isDefinedBy);
434 0           $schema_uri = join('', @{ $schema_uri });
  0            
435            
436 0           my $description = $self->getSchemaData($object_uri, $ODO::Ontology::RDFS::Vocabulary::comment);
437 0           $description = $self->__make_perl_string( join('', @{ $description } ) );
  0            
438              
439 0   0       my $object_properties = ($self->getObjectProperties($object_uri) || []);
440            
441             return {
442 0           schemaURI=> $schema_uri,
443             description=> $description,
444             properties=> $object_properties,
445             queryString=> "(?subj, rdf:type, <$object_uri>)",
446             propertyContainerName=> $property_container_package,
447             };
448             }
449              
450              
451             =item getSchemaData( $schemaObject, $property )
452              
453             =cut
454              
455             sub getSchemaData {
456 0     0 1   my ($self, $schemaObject, $property) = @_;
457            
458 0 0         $schemaObject = ODO::Node::Resource->new( $schemaObject )
459             unless(UNIVERSAL::isa($schemaObject, 'ODO::Node::Resource'));
460            
461 0 0         $property = ODO::Node::Resource->new( $property )
462             unless(UNIVERSAL::isa($property, 'ODO::Node::Resource'));
463            
464 0           my $query = ODO::Query::Simple->new(s=> $schemaObject, p=> $property, o=> undef);
465 0           my @results = map { $_->o()->value() } @{ $self->schema_graph()->query($query)->results() };
  0            
  0            
466 0           return \@results;
467             }
468              
469              
470             =item get_class_data( $uri )
471              
472             =cut
473              
474             sub get_class_data {
475 0     0 1   my ($self, $class_uri) = @_;
476 0           my $perl_class_data = {
477             objectURI=> $class_uri,
478             packageName=> $self->get_symtab_entry($CLASS_SYMTAB_URI, $class_uri),
479             useModules=> [ 'ODO', 'ODO::Query::Simple', 'ODO::Statement::Group', 'ODO::Ontology::RDFS::BaseClass' ],
480             variables=> [],
481             };
482            
483             # FIXME: Does this comment still make sense?
484             # I believe that since there are instance requirements for the subClassOf and subPropertyOf
485             # properties, a rdf:Property can't contain both properties; the same being true for
486             # rdfs:Class definitions.
487 0           my $subObjects = $self->getSchemaData($class_uri, $ODO::Ontology::RDFS::Vocabulary::subClassOf);
488              
489 0 0         if(scalar(@{ $subObjects }) > 0) {
  0 0          
490              
491 0           $perl_class_data->{'inheritanceMap'} = {};
492            
493 0           while(@{ $subObjects }) {
  0            
494 0           my $sc = shift @{ $subObjects };
  0            
495 0           $perl_class_data->{'inheritanceMap'}->{ $sc } = $self->get_symtab_entry($CLASS_SYMTAB_URI, $sc);
496 0 0         unless (defined($perl_class_data->{'inheritanceMap'}->{ $sc })) {
497 0           delete $perl_class_data->{'inheritanceMap'}->{ $sc };
498 0           next;
499             }
500             # The base class should be included in the 'use ...' section
501             # of the package definition
502 0 0         push @{ $perl_class_data->{'useModules'} }, $self->get_symtab_entry($CLASS_SYMTAB_URI, $sc)
  0            
503             if($sc eq $BASECLASS_URI);
504             }
505            
506 0 0         if(scalar(values(%{ $perl_class_data->{'inheritanceMap'} })) > 0) {
  0            
507 0           $perl_class_data->{'ISA'} = [ values(%{ $perl_class_data->{'inheritanceMap'} }) ];
  0            
508 0           push @{ $perl_class_data->{'variables'} }, '@ISA';
  0            
509             }
510             }
511             elsif($class_uri !~ /$BOOTSTRAPPED_TYPE/) {
512 0           my $Class = $ODO::Ontology::RDFS::Vocabulary::Class->value();
513 0           my $ClassPackageName = $self->get_symtab_entry($CLASS_SYMTAB_URI, $Class);
514 0 0         if (defined $ClassPackageName) {
515 0           $perl_class_data->{'inheritanceMap'} = { $Class=> $ClassPackageName };
516 0           $perl_class_data->{'ISA'} = [ values(%{ $perl_class_data->{'inheritanceMap'} }) ];
  0            
517 0           push @{ $perl_class_data->{'variables'} }, '@ISA';
  0            
518             } else {
519 0           $perl_class_data->{'inheritanceMap'} = { $Class=> "ODO::Ontology::RDFS::BaseClass"};
520 0           $perl_class_data->{'ISA'} = [ values(%{ $perl_class_data->{'inheritanceMap'} }) ];
  0            
521 0           push @{ $perl_class_data->{'variables'} }, '@ISA';
  0            
522             }
523             }
524 0           return $perl_class_data;
525             }
526              
527              
528             =item get_property_data( $uri )
529              
530             =cut
531              
532             sub get_property_data {
533 0     0 1   my ($self, $uri) = @_;
534            
535 0           my $propertyData = {
536             objectURI=> $uri,
537             packageName=> $self->get_symtab_entry($PROPERTY_SYMTAB_URI, $uri),
538             useModules=> [ 'ODO', 'ODO::Query::Simple', 'ODO::Statement::Group', 'ODO::RDFS::Container' ],
539             variables=> []
540             };
541            
542 0           my $subObjects = $self->getSchemaData($uri, $ODO::Ontology::RDFS::Vocabulary::subPropertyOf);
543              
544 0           $propertyData->{'inheritanceMap'} = {};
545            
546 0 0         if(scalar(@{ $subObjects }) > 0) {
  0 0          
547            
548 0           while(@{ $subObjects }) {
  0            
549 0           my $sp = shift @{ $subObjects };
  0            
550 0           $propertyData->{'inheritanceMap'}->{ $sp } = $self->get_symtab_entry($PROPERTY_SYMTAB_URI, $sp);
551 0 0         unless (defined($propertyData->{'inheritanceMap'}->{ $sp })) {
552 0           delete $propertyData->{'inheritanceMap'}->{ $sp };
553 0           next;
554             }
555             }
556              
557             }
558             elsif($propertyData->{'objectURI'} ne $ODO::Ontology::RDFS::Vocabulary::Property) {
559              
560 0           my $Property = $ODO::Ontology::RDFS::Vocabulary::Property->value();
561 0           my $PropertyPackageName = $self->get_symtab_entry($CLASS_SYMTAB_URI, $Property);
562 0 0         if (defined $PropertyPackageName) {
563 0           $propertyData->{'inheritanceMap'} = { $Property=> $PropertyPackageName };
564             }
565             }
566             else {
567             }
568              
569 0           my $range = $self->getSchemaData($uri, $ODO::Ontology::RDFS::Vocabulary::range);
570            
571 0 0         if(scalar(@{ $range }) > 0) {
  0            
572            
573 0           $propertyData->{'range'} = {};
574            
575 0           while(@{ $range }) {
  0            
576              
577 0           my $sp = shift @{ $range };
  0            
578            
579 0   0       my $name = ($self->get_symtab_entry($CLASS_SYMTAB_URI, $sp) || $self->get_symtab_entry($PROPERTY_SYMTAB_URI, $sp)) ;
580            
581             #
582             # The URI defined in the rdfs:range property may not be
583             # defined by the schema (hopefully it will though)
584             #
585 0 0         unless($name) {
586            
587 0 0         if($self->isClassURI($sp)) {
    0          
588 0           $name = $self->uri_to_package_name($sp)
589             }
590             elsif($self->isPropertyURI($sp)) {
591 0           $name = $self->uri_to_property_package_name($sp)
592             }
593             else {
594 0           warn "rdfs:range points to a URI that is not defined as a rdfs:Class or rdf:Property - $sp\n";
595            
596 0           $name = $self->uri_to_package_name($sp);
597             }
598             }
599            
600             # Record the range information in its own hash to preserve the data
601             # trail
602             # AND
603             # Record the range information in the inheritance structure so the
604             # proper inheritance tree is constructed
605 0           $propertyData->{'range'}->{ $sp } = $name;
606 0           $propertyData->{'inheritanceMap'}->{ $sp } = $name;
607             }
608             }
609 0           push @{ $propertyData->{'variables'} }, '@ISA';
  0            
610             # TODO this might not be necessary
611 0 0         $propertyData->{'ISA'} = [ values(%{ $propertyData->{'inheritanceMap'} }) ] if scalar(values(%{ $propertyData->{'inheritanceMap'} }));
  0            
  0            
612 0 0         $propertyData->{'ISA'} = ['ODO::RDFS::Container'] unless scalar(values(%{ $propertyData->{'inheritanceMap'} }));
  0            
613            
614 0           return $propertyData;
615             }
616              
617              
618             =item get_rdfs_label( $uri )
619              
620             =cut
621              
622             sub get_rdfs_label {
623 0     0 1   my ($self, $owner_uri) = @_;
624            
625 0           my $p = $ODO::Ontology::RDFS::Vocabulary::label;
626              
627 0 0         $owner_uri = ODO::Node::Resource->new( $owner_uri )
628             unless(UNIVERSAL::isa($owner_uri, 'ODO::Node::Resource'));
629            
630 0           my $query = ODO::Query::Simple->new(s=> undef, p=> $owner_uri, o=> $p);
631 0           my $results = $self->schema_graph()->query($query)->results();
632            
633             return undef
634 0 0 0       unless(ref $results eq 'ARRAY' && scalar(@{ $results }) > 0);
  0            
635            
636 0           return $self->__make_perl_string($results->[0]->value());
637             }
638              
639              
640             =item isPropertyURI( $uri )
641              
642             =cut
643              
644             sub isPropertyURI {
645 0     0 1   my ($self, $uri) = @_;
646              
647 0           my $sourceGraph = $self->schema_graph();
648              
649 0 0         $uri = ODO::Node::Resource->new( $uri )
650             unless(UNIVERSAL::isa($uri, 'ODO::Node::Resource'));
651              
652 0           my $p = ODO::Node::Resource->new($ODO::Ontology::RDFS::Vocabulary::type);
653 0           my $o = ODO::Node::Resource->new($ODO::Ontology::RDFS::Vocabulary::Property);
654            
655 0           my $match = ODO::Query::Simple->new($uri, $p, $o);
656            
657 0           my $results = $sourceGraph->query($match)->results();
658            
659 0           return 1
660 0 0 0       if(UNIVERSAL::isa($results, 'ARRAY') && scalar(@{ $results }) > 0 );
661            
662             # Test if its a subPropertyOf
663 0           $p = ODO::Node::Resource->new($ODO::Ontology::RDFS::Vocabulary::subPropertyOf);
664            
665 0           $results = $sourceGraph->query($match)->results();
666            
667 0           return 1
668 0 0 0       if(UNIVERSAL::isa($results, 'ARRAY') && scalar(@{ $results }) > 0 );
669            
670 0           return 0;
671             }
672              
673              
674             =item isClassURI( $uri )
675              
676             =cut
677              
678             sub isClassURI {
679 0     0 1   my ($self, $uri) = @_;
680              
681 0           my $sourceGraph = $self->schema_graph();
682              
683 0 0         $uri = ODO::Node::Resource->new( $uri )
684             unless(UNIVERSAL::isa($uri, 'ODO::Node::Resource'));
685              
686 0           my $p = $ODO::Ontology::RDFS::Vocabulary::type;
687 0           my $o = $ODO::Ontology::RDFS::Vocabulary::Class;
688            
689 0           my $match = ODO::Query::Simple->new($uri, $p, $o);
690              
691 0           my $results = $sourceGraph->query($match)->results();
692            
693 0           return 1
694 0 0 0       if(UNIVERSAL::isa($results, 'ARRAY') && scalar(@{ $results }) > 0 );
695              
696             # Test if its a subClassOf
697 0           $p = $ODO::Ontology::RDFS::Vocabulary::subClassOf;
698            
699 0           $results = $sourceGraph->query($match)->results();
700            
701 0           return 1
702 0 0 0       if(UNIVERSAL::isa($results, 'ARRAY') && scalar(@{ $results }) > 0 );
703            
704 0           return 0;
705             }
706              
707              
708             =item forward_declare_classes( $class_uri_list )
709              
710             =cut
711              
712             sub forward_declare_classes {
713 0     0 1   my ($self, $class_uri_list) = @_;
714            
715 0           foreach my $class (@{ $class_uri_list }) {
  0            
716              
717 0           my $class_uri = $class->value();
718            
719             next
720 0 0         if($self->get_symtab_entry($CLASS_SYMTAB_URI, $class_uri));
721            
722 0           my $package_name = $self->uri_to_package_name($class_uri);
723 0           $self->add_symtab_entry($CLASS_SYMTAB_URI, $class_uri, $package_name);
724             }
725             }
726              
727              
728             =item foward_declare_properties( $property_list )
729              
730             =cut
731              
732             sub foward_declare_properties {
733 0     0 1   my ($self, $property_uri_list) = @_;
734              
735 0           foreach my $property (@{ $property_uri_list }) {
  0            
736              
737 0           my $property_uri = $property->value();
738            
739             next
740 0 0         if($self->get_symtab_entry($PROPERTY_SYMTAB_URI, $property_uri));
741            
742 0           my $package_name = $self->uri_to_property_package_name($property_uri);
743 0           $self->add_symtab_entry($PROPERTY_SYMTAB_URI, $property_uri, $package_name);
744             }
745             }
746              
747              
748             =item get_class_uris( )
749              
750             Finds all of the triples that fit the form: (subject, , )
751             Semantically: all of the RDFS classes in the graph.
752              
753             =cut
754              
755             sub get_class_uris {
756 0     0 1   my $self = shift;
757              
758 0           my $p = $ODO::Ontology::RDFS::Vocabulary::type;
759 0           my $o = $ODO::Ontology::RDFS::Vocabulary::Class;
760            
761 0           my $query = ODO::Query::Simple->new(s=> undef, p=> $p, o=> $o);
762 0           my @subjects = map { $_->s(); } @{ $self->schema_graph()->query($query)->results() };
  0            
  0            
763 0           return \@subjects;
764             }
765              
766              
767             =item get_property_uris( )
768              
769             Finds all triples that fit the form: (, , ).
770             Semantically: Find all of the rdf:Properties in this graph.
771              
772             =cut
773              
774             sub get_property_uris {
775 0     0 1   my $self = shift;
776              
777 0           my $p = $ODO::Ontology::RDFS::Vocabulary::type;
778 0           my $o = $ODO::Ontology::RDFS::Vocabulary::Property;
779              
780 0           my $query = ODO::Query::Simple->new(s=> undef, p=> $p, o=> $o);
781            
782 0           my @subjects = map { $_->s() } @{ $self->schema_graph()->query($query)->results() };
  0            
  0            
783 0           return \@subjects;
784             }
785              
786              
787             =item getPropertiesInDomain( $graph, $owner_uri )
788              
789             Finds all of the triples that fit the form: (, , )
790             Semantically: All subjects that have a domain restriction that is the owner class. These
791             should be
792              
793             =cut
794              
795             sub getPropertiesInDomain {
796 0     0 1   my ($self, $owner_uri) = @_;
797            
798 0 0         $owner_uri = ODO::Node::Resource->new( $owner_uri )
799             unless(UNIVERSAL::isa($owner_uri, 'ODO::Node::Resource'));
800            
801 0           my $domain = $ODO::Ontology::RDFS::Vocabulary::domain;
802            
803 0           my $query = ODO::Query::Simple->new(s=> undef, p=> $domain, o=> $owner_uri);
804            
805 0           my @subjects = map { $_->s() } @{ $self->schema_graph()->query($query)->results() };
  0            
  0            
806 0           return \@subjects;
807             }
808              
809              
810             =item __uri_to_perl_identifier($uri)
811              
812             =cut
813              
814             sub __uri_to_perl_identifier {
815 0     0     my ($self, $uri) = @_;
816            
817             # We need to find a good name for the URI given.. check the following 3 sources
818             # in the following preferred order
819             # 1. Find the URI's name and then try to add it in to the class name list,
820             # 2.if it fails then we have a duplicate class name which is bad...
821             # 3. The URI provides another method to get a name for a class
822 0   0       my $name = (
823             ODO::Ontology::RDFS::Vocabulary->uri_to_name($uri)
824             || $self->get_rdfs_label($uri)
825             || $self->__parse_uri_for_name($uri)
826             );
827            
828 0           $name = $self->__make_perl_identifier( $name );
829            
830 0 0         $name = $self->make_perl_package_name($self->schema_name(), $name)
831             if($self->schema_name());
832              
833 0           return $name;
834             }
835              
836              
837             =item uri_to_property_package_name( $uri )
838              
839             =cut
840              
841             sub uri_to_property_package_name {
842 0     0 1   my ($self, $uri) = @_;
843 0           my $name = $self->__uri_to_perl_identifier($uri);
844 0           return $self->make_perl_package_name($self->property_namespace(), $name);
845             }
846              
847              
848             =item uri_to_package_name( $uri )
849              
850             =cut
851              
852             sub uri_to_package_name {
853 0     0 1   my ($self, $uri) = @_;
854 0           my $name = $self->__uri_to_perl_identifier($uri);
855 0           return $self->make_perl_package_name($self->base_namespace(), $name);
856             }
857              
858              
859             =item print_perl( )
860              
861             =cut
862              
863             sub print_perl {
864 0     0 1   my ($self, $printRDFS, $fh) = @_;
865              
866 0 0         $fh = \*STDOUT
867             unless($fh);
868            
869 0           my @impls = keys( %{ $self->get_symbol_table($CLASS_IMPL_SYMTAB_URI)->{'uris'} });
  0            
870            
871 0           foreach my $ci (@impls) {
872             next
873 0 0 0       if( !$printRDFS
874             && ODO::Ontology::RDFS::Vocabulary->uri_to_name($ci) );
875            
876 0           my $class = $self->get_symtab_entry($CLASS_IMPL_SYMTAB_URI, $ci );
877 0           my $property_accessor = $self->get_symtab_entry($PROPERTY_ACC_IMPL_SYMTAB_URI, $ci );
878            
879 0           print $fh $class->serialize(), "\n";
880 0           print $fh $property_accessor->serialize(), "\n";
881             }
882              
883 0           @impls = keys( %{ $self->get_symbol_table($PROPERTY_IMPL_SYMTAB_URI)->{'uris'} });
  0            
884            
885 0           foreach my $pi (@impls) {
886             next
887 0 0 0       if( !$printRDFS
888             && ODO::Ontology::RDFS::Vocabulary->uri_to_name($pi) );
889            
890 0           my $property = $self->get_symtab_entry($PROPERTY_IMPL_SYMTAB_URI, $pi);
891 0           my $property_accessor = $self->get_symtab_entry($PROPERTY_ACC_IMPL_SYMTAB_URI, $pi);
892            
893 0           print $fh $property->serialize(), "\n";
894 0           print $fh $property_accessor->serialize(), "\n";
895             }
896            
897              
898             }
899              
900              
901             =item bootstrap( )
902              
903             =cut
904              
905             sub bootstrap {
906 0     0     my $self = shift;
907            
908             # Load the RDF associated with the RDFS schema and then add the base class URI
909             # so that RDFS::Resource will have the correct inheritance structure
910 0           my $graph = ODO::Graph::Simple->Memory();
911 0           my $rdfs_schema_statements = ODO::Parser::XML->parse($ODO::Ontology::RDFS::Vocabulary::RDFS_SCHEMA_DATA);
912            
913             # TODO: Error check the parser
914            
915 0           $graph->add($rdfs_schema_statements);
916            
917             #
918 0           my $s = $ODO::Ontology::RDFS::Vocabulary::Resource;
919 0           my $p = $ODO::Ontology::RDFS::Vocabulary::subClassOf;
920 0           my $o_bc = ODO::Node::Resource->new($BASECLASS_URI);
921            
922 0           my $statement = ODO::Statement->new($s, $p, $o_bc);
923 0           $graph->add($statement);
924            
925 0           my %config = (
926             graph=> $graph,
927             schema_graph=> $graph,
928             base_class=> 'ODO::Ontology::RDFS::BaseClass',
929            
930             base_namespace=> 'RDFS',
931             property_namespace=> 'RDFS::Properties',
932             );
933            
934 0           foreach my $k (keys(%config)) {
935 0           $self->{$k} = $config{$k};
936             }
937            
938 0           $self->add_symtab_entry($CLASS_SYMTAB_URI, $BASECLASS_URI, 'ODO::Ontology::RDFS::BaseClass');
939            
940 0           $self->define_schema_objects();
941            
942             # Reset the boostrap specific state to undefined
943 0           delete $self->{'base_namespace'};
944             }
945              
946              
947             sub init {
948 0     0 1   my ($self, $config) = @_;
949 0 0         if(!UNIVERSAL::can('ODO::RDFS::Resource', 'new')) {
950             # Build the RDFS Perl code or just import
951             # already built code if available
952 0           $self->bootstrap();
953             }
954 0           $self = $self->SUPER::init($config);
955 0           $self->params($config, qw//);
956             # Class package: ::::*
957             #
958             # Property package: ::::Properties::*
959 0           my $pn = $self->make_perl_package_name($self->base_namespace(), 'Properties');
960 0           $self->property_namespace($pn);
961 0           $self->define_schema_objects();
962 0           $self->eval_schema_objects();
963            
964 0           return ODO::Ontology::RDFS::PerlEntity->new(ontology=> $self);
965             }
966              
967             =back
968              
969             =head1 COPYRIGHT
970              
971             Copyright (c) 2005-2006 IBM Corporation.
972              
973             All rights reserved. This program and the accompanying materials
974             are made available under the terms of the Eclipse Public License v1.0
975             which accompanies this distribution, and is available at
976             http://www.eclipse.org/legal/epl-v10.html
977            
978             =cut
979              
980             1;
981              
982             __END__