shelver 0.0.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.
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