active-fedora 1.1.13 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,9 @@
1
1
  require 'solr'
2
- require "active_fedora/solr_mapper"
3
- require "yaml"
4
- module ActiveFedora
5
- class SolrService
2
+ require "solrizer/field_name_mapper"
3
+
4
+ module ActiveFedora
5
+ class SolrService
6
6
 
7
- @@mappings = {}
8
7
  attr_reader :conn
9
8
 
10
9
  def self.register(host=nil, args={})
@@ -22,19 +21,23 @@ module ActiveFedora
22
21
  Thread.current[:solr_service]
23
22
  end
24
23
 
25
- def self.reify_solr_results(solr_result)
24
+ def self.reify_solr_results(solr_result,opts={})
26
25
  unless solr_result.is_a?(Solr::Response::Standard)
27
26
  raise ArgumentError.new("Only solr responses (Solr::Response::Standard) are allowed. You provided a #{solr_result.class}")
28
27
  end
29
28
  results = []
30
29
  solr_result.hits.each do |hit|
31
- model_value = hit[ActiveFedora::SolrMapper.solr_name("active_fedora_model", :symbol)].first
30
+ model_value = hit[Solrizer::FieldNameMapper.solr_name("active_fedora_model", :symbol)].first
32
31
  if model_value.include?("::")
33
32
  classname = eval(model_value)
34
33
  else
35
34
  classname = Kernel.const_get(model_value)
36
35
  end
37
- results << Fedora::Repository.instance.find_model(hit[SOLR_DOCUMENT_ID], classname)
36
+ if opts[:load_from_solr]
37
+ results << classname.load_instance_from_solr(hit[SOLR_DOCUMENT_ID])
38
+ else
39
+ results << Fedora::Repository.instance.find_model(hit[SOLR_DOCUMENT_ID], classname)
40
+ end
38
41
  end
39
42
  return results
40
43
  end
@@ -54,40 +57,22 @@ module ActiveFedora
54
57
  end
55
58
 
56
59
  def self.mappings
57
- @@mappings
60
+ Solrizer::FieldNameMapper.mappings
58
61
  end
59
62
  def self.mappings=(mappings)
60
- @@mappings = mappings
61
- end
62
-
63
+ Solrizer::FieldNameMapper.mappings = mappings
64
+ end
65
+
63
66
  def self.logger
64
67
  @logger ||= defined?(RAILS_DEFAULT_LOGGER) ? RAILS_DEFAULT_LOGGER : Logger.new(STDOUT)
65
68
  end
66
69
 
67
- # Loads solr mappings from yml file.
68
- # @config_path This is the path to the directory where your mappings file is stored. @default "RAILS_ROOT/config/solr_mappings.yml"
69
- # @mappings_file This is the filename for your solr mappings YAML file. @default solr_mappings.yml
70
+ # (re)load solr field name mappings
70
71
  def self.load_mappings( config_path=nil )
71
-
72
- if config_path.nil?
73
- if defined?(RAILS_ROOT)
74
- config_path = File.join(RAILS_ROOT, "config", "solr_mappings.yml")
75
- end
76
- # Default to using the config file within the gem
77
- if !File.exist?(config_path.to_s)
78
- config_path = File.join(File.dirname(__FILE__), "..", "..", "config", "solr_mappings.yml")
79
- end
80
- end
81
-
82
- logger.info("FEDORA: loading SolrService mappings from #{File.expand_path(config_path)}")
83
-
84
- @@mappings = YAML::load(File.open(config_path))
85
-
86
- mappings["id"] = "id" unless mappings["id"]
72
+ Solrizer::FieldNameMapper.load_mappings(config_path)
87
73
  end
88
74
 
89
- self.load_mappings
90
-
91
- end
92
- class SolrNotInitialized < StandardError;end
93
- end
75
+
76
+ end #SolrService
77
+ class SolrNotInitialized < StandardError;end
78
+ end #ActiveFedora
@@ -186,9 +186,13 @@ module Fedora
186
186
  # Creates new Net::HTTP instance for communication with
187
187
  # remote service and resources.
188
188
  def http
189
- http = Net::HTTP.new(@site.host, @site.port)
190
- http.use_ssl = @site.is_a?(URI::HTTPS)
191
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl
189
+ http = Net::HTTP.new(@site.host, @site.port)
190
+ if(@site.is_a?(URI::HTTPS) && !SSL_CLIENT_CERT_FILE.nil? && !SSL_CLIENT_KEY_FILE.nil? && !SSL_CLIENT_KEY_PASS.nil?)
191
+ http.use_ssl = true
192
+ http.cert = OpenSSL::X509::Certificate.new( File.read(SSL_CLIENT_CERT_FILE) )
193
+ http.key = OpenSSL::PKey::RSA.new( File.read(SSL_CLIENT_KEY_FILE), SSL_CLIENT_KEY_PASS )
194
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
195
+ end
192
196
  http
193
197
  end
194
198
 
@@ -1,100 +1,63 @@
1
1
  require "hydra"
2
2
  module Hydra
3
3
  class Hydra::SampleModsDatastream < ActiveFedora::NokogiriDatastream
4
-
5
- # have to call this in order to set namespace & schema
6
- root_property :mods, "mods", "http://www.loc.gov/mods/v3", :attributes=>["id", "version"], :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd"
7
-
8
- property :title_info, :path=>"titleInfo",
9
- :convenience_methods => {
10
- :main_title => {:path=>"title"},
11
- :language => {:path=>{:attribute=>"lang"}},
12
- }
13
- property :abstract, :path=>"abstract"
14
- property :topic_tag, :path=>'subject',:default_content_path => "topic"
15
-
16
- property :name_, :path=>"name",
17
- :attributes=>[:xlink, :lang, "xml:lang", :script, :transliteration, {:type=>["personal", "enumerated", "corporate"]} ],
18
- :subelements=>["namePart", "displayForm", "affiliation", :role, "description"],
19
- :default_content_path => "namePart",
20
- :convenience_methods => {
21
- :date => {:path=>"namePart", :attributes=>{:type=>"date"}},
22
- :family_name => {:path=>"namePart", :attributes=>{:type=>"family"}},
23
- :first_name => {:path=>"namePart", :attributes=>{:type=>"given"}},
24
- :terms_of_address => {:path=>"namePart", :attributes=>{:type=>"termsOfAddress"}}
25
- }
26
-
27
- property :person, :variant_of=>:name_, :attributes=>{:type=>"personal"}
28
- property :organizaton, :variant_of=>:name_, :attributes=>{:type=>"institutional"}
29
- property :conference, :variant_of=>:name_, :attributes=>{:type=>"conference"}
30
-
31
- property :role, :path=>"role",
32
- :parents=>[:name_],
33
- :convenience_methods => {
34
- :text => {:path=>"roleTerm", :attributes=>{:type=>"text"}},
35
- :code => {:path=>"roleTerm", :attributes=>{:type=>"code"}},
36
- }
37
-
38
- property :journal, :path=>'relatedItem', :attributes=>{:type=>"host"},
39
- :subelements=>[:title_info, :origin_info, :issue],
40
- :convenience_methods => {
41
- :issn => {:path=>"identifier", :attributes=>{:type=>"issn"}},
42
- }
43
-
44
- property :origin_info, :path=>'originInfo',
45
- :subelements=>["publisher","dateIssued"]
46
-
47
- property :issue, :path=>'part',
48
- :subelements=>[:start_page, :end_page],
49
- :convenience_methods => {
50
- :volume => {:path=>"detail", :attributes=>{:type=>"volume"}},
51
- :level => {:path=>"detail", :attributes=>{:type=>"level"}},
52
- :publication_date => {:path=>"date"}
53
- }
54
- property :start_page, :path=>"extent", :attributes=>{:unit=>"pages"}, :default_content_path => "start"
55
- property :end_page, :path=>"extent", :attributes=>{:unit=>"pages"}, :default_content_path => "end"
56
-
57
- generate_accessors_from_properties
58
- # accessor :title_info, :relative_xpath=>'oxns:titleInfo', :children=>[
59
- # {:main_title=>{:relative_xpath=>'oxns:title'}},
60
- # {:language =>{:relative_xpath=>{:attribute=>"lang"} }}
61
- # ]
62
- # accessor :abstract
63
- # accessor :topic_tag, :relative_xpath=>'oxns:subject/oxns:topic'
64
- # accessor :person, :relative_xpath=>'oxns:name[@type="personal"]', :children=>[
65
- # {:last_name=>{:relative_xpath=>'oxns:namePart[@type="family"]'}},
66
- # {:first_name=>{:relative_xpath=>'oxns:namePart[@type="given"]'}},
67
- # {:institution=>{:relative_xpath=>'oxns:affiliation'}},
68
- # {:role=>{:children=>[
69
- # {:text=>{:relative_xpath=>'oxns:roleTerm[@type="text"]'}},
70
- # {:code=>{:relative_xpath=>'oxns:roleTerm[@type="code"]'}}
71
- # ]}}
72
- # ]
73
- # accessor :organization, :relative_xpath=>'oxns:name[@type="institutional"]', :children=>[
74
- # {:role=>{:children=>[
75
- # {:text=>{:relative_xpath=>'oxns:roleTerm[@type="text"]'}},
76
- # {:code=>{:relative_xpath=>'oxns:roleTerm[@type="code"]'}}
77
- # ]}}
78
- # ]
79
- # accessor :conference, :relative_xpath=>'oxns:name[@type="conference"]', :children=>[
80
- # {:role=>{:children=>[
81
- # {:text=>{:relative_xpath=>'oxns:roleTerm[@type="text"]'}},
82
- # {:code=>{:relative_xpath=>'oxns:roleTerm[@type="code"]'}}
83
- # ]}}
84
- # ]
85
- # accessor :journal, :relative_xpath=>'oxns:relatedItem[@type="host"]', :children=>[
86
- # {:title=>{:relative_xpath=>'oxns:titleInfo/oxns:title'}},
87
- # {:publisher=>{:relative_xpath=>'oxns:originInfo/oxns:publisher'}},
88
- # {:issn=>{:relative_xpath=>'oxns:identifier[@type="issn"]'}},
89
- # {:date_issued=>{:relative_xpath=>'oxns:originInfo/oxns:dateIssued'}},
90
- # {:issue => {:relative_xpath=>"oxns:part", :children=>[
91
- # {:volume=>{:relative_xpath=>'oxns:detail[@type="volume"]'}},
92
- # {:level=>{:relative_xpath=>'oxns:detail[@type="level"]'}},
93
- # {:start_page=>{:relative_xpath=>'oxns:extent[@unit="pages"]/oxns:start'}},
94
- # {:end_page=>{:relative_xpath=>'oxns:extent[@unit="pages"]/oxns:end'}},
95
- # {:publication_date=>{:relative_xpath=>'oxns:date'}}
96
- # ]}}
97
- # ]
4
+
5
+ set_terminology do |t|
6
+ t.root(:path=>"mods", :xmlns=>"http://www.loc.gov/mods/v3", :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd")
7
+
8
+ t.title_info(:path=>"titleInfo") {
9
+ t.main_title(:path=>"title", :label=>"title")
10
+ t.language(:path=>{:attribute=>"lang"})
11
+ }
12
+ t.abstract
13
+ t.topic_tag(:path=>"subject", :default_content_path=>"topic")
14
+ # This is a mods:name. The underscore is purely to avoid namespace conflicts.
15
+ t.name_ {
16
+ # this is a namepart
17
+ t.namePart(:index_as=>[:searchable, :displayable, :facetable, :sortable], :required=>:true, :type=>:string, :label=>"generic name")
18
+ # affiliations are great
19
+ t.affiliation
20
+ t.displayForm
21
+ t.role(:ref=>[:role])
22
+ t.description
23
+ t.date(:path=>"namePart", :attributes=>{:type=>"date"})
24
+ t.last_name(:path=>"namePart", :attributes=>{:type=>"family"})
25
+ t.first_name(:path=>"namePart", :attributes=>{:type=>"given"}, :label=>"first name")
26
+ t.terms_of_address(:path=>"namePart", :attributes=>{:type=>"termsOfAddress"})
27
+ }
28
+ # lookup :person, :first_name
29
+ t.person(:ref=>:name, :attributes=>{:type=>"personal"})
30
+ t.organizaton(:ref=>:name, :attributes=>{:type=>"institutional"})
31
+ t.conference(:ref=>:name, :attributes=>{:type=>"conference"})
32
+
33
+ t.role {
34
+ t.text(:path=>"roleTerm",:attributes=>{:type=>"text"})
35
+ t.code(:path=>"roleTerm",:attributes=>{:type=>"code"})
36
+ }
37
+ t.journal(:path=>'relatedItem', :attributes=>{:type=>"host"}) {
38
+ t.title_info
39
+ t.origin_info(:path=>"originInfo") {
40
+ t.publisher
41
+ t.date_issued(:path=>"dateIssued")
42
+ }
43
+ t.issn(:path=>"identifier", :attributes=>{:type=>"issn"})
44
+ t.issue(:path=>"part") {
45
+ t.volume(:path=>"detail", :attributes=>{:type=>"volume"}, :default_content_path=>"number")
46
+ t.level(:path=>"detail", :attributes=>{:type=>"number"}, :default_content_path=>"number")
47
+ t.extent
48
+ t.pages(:path=>"extent", :attributes=>{:type=>"pages"}) {
49
+ t.start
50
+ t.end
51
+ }
52
+ t.publication_date(:path=>"date")
53
+ }
54
+ }
55
+
56
+ end
57
+
58
+ # Changes from OM::Properties implementation
59
+ # renamed family_name => last_name
60
+ # start_page & end_page now accessible as [:journal, :issue, :pages, :start] (etc.)
98
61
 
99
62
  end
100
63
  end
@@ -0,0 +1,215 @@
1
+ require File.join( File.dirname(__FILE__), "..", "spec_helper" )
2
+
3
+ class MockAFBaseQuerySolr < ActiveFedora::Base
4
+ has_metadata :name => "properties", :type => ActiveFedora::MetadataDatastream do |m|
5
+ m.field "holding_id", :string
6
+ end
7
+
8
+ has_metadata :name => "descMetadata", :type => ActiveFedora::QualifiedDublinCoreDatastream do |m|
9
+ m.field "created", :date, :xml_node => "created"
10
+ m.field "language", :string, :xml_node => "language"
11
+ m.field "creator", :string, :xml_node => "creator"
12
+ # Created remaining fields
13
+ m.field "geography", :string, :xml_node => "geography"
14
+ m.field "title", :string, :xml_node => "title"
15
+ end
16
+ end
17
+
18
+ describe ActiveFedora::Base do
19
+
20
+ before(:each) do
21
+ @test_object = ActiveFedora::Base.new
22
+ @test_object.new_object = true
23
+ end
24
+
25
+ after(:each) do
26
+ begin
27
+ @test_object.delete
28
+ rescue
29
+ end
30
+ begin
31
+ @test_object2.delete
32
+ rescue
33
+ end
34
+ begin
35
+ @test_object3.delete
36
+ rescue
37
+ end
38
+ begin
39
+ @test_object4.delete
40
+ rescue
41
+ end
42
+ begin
43
+ @test_object5.delete
44
+ rescue
45
+ end
46
+ end
47
+
48
+ describe '#find_by_fields_by_solr' do
49
+ it 'should return fedora objects of the model of self that match the given solr query, queries the active_fedora solr instance' do
50
+ #get objects into fedora and solr
51
+ @test_object2 = MockAFBaseQuerySolr.new
52
+ @test_object2.new_object = true
53
+ attributes = {"holding_id"=>{0=>"Holding 1"},
54
+ "language"=>{0=>"Italian"},
55
+ "creator"=>{0=>"Linguist, A."},
56
+ "geography"=>{0=>"Italy"},
57
+ "title"=>{0=>"Italian and Spanish: A Comparison of Common Phrases"}}
58
+ @test_object2.update_indexed_attributes(attributes)
59
+ @test_object2.save
60
+
61
+ @test_object3 = MockAFBaseQuerySolr.new
62
+ @test_object3.new_object = true
63
+ attributes = {"holding_id"=>{0=>"Holding 2"},
64
+ "language"=>{0=>"Spanish;Latin"},
65
+ "creator"=>{0=>"Linguist, A."},
66
+ "geography"=>{0=>"Spain"},
67
+ "title"=>{0=>"A study of the evolution of Spanish from Latin"}}
68
+ @test_object3.update_indexed_attributes(attributes)
69
+ @test_object3.save
70
+
71
+ @test_object4 = MockAFBaseQuerySolr.new
72
+ @test_object4.new_object = true
73
+ attributes = {"holding_id"=>{0=>"Holding 3"},
74
+ "language"=>{0=>"Spanish;Latin"},
75
+ "creator"=>{0=>"Linguist, A."},
76
+ "geography"=>{0=>"Spain"},
77
+ "title"=>{0=>"An obscure look into early nomadic tribes of Spain"}}
78
+ @test_object4.update_indexed_attributes(attributes)
79
+ @test_object4.save
80
+
81
+ #query based on just model
82
+ results = MockAFBaseQuerySolr.find_by_fields_by_solr({})
83
+ found_pids = []
84
+ results.hits.each do |hit|
85
+ found_pids.push(hit[SOLR_DOCUMENT_ID])
86
+ end
87
+
88
+ found_pids.should == [@test_object2.pid,@test_object3.pid,@test_object4.pid]
89
+
90
+ #query on certain fields
91
+ results = MockAFBaseQuerySolr.find_by_fields_by_solr({"language"=>"Latin"})
92
+ found_pids = []
93
+ results.hits.each do |hit|
94
+ found_pids.push(hit[SOLR_DOCUMENT_ID])
95
+ end
96
+
97
+ found_pids.should == [@test_object3.pid,@test_object4.pid]
98
+
99
+ results = MockAFBaseQuerySolr.find_by_fields_by_solr({"language"=>"Italian"})
100
+ found_pids = []
101
+ results.hits.each do |hit|
102
+ found_pids.push(hit[SOLR_DOCUMENT_ID])
103
+ end
104
+
105
+ found_pids.should== [@test_object2.pid]
106
+
107
+ results = MockAFBaseQuerySolr.find_by_fields_by_solr({"language"=>"Spanish"})
108
+ found_pids = []
109
+ results.hits.each do |hit|
110
+ found_pids.push(hit[SOLR_DOCUMENT_ID])
111
+ end
112
+
113
+ found_pids.should == [@test_object3.pid,@test_object4.pid]
114
+
115
+ #assume spaces removed at index time so query by 'Linguist,A.' instead of 'Linguist, A.'
116
+ results = MockAFBaseQuerySolr.find_by_fields_by_solr({"creator"=>"Linguist,A."})
117
+ found_pids = []
118
+ results.hits.each do |hit|
119
+ found_pids.push(hit[SOLR_DOCUMENT_ID])
120
+ end
121
+
122
+ found_pids.should == [@test_object2.pid,@test_object3.pid,@test_object4.pid]
123
+
124
+ results = MockAFBaseQuerySolr.find_by_fields_by_solr({"geography"=>"Italy"})
125
+ found_pids = []
126
+ results.hits.each do |hit|
127
+ found_pids.push(hit[SOLR_DOCUMENT_ID])
128
+ end
129
+
130
+ found_pids.should == [@test_object2.pid]
131
+
132
+ results = MockAFBaseQuerySolr.find_by_fields_by_solr({"creator"=>"Linguist,A.","title"=>"latin"})
133
+ found_pids = []
134
+ results.hits.each do |hit|
135
+ found_pids.push(hit[SOLR_DOCUMENT_ID])
136
+ end
137
+
138
+ found_pids.should == [@test_object3.pid]
139
+
140
+ #query with value with embedded ':' (pid)
141
+ results = MockAFBaseQuerySolr.find_by_fields_by_solr({"id"=>@test_object3.pid})
142
+ found_pids = []
143
+ results.hits.each do |hit|
144
+ found_pids.push(hit[SOLR_DOCUMENT_ID])
145
+ end
146
+
147
+ found_pids.should == [@test_object3.pid]
148
+
149
+ #query with different options
150
+ #sort defaults to system_create_date
151
+ results = MockAFBaseQuerySolr.find_by_fields_by_solr({"creator"=>"Linguist,A.","language"=>"Spanish"})
152
+ found_pids = []
153
+ results.hits.each do |hit|
154
+ found_pids.push(hit[SOLR_DOCUMENT_ID])
155
+ end
156
+
157
+ found_pids.should == [@test_object3.pid,@test_object4.pid]
158
+
159
+ #change sort direction
160
+ results = MockAFBaseQuerySolr.find_by_fields_by_solr({"creator"=>"Linguist,A."},{:sort=>[{"system_create"=>"desc"}]})
161
+ found_pids = []
162
+ results.hits.each do |hit|
163
+ found_pids.push(hit[SOLR_DOCUMENT_ID])
164
+ end
165
+
166
+ found_pids.should == [@test_object4.pid,@test_object3.pid,@test_object2.pid]
167
+
168
+ #pass in sort without direction defined and make ascending by default
169
+ results = MockAFBaseQuerySolr.find_by_fields_by_solr({"creator"=>"Linguist,A."},{:sort=>["system_create"]})
170
+ found_pids = []
171
+ results.hits.each do |hit|
172
+ found_pids.push(hit[SOLR_DOCUMENT_ID])
173
+ end
174
+
175
+ found_pids.should == [@test_object2.pid,@test_object3.pid,@test_object4.pid]
176
+
177
+ #sort on multiple fields
178
+ results = MockAFBaseQuerySolr.find_by_fields_by_solr({"creator"=>"Linguist,A."},{:sort=>["geography",{"system_create"=>"desc"}]})
179
+ found_pids = []
180
+ results.hits.each do |hit|
181
+ found_pids.push(hit[SOLR_DOCUMENT_ID])
182
+ end
183
+
184
+ found_pids.should == [@test_object2.pid,@test_object4.pid,@test_object3.pid]
185
+
186
+ #check appropriate logic for system_modified_date field name transformation
187
+ results = MockAFBaseQuerySolr.find_by_fields_by_solr({"creator"=>"Linguist,A."},{:sort=>["geography",{"system_mod"=>"desc"}]})
188
+ found_pids = []
189
+ results.hits.each do |hit|
190
+ found_pids.push(hit[SOLR_DOCUMENT_ID])
191
+ end
192
+
193
+ found_pids.should == [@test_object2.pid,@test_object4.pid,@test_object3.pid]
194
+
195
+ #check pass in rows values
196
+ results = MockAFBaseQuerySolr.find_by_fields_by_solr({"creator"=>"Linguist,A."},{:rows=>2})
197
+ found_pids = []
198
+ results.hits.each do |hit|
199
+ found_pids.push(hit[SOLR_DOCUMENT_ID])
200
+ end
201
+
202
+ found_pids.should == [@test_object2.pid,@test_object3.pid]
203
+
204
+ #check query with field mapping to solr field and with solr field that is not a field in object
205
+ #should be able to query by either active fedora model field name or solr key name
206
+ results = MockAFBaseQuerySolr.find_by_fields_by_solr({"geography_t"=>"Italy"})
207
+ found_pids = []
208
+ results.hits.each do |hit|
209
+ found_pids.push(hit[SOLR_DOCUMENT_ID])
210
+ end
211
+
212
+ found_pids.should == [@test_object2.pid]
213
+ end
214
+ end
215
+ end