class Alexandria::BookProviders::Z3950Provider

Public Class Methods

new(name = "Z3950", fullname = "Z39.50") click to toggle source
# File lib/alexandria/book_providers/z3950.rb, line 20
def initialize(name = "Z3950", fullname = "Z39.50")
  super
  prefs.add("hostname", _("Hostname"), "")
  prefs.add("port", _("Port"), 7090)
  prefs.add("database", _("Database"), "")
  prefs.add("record_syntax", _("Record syntax"), "USMARC",
            ["USMARC", "UNIMARC", "SUTRS"])
  prefs.add("username", _("Username"), "", nil, false)
  prefs.add("password", _("Password"), "", nil, false)
  prefs.add("charset", _("Charset encoding"), "ISO-8859-1")

  # HACK : piggybacking support
  prefs.add("piggyback", "Piggyback", true, [true, false])
  prefs.read
end

Public Instance Methods

books_from_resultset(resultset, isbn) click to toggle source
# File lib/alexandria/book_providers/z3950.rb, line 56
def books_from_resultset(resultset, isbn)
  case prefs["record_syntax"]
  when /MARC$/
    books_from_marc(resultset, isbn)
  when "SUTRS"
    books_from_sutrs(resultset)
  else
    raise NoResultsError
  end
end
url(_book) click to toggle source
# File lib/alexandria/book_providers/z3950.rb, line 52
def url(_book)
  nil
end

Private Instance Methods

books_from_marc(resultset, isbn) click to toggle source
# File lib/alexandria/book_providers/z3950.rb, line 122
def books_from_marc(resultset, isbn)
  results = []
  resultset[0..9].each do |record|
    marc_txt = record.render(prefs["charset"], "UTF-8")
    log.debug { marc_txt }
    if $DEBUG
      File.open(",marc.txt", "wb") do |f| # DEBUG
        f.write(marc_txt)
      end
    end
    book = nil
    begin
      mappings = Alexandria::PseudoMarcParser::USMARC_MAPPINGS
      if prefs["hostname"] == "z3950.bnf.fr"
        mappings = Alexandria::PseudoMarcParser::BNF_FR_MAPPINGS
      end
      # try pseudo-marc parser first (it seems to have more luck)
      book = Alexandria::PseudoMarcParser.marc_text_to_book(marc_txt,
                                                            mappings)
      if book.nil?
        # failing that, try the genuine MARC parser
        book = marc_to_book(marc_txt, isbn)
      end
    rescue StandardError => ex
      log.warn { ex }
      log.warn { ex.backtrace }
    end

    results << [book] unless book.nil?
  end
  results
end
books_from_sutrs(_resultset) click to toggle source
# File lib/alexandria/book_providers/z3950.rb, line 78
def books_from_sutrs(_resultset)
  # SUTRS needs to be decoded separately, because each Z39.50 server has a
  # different one.
  raise NoResultsError
end
canonicalise_criterion(criterion, type) click to toggle source
# File lib/alexandria/book_providers/z3950.rb, line 73
def canonicalise_criterion(criterion, type)
  criterion = Library.canonicalise_isbn(criterion) if type == SEARCH_BY_ISBN
  criterion
end
marc?() click to toggle source
# File lib/alexandria/book_providers/z3950.rb, line 155
def marc?
  prefs["record_syntax"].end_with?("MARC")
end
marc_to_book(marc_txt, isbn) click to toggle source
# File lib/alexandria/book_providers/z3950.rb, line 84
def marc_to_book(marc_txt, isbn)
  begin
    marc = MARC::Record.new_from_marc(marc_txt, forgiving: true)
  rescue StandardError => ex
    log.error { ex.message }
    log.error { ex.backtrace.join("> \n") }
    begin
      marc = MARC::Record.new(marc_txt)
    rescue StandardError => ex
      log.error { ex.message }
      log.error { ex.backtrace.join("> \n") }
      raise ex
    end
  end

  log.debug do
    msg = "Parsing MARC"
    msg += "\n title: #{marc.title}"
    msg += "\n authors: #{marc.authors.join(', ')}"
    msg += "\n isbn: #{marc.isbn}, #{isbn}"
    msg += "\n publisher: #{marc.publisher}"
    msg += "\n publish year: #{marc.publish_year}" if marc.respond_to?(:publish_year)
    msg += "\n edition: #{marc.edition}"
    msg
  end

  return if marc.title.nil? # or marc.authors.empty?

  isbn ||= marc.isbn
  isbn = Library.canonicalise_ean(isbn)

  Book.new(marc.title, marc.authors,
           isbn,
           (marc.publisher || ""),
           marc.respond_to?(:publish_year) ? marc.publish_year.to_i : nil,
           (marc.edition || ""))
end
request_count(type) click to toggle source
# File lib/alexandria/book_providers/z3950.rb, line 69
def request_count(type)
  type == SEARCH_BY_ISBN ? 1 : 10 # results to retrieve
end
search_records(criterion, type, conn_count) click to toggle source
# File lib/alexandria/book_providers/z3950.rb, line 159
def search_records(criterion, type, conn_count)
  options = {}
  unless prefs["username"].empty? || prefs["password"].empty?
    options["user"] = prefs["username"]
    options["password"] = prefs["password"]
  end
  hostname = prefs["hostname"]
  port = prefs["port"].to_i
  log.debug { "hostname #{hostname} port #{port} options #{options}" }
  conn = ZOOM::Connection.new(options).connect(hostname, port)
  conn.database_name = prefs["database"]

  conn.preferred_record_syntax = prefs["record_syntax"]
  conn.element_set_name = "F"
  conn.count = conn_count
  attr = case type
         when SEARCH_BY_ISBN     then [7]
         when SEARCH_BY_TITLE    then [4]
         when SEARCH_BY_AUTHORS  then [1, 1003]
         when SEARCH_BY_KEYWORD  then [1016]
         end
  pqf = ""
  attr.each { |att| pqf += "@attr 1=#{att} " }
  pqf += '"' + criterion.upcase + '"'
  log.debug { "pqf is #{pqf}, syntax #{prefs['record_syntax']}" }

  begin
    if prefs.variable_named("piggyback") && !prefs["piggyback"]
      log.debug { "setting conn.piggyback to false" }
      conn.piggyback = false
    end
    conn.search(pqf)
  rescue StandardError => ex
    if /1005/.match?(ex.message) &&
        prefs.variable_named("piggyback") && prefs["piggyback"]
      log.error { "Z39.50 search failed:: #{ex.message}" }
      log.info { "Turning off piggybacking for this provider" }
      prefs.variable_named("piggyback").new_value = false
      retry
    end

    raise ex
  end
end