Class: PrimoService
- Defined in:
- lib/service_adaptors/primo_service.rb
Overview
Overview
PrimoService is a Service that makes a call to the Primo web services based on the OpenURL key value pairs. – NOT YET: It first looks for rft.primo DEPRECATED, failing that, it parses the identifier for an id. ++ It first looks for rft.primo, the Primo id. If the Primo id is present, the service gets the PNX record from the Primo web services. If no Primo id is found, the service searches Primo by (in order of precedence):
-
ISBN
-
ISSN
-
Title, Author, Genre
Available Services
Several service types are available in the Primo service. The default service types are: fulltext, holding, holding_search, table_of_contents, referent_enhance, cover_image Available service types are listed below and can be configured using the service_types parameter in service.yml:
-
fulltext - parsed from links/linktorsrc elements in the PNX record
-
holding - parsed from display/availlibrary elements in the PNX record
-
holding_search - link to an exact title search in Primo if no holdings found AND the OpenURL did not come from Primo
-
primo_source - similar to holdings but used in conjuction with the PrimoSource service to map Primo records to their original sources; a PrimoSource service must be defined in service.yml for this to work
-
table_of_contents - parsed from links/linktotoc elements in the PNX record
-
referent_enhance - metadata parsed from the addata section of the PNX record when the record was found by Primo id
-
cover_image - parsed from first addata/lad02 element in the PNX record
-
highlighted_link - parsed from links/addlink elements in the PNX record
Available Parameters
Several configurations parameters are available to be set in services.yml, e.g.
Primo:
type: PrimoService
priority: 2 # After SFX, to get SFX metadata enhancement
status: active
base_url: http://bobcat.library.nyu.edu
vid: NYU
holding_search_institution: NYU
holding_search_text: Search for this title in BobCat.
suppress_holdings: [ !ruby/regexp '/\$\$LWEB/', !ruby/regexp '/\$\$1Restricted Internet Resources/' ]
ez_proxy: !ruby/regexp '/https\:\/\/ezproxy\.library\.nyu\.edu\/login\?url=/'
service_types:
- holding
- holding_search
- fulltext
- table_of_contents
- referent_enhance
- cover_image
- highlighted_link
- base_url
-
required host and port of Primo server; used for Primo web services, deep links and holding_search
- base_path
-
DEPRECATED previous name of base_url
- vid
-
required view id for Primo deep links and holding_search.
- institution
-
required institution id for Primo institution; used for Primo web services
- base_view_id
-
DEPRECATED previous name of vid
- holding_search_institution
-
_required if service types include holding_search_ institution to be used for the holding_search
- holding_search_text
-
optional text to display for the holding_search
- default holding search text
-
“Search for this title.”
- link_to_search_text
-
DEPRECATED previous name of holding_search_text
- service_types
-
optional array of strings that represent the service types desired. options are: fulltext, holding, holding_search, table_of_contents, referent_enhance, cover_image, primo_source defaults are: fulltext, holding, holding_search, table_of_contents, referent_enhance, cover_image if no options are specified, default service types will be added.
- suppress_urls
-
optional array of strings or regexps to NOT use from the catalog. Used for linktorsrc elements that may duplicate resources from in other services. Regexps can be put in the services.yml like this:
[!ruby/regexp '/sagepub.com$/']
- suppress_holdings
-
optional array of strings or regexps to NOT use from the catalog. Used for availlibrary elements that may duplicate resources from in other services. Regexps can be put in the services.yml like this:
[!ruby/regexp '/\$\$LWEB$/']
- suppress_tocs
-
optional array of strings or regexps to NOT link to for Tables of Contents. Used for linktotoc elements that may duplicate resources from in other services. Regexps can be put in the services.yml like this:
[!ruby/regexp '/\$\$LWEB$/']
- service_types
-
optional array of strings that represent the service types desired. options are: fulltext, holding, holding_search, table_of_contents, referent_enhance, cover_image, primo_source defaults are: fulltext, holding, holding_search, table_of_contents, referent_enhance, cover_image if no options are specified, default service types will be added.
- ez_proxy
-
optional string or regexp of an ezproxy prefix. used in the case where an ezproxy prefix (on any other regexp) is hardcoded in the URL, and needs to be removed in order to match against SFXUrls. Example:
!ruby/regexp '/https\:\/\/ezproxy\.library\.nyu\.edu\/login\?url=/'
- primo_config
-
optional string representing the primo yaml config file in config/umlaut_config default file name: primo.yml hash mappings from yaml config
institutions: "primo_institution_code": "Primo Institution String" libraries: "primo_library_code": "Primo Library String" statuses: "status1_code": "Status One" sources: data_source1: base_url: "http://source1.base.url type: source_type class_name: Source1Implementation (in exlibris/primo/sources or exlibris/primo/sources/local) source1_config_option1: source1_config_option1 source1_config_option2: source1_config_option2 data_source2: base_url: "http://source2.base.url type: source_type class_name: Source2Implementation (in exlibris/primo/sources or exlibris/primo/sources/local) source2_config_option1: source2_config_option1 source2_config_option2: source2_config_option2
- holding_attributes
-
optional array of Holding attribute readers to save to holding/primo_source service_data; can be used to save custom source implementation attributes for display by a custom holding partial
Benchmarks
The following benchmarks were run on SunOS 5.10 Generic_141414-08 sun4u sparc SUNW,Sun-Fire-V240.
Rehearsal ----------------------------------------------------------------
PrimoService Minimum Config: 3.850000 0.060000 3.910000 ( 4.163065)
PrimoService Default Config: 3.410000 0.060000 3.470000 ( 3.958777)
------------------------------------------------------- total: 7.380000sec
user system total real
PrimoService Minimum Config: 3.470000 0.050000 3.520000 ( 4.567797)
PrimoService Default Config: 3.420000 0.050000 3.470000 ( 3.990271)
Direct Known Subclasses
Constant Summary
Constants inherited from Service
Service::LinkOutFilterTask, Service::StandardTask
Instance Attribute Summary
Attributes inherited from Service
#name, #priority, #request, #service_id, #session_id, #status, #task, #url
Instance Method Summary collapse
-
#handle(request) ⇒ Object
Overwrites Service#handle.
-
#initialize(config) ⇒ PrimoService
constructor
Overwrites Service#new.
-
#service_types_generated ⇒ Object
Overwrites Service#service_types_generated.
-
#to_primo_source(service_response) ⇒ Object
Called by ServiceType#view_data to provide custom functionality for Primo sources.
Methods inherited from Service
#credits, #display_name, #handle_wrapper, #link_out_filter, #preempted_by, required_config_params, #response_to_view_data, #response_url, #view_data_from_service_type
Constructor Details
#initialize(config) ⇒ PrimoService
Overwrites Service#new.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/service_adaptors/primo_service.rb', line 130 def initialize(config) # defaults @holding_attributes = Exlibris::Primo::Holding.base_attributes @rsrc_attributes = Exlibris::Primo::Rsrc.base_attributes @toc_attributes = Exlibris::Primo::Toc.base_attributes @related_link_attributes = Exlibris::Primo::RelatedLink.base_attributes # TODO: Run these decisions by Bill M. to see if they make sense. @referent_enhancements = { # Prefer SFX journal titles to Primo journal titles :jtitle => { :overwrite => false }, :btitle => { :overwrite => true }, :aulast => { :overwrite => true }, :aufirst => { :overwrite => true }, :aucorp => { :overwrite => true }, :au => { :overwrite => true }, :pub => { :overwrite => true }, :place => { :value => :cop, :overwrite => false }, # Prefer SFX journal titles to Primo journal titles :title => { :value => :jtitle, :overwrite => false}, :title => { :value => :btitle, :overwrite => true}, # Primo lccn and oclcid are spotty in Primo, so don't overwrite :lccn => { :overwrite => false }, :oclcnum => { :value => :oclcid, :overwrite => false} } @suppress_urls = [] @suppress_tocs = [] @suppress_related_links = [] @suppress_holdings = [] @service_types = [ "fulltext", "holding", "holding_search", "table_of_contents", "referent_enhance", "cover_image" ] if @service_types.nil? # For backward compatibility, re-map "old" config values to new more # Umlaut-y names and print deprecation warning in the logs. old_to_new_mappings = { :base_path => :base_url, :base_view_id => :vid, :link_to_search_text => :holding_search_text } old_to_new_mappings.each do |old_param, new_param| unless config["#{old_param}"].nil? config["#{new_param}"] = config["#{old_param}"] if config["#{new_param}"].nil? Rails.logger.warn("Parameter '#{old_param}' is deprecated. Please use '#{new_param}' instead.") end end # End backward compatibility maintenance super(config) # For backward compatibility, handle the special case where holding_search_institution was not included. # Set holding_search_institution to vid and print warning in the logs. if @service_types.include?("holding_search") and @holding_search_institution.nil? @holding_search_institution = @institution Rails.logger.warn("Required parameter 'holding_search_institution' was not set. Please set the appropriate value in services.yml. Defaulting institution to view id, #{@vid}.") end # End backward compatibility maintenance raise ArgumentError.new( "Missing Service configuration parameter. Service type #{self.class} (id: #{self.id}) requires a config parameter named 'holding_search_institution'. Check your config/umlaut_config/services.yml file." ) if @service_types.include?("holding_search") and @holding_search_institution.nil? end |
Instance Method Details
#handle(request) ⇒ Object
Overwrites Service#handle.
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 |
# File 'lib/service_adaptors/primo_service.rb', line 191 def handle(request) @identifier = request.referrer_id @primo_id = @identifier.match(/primo-(.+)/)[1] if primo_identifier? unless @identifier.nil? or @identifier.match(/primo-(.+)/).nil? # DEPRECATED # Extend OpenURL standard to take Primo Doc Id @primo_id = request.referent.['primo'] unless request.referent.['primo'].nil? Rails.logger.warn("Use of 'rft.primo' is deprecated. Please use the identifier instead.") unless request.referent.['primo'].nil? # End DEPRECATED searcher_setup = { :base_url => @base_url, :vid => @vid, :institution => @institution, :config => primo_config } # don't send mal-formed issn @issn = request.referent.['issn'] if request.referent.['issn'] =~ /\d{4}(-)?\d{3}(\d|X)/ @isbn = request.referent.['isbn'] @title = title(request) search_params = { :primo_id => @primo_id, :isbn => @isbn, :issn => @issn, :title => @title, :author => (request), :genre => request.referent.['genre'] } begin primo_searcher = Exlibris::Primo::Searcher.new(searcher_setup, search_params) rescue Exception => e # Log error and return finished Rails.logger.error( "Error in Exlibris::Primo::Searcher. "+ "Returning 0 Primo services for search #{search_params.inspect}. "+ "Exlibris::Primo::Searcher raised the following exception:\n#{e}\n#{e.backtrace.inspect}") return request.dispatched(self, true) end # Enhance the referent with metadata from Primo Searcher if primo id is present # i.e. if we did our search with the Primo system number if @primo_id and @service_types.include?("referent_enhance") @referent_enhancements.each do |key, | value = ([:value].nil?) ? key.to_sym : [:value].to_sym request.referent.enhance_referent( key.to_s, primo_searcher.method(value).call, true, false, ) if primo_searcher.respond_to? value and not primo_searcher.method(value).call.nil? end end # Get cover image only if @primo_id is defined # TODO: make cover image service smarter and only # include things that are actually URLs. if @primo_id and @service_types.include?("cover_image") cover_image = primo_searcher.cover_image unless cover_image.nil? request.add_service_response( :service => self, :display_text => 'Cover Image', :key => 'medium', :url => cover_image, :size => 'medium', :service_type_value => :cover_image) end end # Get holdings from Primo Searcher if @service_types.include?("holding") or @service_types.include?("primo_source") holdings = primo_searcher.holdings # Array of Exlibris::Primo::Holding holdings.each do |holding| next if @suppress_holdings.find {|suppress| suppress === holding.availlibrary} service_data = {} @holding_attributes.each do |attr| service_data[attr] = holding.method(attr).call end # Umlaut specific attributes. service_data[:match_reliability] = (reliable_match?(:title => holding.title, :author => holding.)) ? ServiceResponse::MatchExact : ServiceResponse::MatchUnsure service_data[:request_link_supports_ajax_call] = (holding.respond_to?(:request_link_supports_ajax_call)) ? holding.request_link_supports_ajax_call : false # Only add one service type, either "primo_source" OR "holding", not both. service_type = (@service_types.include?("primo_source")) ? "primo_source" : "holding" # Add some other holding information for compatibility with default holding partial service_data.merge!({ :call_number => holding.call_number, :collection => holding.collection, :collection_str => "#{holding.library} #{holding.collection}", :coverage_str => holding.coverage.join("<br />"), :coverage_str_array => holding.coverage }) if service_type.eql? "holding" request.add_service_response( service_data.merge( :service => self, :service_type_value => service_type ) ) end # Provide title search functionality in the absence of available holdings. if @service_types.include?("holding_search") if holdings.empty? and not primo_identifier? and not @title.nil? service_data = {} service_data[:type] = "link_to_search" service_data[:display_text] = (@holding_search_text.nil?) ? "Search for this title." : @holding_search_text service_data[:note] = "" service_data[:url] = @base_url+"/primo_library/libweb/action/dlSearch.do?institution=#{@holding_search_institution}&vid=#{@vid}&onCampus=false&query=#{CGI::escape("title,exact,"+@title)}&indx=1&bulkSize=10&group=GUEST" request.add_service_response( service_data.merge( :service => self, :service_type_value => 'holding_search' ) ) end end end # Get fulltext if @service_types.include?("fulltext") # Get RSRCs from Primo Searcher (executes search) # Let's find any URLs, and add full text responses for those. urls_seen = [] # for de-duplicating urls from catalog. primo_searcher.rsrcs.each do |rsrc| # No url? Forget it. next if rsrc.url.nil? # Next if duplicate. next if urls_seen.include?(rsrc.url) # Don't add the URL if it matches our SFXUrl finder (unless fulltext is empty, # [assuming something is better than nothing]), because # that means we think this is an SFX controlled URL. next if SfxUrl.sfx_controls_url?(handle_ezproxy(rsrc.url)) and request.referent.['genre'] != "book" and !request.get_service_type("fulltext", { :refresh => true }).empty? # We have our own list of URLs to suppress, array of strings # or regexps. next if @suppress_urls.find {|suppress| suppress === rsrc.url} urls_seen.push(rsrc.url) service_data = {} @rsrc_attributes.each do |attr| service_data[attr] = rsrc.method(attr).call end # Default display text to URL. service_data[:display_text] = (service_data[:display].nil?) ? service_data[:url] : service_data[:display] # Add the response request.add_service_response( service_data.merge( :service => self, :service_type_value => 'fulltext' ) ) end end # Get TOCs if @service_types.include?("table_of_contents") # Let's find any TOCs, and add table of contents responses for those. tocs_seen = [] # for de-duplicating urls from catalog. primo_searcher.tocs.each do |toc| url = toc.url # actual url next if tocs_seen.include?(toc.url) # We have our own list of URLs to suppress, array of strings # or regexps. next if @suppress_tocs.find {|suppress| suppress === toc.url} # No url? Forget it. next if toc.url.nil? tocs_seen.push(toc.url) service_data = {} @toc_attributes.each do |attr| service_data[attr] = toc.method(attr).call end # Default display text to URL. service_data[:display_text] = (service_data[:display].nil?) ? service_data[:url] : service_data[:display] # Add the response request.add_service_response( service_data.merge( :service => self, :service_type_value => 'table_of_contents' ) ) end end if @service_types.include?("highlighted_link") # Let's find any related links, and add highlighted link responses for those. = [] # for de-duplicating urls from catalog. primo_searcher..each do || url = .url # actual url next if .include?(.url) # We have our own list of URLs to suppress, array of strings # or regexps. next if @suppress_related_links.find {|suppress| suppress === .url} # No url? Forget it. next if .url.nil? .push(.url) service_data = {} @related_link_attributes.each do |attr| service_data[attr] = .method(attr).call end # Default display text to URL. service_data[:display_text] = (service_data[:display].nil?) ? service_data[:url] : service_data[:display] # Add the response request.add_service_response( service_data.merge( :service => self, :service_type_value => 'highlighted_link' ) ) end end return request.dispatched(self, true) end |
#service_types_generated ⇒ Object
Overwrites Service#service_types_generated.
182 183 184 185 186 187 188 |
# File 'lib/service_adaptors/primo_service.rb', line 182 def service_types_generated types = Array.new @service_types.each do |type| types.push(ServiceTypeValue[type.to_sym]) end return types end |
#to_primo_source(service_response) ⇒ Object
Called by ServiceType#view_data to provide custom functionality for Primo sources. For more information on Primo sources see PrimoSource.
396 397 398 399 400 401 |
# File 'lib/service_adaptors/primo_service.rb', line 396 def to_primo_source(service_response) source_parameters = { :base_url => @base_url, :vid => @vid, :config => primo_config } @holding_attributes.each { |attr| source_parameters[attr] = service_response.data_values[attr] } return Exlibris::Primo::Holding.new(source_parameters).to_source end |