Bug 14939: Modularize OAI Server existing classes
[koha.git] / Koha / OAI / Server / Repository.pm
1 # Copyright Tamil s.a.r.l. 2008-2015
2 # Copyright Biblibre 2008-2015
3 #
4 # This file is part of Koha.
5 #
6 # Koha is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # Koha is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with Koha; if not, see <http://www.gnu.org/licenses>.
18
19 package Koha::OAI::Server::Repository;
20
21 use Modern::Perl;
22 use HTTP::OAI;
23 use HTTP::OAI::Repository qw/:validate/;
24
25 use base ("HTTP::OAI::Repository");
26
27 use Koha::OAI::Server::Identify;
28 use Koha::OAI::Server::ListSets;
29 use Koha::OAI::Server::ListMetadataFormats;
30 use Koha::OAI::Server::GetRecord;
31 use Koha::OAI::Server::ListRecords;
32 use Koha::OAI::Server::ListIdentifiers;
33 use XML::SAX::Writer;
34 use XML::LibXML;
35 use XML::LibXSLT;
36 use YAML::Syck qw( LoadFile );
37 use CGI qw/:standard -oldstyle_urls/;
38 use C4::Context;
39 use C4::Biblio;
40
41
42 =head1 NAME
43
44 Koha::OAI::Server::Repository - Handles OAI-PMH requests for a Koha database.
45
46 =head1 SYNOPSIS
47
48   use Koha::OAI::Server::Repository;
49
50   my $repository = Koha::OAI::Server::Repository->new();
51
52 =head1 DESCRIPTION
53
54 This object extend HTTP::OAI::Repository object.
55 It accepts OAI-PMH HTTP requests and returns result.
56
57 This OAI-PMH server can operate in a simple mode and extended one.
58
59 In simple mode, repository configuration comes entirely from Koha system
60 preferences (OAI-PMH:archiveID and OAI-PMH:MaxCount) and the server returns
61 records in marcxml or dublin core format. Dublin core records are created from
62 koha marcxml records transformed with XSLT. Used XSL file is located in koha-
63 tmpl/intranet-tmpl/prog/en/xslt directory and chosen based on marcflavour,
64 respecively MARC21slim2OAIDC.xsl for MARC21 and  MARC21slim2OAIDC.xsl for
65 UNIMARC.
66
67 In extended mode, it's possible to parameter other format than marcxml or
68 Dublin Core. A new syspref OAI-PMH:ConfFile specify a YAML configuration file
69 which list available metadata formats and XSL file used to create them from
70 marcxml records. If this syspref isn't set, Koha OAI server works in simple
71 mode. A configuration file koha-oai.conf can look like that:
72
73   ---
74   format:
75     vs:
76       metadataPrefix: vs
77       metadataNamespace: http://veryspecial.tamil.fr/vs/format-pivot/1.1/vs
78       schema: http://veryspecial.tamil.fr/vs/format-pivot/1.1/vs.xsd
79       xsl_file: /usr/local/koha/xslt/vs.xsl
80     marcxml:
81       metadataPrefix: marxml
82       metadataNamespace: http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim
83       schema: http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd
84       include_items: 1
85     oai_dc:
86       metadataPrefix: oai_dc
87       metadataNamespace: http://www.openarchives.org/OAI/2.0/oai_dc/
88       schema: http://www.openarchives.org/OAI/2.0/oai_dc.xsd
89       xsl_file: /usr/local/koha/koha-tmpl/intranet-tmpl/xslt/UNIMARCslim2OAIDC.xsl
90
91 Note de 'include_items' parameter which is the only mean to return item-level info.
92
93 =cut
94
95
96 sub new {
97     my ($class, %args) = @_;
98     my $self = $class->SUPER::new(%args);
99
100     $self->{ koha_identifier      } = C4::Context->preference("OAI-PMH:archiveID");
101     $self->{ koha_max_count       } = C4::Context->preference("OAI-PMH:MaxCount");
102     $self->{ koha_metadata_format } = ['oai_dc', 'marcxml'];
103     $self->{ koha_stylesheet      } = { }; # Build when needed
104
105     # Load configuration file if defined in OAI-PMH:ConfFile syspref
106     if ( my $file = C4::Context->preference("OAI-PMH:ConfFile") ) {
107         $self->{ conf } = LoadFile( $file );
108         my @formats = keys %{ $self->{conf}->{format} };
109         $self->{ koha_metadata_format } =  \@formats;
110     }
111
112     # Check for grammatical errors in the request
113     my @errs = validate_request( CGI::Vars() );
114
115     # Is metadataPrefix supported by the respository?
116     my $mdp = param('metadataPrefix') || '';
117     if ( $mdp && !grep { $_ eq $mdp } @{$self->{ koha_metadata_format }} ) {
118         push @errs, new HTTP::OAI::Error(
119             code    => 'cannotDisseminateFormat',
120             message => "Dissemination as '$mdp' is not supported",
121         );
122     }
123
124     my $response;
125     if ( @errs ) {
126         $response = HTTP::OAI::Response->new(
127             requestURL  => self_url(),
128             errors      => \@errs,
129         );
130     }
131     else {
132         my %attr = CGI::Vars();
133         my $verb = delete $attr{verb};
134         my $class = "Koha::OAI::Server::$verb";
135         $response = $class->new($self, %attr);
136     }
137
138     $response->set_handler( XML::SAX::Writer->new( Output => *STDOUT ) );
139     $response->generate;
140
141     bless $self, $class;
142     return $self;
143 }
144
145
146 sub get_biblio_marcxml {
147     my ($self, $biblionumber, $format) = @_;
148     my $with_items = 0;
149     if ( my $conf = $self->{conf} ) {
150         $with_items = $conf->{format}->{$format}->{include_items};
151     }
152     my $record = GetMarcBiblio($biblionumber, $with_items, 1);
153     $record ? $record->as_xml() : undef;
154 }
155
156
157 sub stylesheet {
158     my ( $self, $format ) = @_;
159
160     my $stylesheet = $self->{ koha_stylesheet }->{ $format };
161     unless ( $stylesheet ) {
162         my $xsl_file = $self->{ conf }
163                        ? $self->{ conf }->{ format }->{ $format }->{ xsl_file }
164                        : ( C4::Context->config('intrahtdocs') .
165                          '/prog/en/xslt/' .
166                          C4::Context->preference('marcflavour') .
167                          'slim2OAIDC.xsl' );
168         my $parser = XML::LibXML->new();
169         my $xslt = XML::LibXSLT->new();
170         my $style_doc = $parser->parse_file( $xsl_file );
171         $stylesheet = $xslt->parse_stylesheet( $style_doc );
172         $self->{ koha_stylesheet }->{ $format } = $stylesheet;
173     }
174
175     return $stylesheet;
176 }
177
178 1;