shelver 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ .DS_Store
2
+ nohup.out
3
+
4
+ *.sqlite3
5
+ *.log
6
+ *~
7
+ *.swp
8
+
9
+ pkg/
10
+ coverage/*
11
+
12
+ tmp/**/*
13
+ tmp/performance
14
+
15
+ rerun.txt
16
+
17
+ .loadpath
18
+ .project
19
+ .buildpath
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Matt Zumwalt
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = foo
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2010 Matt Zumwalt. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,45 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "shelver"
8
+ gem.summary = %Q{A utility for building solr indexes, usually from Fedora repository content.}
9
+ gem.description = %Q{Use shelver to populate solr indexes from Fedora repository content or from other sources. You can run shelver from within your apps, using the provided rake tasks, or as a JMS listener}
10
+ gem.email = "matt.zumwalt@yourmediashelf.com"
11
+ gem.homepage = "http://github.com/mediashelf/shelver"
12
+ gem.authors = ["Matt Zumwalt"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
36
+
37
+ require 'rake/rdoctask'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "shelver #{version}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -0,0 +1,4 @@
1
+ info:fedora/afmodel:SaltDocument : salt_document
2
+ info:fedora/afmodel:JP2Document : jp2_document
3
+ info:fedora/afmodel:ModsDocument : mods_document
4
+ info:fedora/afmodel:DCDocument : dc_document
data/config/solr.yml ADDED
@@ -0,0 +1,24 @@
1
+ staging:
2
+ default:
3
+ url: http://salt-dev.stanford.edu:8080/bl_solr/core0
4
+ fulltext:
5
+ url: http://salt-dev.stanford.edu:8080/bl_solr/core1
6
+ development:
7
+ default:
8
+ url: http://localhost:8080/bl_solr/core0
9
+ fulltext:
10
+ url: http://localhost:8080/bl_solr/core1
11
+ test: &TEST
12
+ default:
13
+ url: http://localhost:8080/bl_solr/core0
14
+ fulltext:
15
+ url: http://localhost:8080/bl_solr/core1
16
+ production:
17
+ default:
18
+ url: http://salt-dev.stanford.edu:8080/bl_solr/core0
19
+ fulltext:
20
+ url: http://salt-dev.stanford.edu:8080/bl_solr/core1
21
+ cucumber:
22
+ <<: *TEST
23
+ cucumber:
24
+ <<: *TEST
@@ -0,0 +1,8 @@
1
+
2
+ # FEDORA_URL = 'http://fedoraAdmin:fedoraAdmin@salt-dev.stanford.edu/fedora'
3
+ # FEDORA_SOLR_URL = 'http://salt-dev.stanford.edu:8080/solr'
4
+ # SHELVER_SOLR_URL = 'http://sulwebappdev1.stanford.edu:8100/salt_solr'
5
+ FEDORA_URL = 'http://fedoraAdmin:fedoraAdmin@localhost:8080/fedora'
6
+ FEDORA_SOLR_URL = 'http://localhost:8080/solr'
7
+ SHELVER_SOLR_URL = 'http://localhost:8080/bl_solr'
8
+
@@ -0,0 +1,89 @@
1
+ require 'solr'
2
+ require 'rexml/document'
3
+ require "nokogiri"
4
+ require 'yaml'
5
+
6
+ module Shelver
7
+ class Extractor
8
+
9
+
10
+ def extract_tags(text)
11
+ doc = REXML::Document.new( text )
12
+ extract_tag(doc, 'archivist_tags').merge(extract_tag(doc, 'donor_tags'))
13
+ end
14
+
15
+ def extract_tag(doc, type)
16
+ tags = doc.elements["/fields/#{type}"]
17
+ return {} unless tags
18
+ {type => tags.text.split(/,/).map {|t| t.strip}}
19
+ end
20
+
21
+
22
+ #
23
+ # Extracts content-model and hydra-type from RELS-EXT datastream
24
+ #
25
+ def extract_rels_ext( text, solr_doc=Solr::Document.new )
26
+ # TODO: only read in this file once
27
+
28
+ if defined?(RAILS_ROOT)
29
+ config_path = File.join(RAILS_ROOT, "config")
30
+ else
31
+ config_path = File.join(File.dirname(__FILE__), "..", "..", "config")
32
+ end
33
+ map = YAML.load(File.open(File.join(config_path, "hydra_types.yml")))
34
+
35
+ doc = Nokogiri::XML(text)
36
+ doc.xpath( '//foo:hasModel', 'foo' => 'info:fedora/fedora-system:def/model#' ).each do |element|
37
+ cmodel = element.attributes['resource'].to_s
38
+ solr_doc << Solr::Field.new( :cmodel_t => cmodel )
39
+
40
+ if map.has_key?(cmodel)
41
+ solr_doc << Solr::Field.new( :hydra_type_t => map[cmodel] )
42
+ end
43
+ end
44
+
45
+ return solr_doc
46
+ end
47
+
48
+ #
49
+ # This method extracts solr fields from simple xml
50
+ #
51
+ def xml_to_solr( text, solr_doc=Solr::Document.new )
52
+ doc = REXML::Document.new( text )
53
+ doc.root.elements.each do |element|
54
+ solr_doc << Solr::Field.new( :"#{element.name}_t" => "#{element.text}" )
55
+ end
56
+
57
+ return solr_doc
58
+ end
59
+
60
+ #
61
+ # This method strips html tags out and returns content to be indexed in solr
62
+ #
63
+ def html_content_to_solr( ds, solr_doc=Solr::Document.new )
64
+
65
+ text = CGI.unescapeHTML(ds.content)
66
+ doc = Nokogiri::HTML(text)
67
+
68
+ # html to story_display
69
+ stories = doc.xpath('//story')
70
+
71
+ stories.each do |story|
72
+ solr_doc << Solr::Field.new(:story_display => story.children.to_xml)
73
+ end
74
+
75
+ #strip out text and put in story_t
76
+ text_nodes = doc.xpath("//text()")
77
+ text = String.new
78
+
79
+ text_nodes.each do |text_node|
80
+ text << text_node.content
81
+ end
82
+
83
+ solr_doc << Solr::Field.new(:story_t => text)
84
+
85
+ return solr_doc
86
+ end
87
+
88
+ end
89
+ end
@@ -0,0 +1,251 @@
1
+ require 'solr'
2
+ require 'shelver/extractor'
3
+ require 'shelver/repository'
4
+
5
+
6
+ module Shelver
7
+ class Indexer
8
+ #
9
+ # Class variables
10
+ #
11
+ @@unique_id = 0
12
+
13
+ def self.unique_id
14
+ @@unique_id
15
+ end
16
+
17
+ #
18
+ # Member variables
19
+ #
20
+ attr_accessor :connection, :extractor, :index_full_text
21
+
22
+ #
23
+ # This method performs initialization tasks
24
+ #
25
+ def initialize( opts={} )
26
+ @@index_list = false unless defined?(@@index_list)
27
+ @extractor = Extractor.new
28
+
29
+ if opts[:index_full_text] == true || opts[:index_full_text] == "true"
30
+ @index_full_text = true
31
+ else
32
+ @index_full_text = false
33
+ end
34
+
35
+ connect
36
+ end
37
+
38
+ #
39
+ # This method connects to the Solr instance
40
+ #
41
+ def connect
42
+
43
+ if defined?(Blacklight)
44
+ solr_config = Blacklight.solr_config
45
+ else
46
+
47
+ if defined?(RAILS_ROOT)
48
+ config_path = File.join(RAILS_ROOT, "config")
49
+ yaml = YAML.load(File.open(File.join(config_path, "solr.yml")))
50
+ solr_config = yaml[RAILS_ENV]
51
+ else
52
+ config_path = File.join(File.dirname(__FILE__), "..", "..", "config")
53
+ yaml = YAML.load(File.open(File.join(config_path, "solr.yml")))
54
+
55
+
56
+ if ENV["environment"].nil?
57
+ environment = "development"
58
+ else
59
+ environment = ENV["environment"]
60
+ end
61
+
62
+ solr_config = yaml[environment]
63
+ puts solr_config.inspect
64
+ end
65
+
66
+ end
67
+
68
+ if index_full_text == true
69
+ url = solr_config['fulltext']['url']
70
+ else
71
+ url = solr_config['default']['url']
72
+ end
73
+ @connection = Solr::Connection.new(url, :autocommit => :on )
74
+ end
75
+
76
+ #
77
+ # This method extracts the facet categories from the given Fedora object's external tag datastream
78
+ #
79
+ def extract_xml_to_solr( obj, ds_name, solr_doc=Solr::Document.new )
80
+ xml_ds = Repository.get_datastream( obj, ds_name )
81
+ extractor.xml_to_solr( xml_ds.content, solr_doc )
82
+ end
83
+
84
+ #
85
+ #
86
+ #
87
+ def extract_rels_ext( obj, ds_name, solr_doc=Solr::Document.new )
88
+ rels_ext_ds = Repository.get_datastream( obj, ds_name )
89
+ extractor.extract_rels_ext( rels_ext_ds.content, solr_doc )
90
+ end
91
+
92
+ #
93
+ # This method generates the month and day facets from the date_t in solr_doc
94
+ #
95
+
96
+ def generate_dates(solr_doc)
97
+
98
+ # This will check for valid dates, but it seems most of the dates are currently invalid....
99
+ #date_check = /^(19|20)\d\d([- \/.])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])/
100
+
101
+ #if there is not date_t, add on with easy-to-find value
102
+ if solr_doc[:date_t].nil?
103
+ solr_doc << Solr::Field.new( :date_t => "9999-99-99")
104
+ end #if
105
+
106
+ # unless date_check !~ solr_doc[:date_t]
107
+ date_obj = Date._parse(solr_doc[:date_t])
108
+
109
+ if date_obj[:mon].nil?
110
+ solr_doc << Solr::Field.new(:month_facet => 99)
111
+ elsif 0 < date_obj[:mon] && date_obj[:mon] < 13
112
+ solr_doc << Solr::Field.new( :month_facet => date_obj[:mon].to_s.rjust(2, '0'))
113
+ else
114
+ solr_doc << Solr::Field.new( :month_facet => 99)
115
+ end
116
+
117
+ if date_obj[:mday].nil?
118
+ solr_doc << Solr::Field.new( :day_facet => 99)
119
+ elsif 0 < date_obj[:mday] && date_obj[:mday] < 32
120
+ solr_doc << Solr::Field.new( :day_facet => date_obj[:mday].to_s.rjust(2, '0'))
121
+ else
122
+ solr_doc << Solr::Field.new( :day_facet => 99)
123
+ end
124
+
125
+ return solr_doc
126
+ # end
127
+
128
+ end
129
+
130
+
131
+ #
132
+ # This method creates a Solr-formatted XML document
133
+ #
134
+ def create_document( obj )
135
+
136
+ # retrieve a comprehensive list of all the datastreams associated with the given
137
+ # object and categorize each datastream based on its filename
138
+ ext_properties_ds_names, rels_ext_names, properties_ds_names, stories_ds_names, full_text_ds_names, xml_ds_names, jp2_ds_names, = [],[],[],[],[],[],[],[]
139
+ ds_names = Repository.get_datastreams( obj )
140
+
141
+ ds_names.each do |ds_name|
142
+ if ds_name =~ /descMetadata/
143
+ xml_ds_names << ds_name
144
+ elsif ds_name =~ /^properties/
145
+ properties_ds_names << ds_name
146
+ xml_ds_names << ds_name
147
+ elsif ds_name =~ /^RELS-EXT/
148
+ rels_ext_names << ds_name
149
+ end
150
+ end
151
+
152
+ # create the Solr document
153
+ solr_doc = Solr::Document.new
154
+ solr_doc << Solr::Field.new( :id => "#{obj.pid}" )
155
+ solr_doc << Solr::Field.new( :id_t => "#{obj.pid}" )
156
+
157
+
158
+ # Pass the solr_doc through extract_simple_xml_to_solr
159
+ xml_ds_names.each { |ds_name| extract_xml_to_solr(obj, ds_name, solr_doc)}
160
+
161
+ # Generate month_facet and day_facet from date_t value
162
+ generate_dates(solr_doc)
163
+
164
+ # extract RELS-EXT
165
+ rels_ext_names.each { |ds_name| extract_rels_ext(obj, ds_name, solr_doc)}
166
+
167
+ # increment the unique id to ensure that all documents in the search index are unique
168
+ @@unique_id += 1
169
+
170
+ return solr_doc
171
+ end
172
+
173
+ #
174
+ # This method adds a document to the Solr search index
175
+ #
176
+ def index( obj )
177
+ # print "Indexing '#{obj.pid}'..."
178
+ begin
179
+
180
+ solr_doc = create_document( obj )
181
+ connection.add( solr_doc )
182
+
183
+ # puts connection.url
184
+ #puts solr_doc
185
+ # puts "done"
186
+
187
+ rescue Exception => e
188
+ p "unable to index #{obj.pid}. Failed with #{e.inspect}"
189
+ end
190
+
191
+ end
192
+
193
+ #
194
+ # This method queries the Solr search index and returns a response
195
+ #
196
+ def query( query_str )
197
+ response = conn.query( query_str )
198
+ end
199
+
200
+ #
201
+ # This method prints out the results of the given query string by iterating through all the hits
202
+ #
203
+ def printResults( query_str )
204
+ query( query_str ) do |hit|
205
+ puts hit.inspect
206
+ end
207
+ end
208
+
209
+ #
210
+ # This method deletes a document from the Solr search index by id
211
+ #
212
+ def deleteDocument( id )
213
+ connection.delete( id )
214
+ end
215
+
216
+ # Populates a solr doc with values from a hash.
217
+ # Accepts two forms of hashes:
218
+ # => {'technology'=>["t1", "t2"], 'company'=>"c1", "person"=>["p1", "p2"]}
219
+ # or
220
+ # => {:facets => {'technology'=>["t1", "t2"], 'company'=>"c1", "person"=>["p1", "p2"]} }
221
+ #
222
+ # Note that values for individual fields can be a single string or an array of strings.
223
+ def self.solrize( input_hash, solr_doc=Solr::Document.new )
224
+ facets = input_hash.has_key?(:facets) ? input_hash[:facets] : input_hash
225
+ facets.each_pair do |facet_name, value|
226
+ case value.class.to_s
227
+ when "String"
228
+ solr_doc << Solr::Field.new( :"#{facet_name}_facet" => "#{value}" )
229
+ when "Array"
230
+ value.each { |v| solr_doc << Solr::Field.new( :"#{facet_name}_facet" => "#{v}" ) }
231
+ end
232
+ end
233
+
234
+ if input_hash.has_key?(:symbols)
235
+ input_hash[:symbols].each do |symbol_name, value|
236
+ case value.class.to_s
237
+ when "String"
238
+ solr_doc << Solr::Field.new( :"#{symbol_name}_s" => "#{value}" )
239
+ when "Array"
240
+ value.each { |v| solr_doc << Solr::Field.new( :"#{symbol_name}_s" => "#{v}" ) }
241
+ end
242
+ end
243
+ end
244
+ return solr_doc
245
+ end
246
+
247
+
248
+ private :connect, :create_document
249
+
250
+ end
251
+ end
@@ -0,0 +1,17 @@
1
+ #!/bin/env ruby
2
+
3
+ @index_full_text = false
4
+
5
+ require 'rubygems'
6
+ load 'configuration.rb'
7
+ load 'repository.rb'
8
+ load 'shelver.rb'
9
+
10
+ # initialize connection to Fedora repository
11
+ repository = Repository.new
12
+ repository.initialize_repository
13
+
14
+ # shelve all objects in the Fedora repository
15
+ shelver = Shelver.new
16
+ shelver.shelve_objects
17
+
@@ -0,0 +1,143 @@
1
+ require 'fastercsv'
2
+ REPLICATOR_LIST = false unless defined?(REPLICATOR_LIST)
3
+
4
+
5
+ module Shelver
6
+ class Replicator
7
+
8
+ include Stanford::SaltControllerHelper
9
+ attr_accessor :dest_repo, :configs
10
+
11
+ def initialize
12
+ config_path = "#{RAILS_ROOT}/config/replicator.yml"
13
+ raw_configs = YAML::load(File.open(config_path))
14
+ @configs = raw_configs[RAILS_ENV]
15
+ @dest_repo = Fedora::Repository.new(configs["destination"]["fedora"]["url"])
16
+
17
+ ActiveFedora.fedora_config[:url] = configs["source"]["fedora"]["url"]
18
+ logger.info("REPLICATOR: re-initializing Fedora with fedora_config: #{ActiveFedora.fedora_config.inspect}")
19
+
20
+ Fedora::Repository.register(ActiveFedora.fedora_config[:url])
21
+ logger.info("REPLICATOR: re-initialized Fedora as: #{Fedora::Repository.instance.inspect}")
22
+
23
+ # Register Solr
24
+ ActiveFedora.solr_config[:url] = configs["source"]["solr"]["url"]
25
+
26
+ logger.info("REPLICATOR: re-initializing ActiveFedora::SolrService with solr_config: #{ActiveFedora.solr_config.inspect}")
27
+
28
+ ActiveFedora::SolrService.register(ActiveFedora.solr_config[:url])
29
+
30
+ end
31
+
32
+ def replicate_objects
33
+ # retrieve a list of all the pids in the fedora repository
34
+ num_docs = 1000000 # modify this number to guarantee that all the objects are retrieved from the repository
35
+
36
+ if REPLICATOR_LIST == false
37
+
38
+ pids = Repository.get_pids( num_docs )
39
+ puts "Replicating #{pids.length} Fedora objects"
40
+ pids.each do |pid|
41
+ unless pid[0].empty? || pid[0].nil? || !pid[0].include?("druid:")
42
+ puts "Processing #{pid}"
43
+ replicate_object( pid )
44
+ end #unless
45
+ end #pids.each
46
+
47
+ else
48
+
49
+ if File.exists?(REPLICATOR_LIST)
50
+ arr_of_pids = FasterCSV.read(REPLICATOR_LIST, :headers=>false)
51
+
52
+ puts "Replicating from list at #{REPLICATOR_LIST}"
53
+ puts "Replicating #{arr_of_pids.length} Fedora objects"
54
+
55
+ arr_of_pids.each do |row|
56
+ pid = row[0]
57
+ replicate_object( pid )
58
+ end #FASTERCSV
59
+
60
+ else
61
+ puts "#{REPLICATOR_LIST} does not exists!"
62
+ end #if File.exists
63
+
64
+ end #if Index_LISTS
65
+ end #replicate_objects
66
+
67
+
68
+ def replicate_object(obj)
69
+ #source_doc = Document.load_instance(pid)
70
+ obj = obj.kind_of?(ActiveFedora::Base) ? obj : Repository.get_object( obj )
71
+ p "Indexing object #{obj.pid} with label #{obj.label}"
72
+ begin
73
+ unless obj.nil?
74
+ create_stub(obj)
75
+ p "Successfully replicated #{obj.pid}"
76
+ end
77
+ rescue Exception => e
78
+ p "unable to create stub. Failed with #{e.inspect}"
79
+ end
80
+ end
81
+
82
+ # Creates a stub object in @dest_repo with the datastreams that we need in the stubs
83
+ def create_stub(source_object)
84
+
85
+ begin
86
+
87
+ jp2 = downloadables(source_object, :canonical=>true, :mime_type=>"image/jp2")
88
+ jp2.new_object = true
89
+ jp2.control_group = 'M'
90
+ jp2.blob = jp2.content
91
+
92
+ stub_object = Fedora::FedoraObject.new(:pid=>source_object.pid)
93
+ dest_repo.save(stub_object)
94
+ dest_repo.save(jp2)
95
+
96
+ ["properties", "extProperties", "descMetadata", "location"].each do |ds_name|
97
+ ds = source_object.datastreams[ds_name]
98
+ ds.new_object = true
99
+ ds.blob = ds.content
100
+ dest_repo.save(ds)
101
+ end
102
+
103
+ rescue
104
+ #for object without jp2s
105
+ #this is a temp fix to the downloadables() issue
106
+
107
+
108
+ pid = source_object.pid
109
+ p "> #{pid}"
110
+
111
+ jp2_file = File.new('spec/fixtures/image.jp2')
112
+ ds = ActiveFedora::Datastream.new(:dsID => "image.jp2", :dsLabel => 'image.jp2', :controlGroup => 'M', :blob => jp2_file)
113
+ source_object.add_datastream(ds)
114
+ source_object.save
115
+ # source_object = Document.load_instance(pid)
116
+ source_object = ActiveFedora::Base.load_instance(pid)
117
+ stub_object = Fedora::FedoraObject.new(:pid=>source_object.pid)
118
+ dest_repo.save(stub_object)
119
+
120
+ jp2 = downloadables(source_object, :canonical=>true, :mime_type=>"image/jp2")
121
+ jp2.new_object = true
122
+ jp2.control_group = 'M'
123
+ jp2.blob = jp2.content
124
+
125
+ stub_object = Fedora::FedoraObject.new(:pid=>source_object.pid)
126
+ dest_repo.save(stub_object)
127
+ dest_repo.save(jp2)
128
+
129
+ ["properties", "extProperties", "descMetadata", "location"].each do |ds_name|
130
+ ds = source_object.datastreams[ds_name]
131
+ ds.new_object = true
132
+ ds.blob = ds.content
133
+ dest_repo.save(ds)
134
+ end
135
+
136
+ end
137
+ end
138
+ def logger
139
+ @logger ||= defined?(RAILS_DEFAULT_LOGGER) ? RAILS_DEFAULT_LOGGER : Logger.new(STDOUT)
140
+ end
141
+
142
+ end
143
+ end