Class: FileStore::SimpleFileStore

Inherits:
Object
  • Object
show all
Includes:
Logger, OberservedSubject
Defined in:
lib/filestore/simple_store.rb

Overview

Main library class implementing a simple file store used for storing and managing arbitrary files

Constant Summary collapse

STORE_LOCK_FILE =

Name of the lock file

".locked"
META_FILE =

Name of the meta file describing the current file store

"filestore.yaml"
STORE_ROOT =

The base name of the file store directory

'filestore'
DELETED_ROOT =

The base name of the directory for storing deleted files

'deleted'
ROLLBACK_ROOT =

The base name of the directory storing files extracted from file store by a rollback action

'rollback'

Instance Attribute Summary collapse

Attributes included from OberservedSubject

#observers

Attributes included from Logger

#logger

Class Method Summary collapse

Instance Method Summary collapse

Methods included from OberservedSubject

included, #inform, #initialize_obs, #register, #unregister

Constructor Details

#initialize(metaManager, rootPath = '.', logger) ⇒ SimpleFileStore

Initializes a new instance of SimpleFileStore

Arguments: metaManager: The meta data manager instance to be used by this store rootPath: The path where the file store resides

Raises:



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/filestore/simple_store.rb', line 43

def initialize(metaManager, rootPath = '.', logger)
	raise FileStoreException, "Root path already locked" if SimpleFileStore.is_directory_locked?(rootPath)		
	raise FileStoreException, "FileStore root path #{rootPath} doesn't exist" if not File.directory?(rootPath)
	raise FileStoreException, "FileStore root path #{rootPath} isn't writable" if not File.writable?(rootPath)
	raise FileStoreException, "No meta data manager given" if metaManager.nil?
	raise FileStoreException, "Meta data manager must be of type FileStore::MetaManager" if not metaManager.is_a?(MetaManager)
	
	@metaManager = metaManager
	@rootPath = rootPath
	@storePath = File.join(@rootPath, STORE_ROOT)
	@deletedPath = File.join(@rootPath, DELETED_ROOT)
	@rollbackPath = File.join(@rootPath, ROLLBACK_ROOT)
	@metaFile = File.join(@rootPath, META_FILE)
	@locked = false
	@logger = logger
	
	self.initialize_obs
	
	begin
		# Try to recover existing store
		SimpleFileStore.recover_store(self)
	rescue FileStoreException => e
		# Recovery failed, trying to create the store
		SimpleFileStore.create_store(self)
	end
	
	lock
end

Instance Attribute Details

#deletedPathObject (readonly)

Accessors for important properties



35
36
37
# File 'lib/filestore/simple_store.rb', line 35

def deletedPath
  @deletedPath
end

#metaFileObject (readonly)

Accessors for important properties



35
36
37
# File 'lib/filestore/simple_store.rb', line 35

def metaFile
  @metaFile
end

#metaManagerObject (readonly)

Accessors for important properties



35
36
37
# File 'lib/filestore/simple_store.rb', line 35

def metaManager
  @metaManager
end

#rollbackPathObject (readonly)

Accessors for important properties



35
36
37
# File 'lib/filestore/simple_store.rb', line 35

def rollbackPath
  @rollbackPath
end

#rootPathObject (readonly)

Accessors for important properties



35
36
37
# File 'lib/filestore/simple_store.rb', line 35

def rootPath
  @rootPath
end

#storePathObject (readonly)

Accessors for important properties



35
36
37
# File 'lib/filestore/simple_store.rb', line 35

def storePath
  @storePath
end

Class Method Details

.create_store(store) ⇒ Object

Setup for a new file store directory

Arguments: store: The file store instance to set up



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
# File 'lib/filestore/simple_store.rb', line 277

def self.create_store(store)
	# Try to create needed directories
	begin
		FileUtils.mkdir [store.storePath, store.deletedPath, store.rollbackPath]
	rescue Errno::ENOENT => e
		raise FileStoreException, "One ore more system directories couldn't be created.\n#{e.message}"
	end
	# Try to create hidden meta file
	begin
		meta = { :created_at => Date.today.strftime('%d.%m.%Y %H:%M:%S:%L'), 
			:storePath => store.storePath,
			:deletedPath => store.deletedPath,
			:rollbackPath => store.rollbackPath,
			:created_by => Etc.getlogin
		}
		
		File.open(store.metaFile, "w+") do |fh|
			YAML.dump(meta, fh)
		end
		
		#
		# Creation was successful
		#
	rescue Exception => e
		raise FileStoreException, "Meta file #{store.metaFile} couldn't be created.\n#{e.message}"
	end
end

.get_daily_directory(base) ⇒ Object

Returns the currently used directory

Raises:



258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/filestore/simple_store.rb', line 258

def self.get_daily_directory(base)
	date = Date.today
	dir = File.join(base, date.year.to_s, date.month.to_s, date.day.to_s)
	
	begin
		FileUtils.mkdir_p(dir) if not File.directory?(dir)
	rescue Exception => e
		raise FileStoreException, "Can't create daily directory #{dir}.\n#{e.message}"
	end
	
	raise FileStoreException, "Daily directory #{dir} isn't writable" if not File.writable?(dir)
	return dir
end

.get_id(store) ⇒ Object

Creates a new file ID

Returns: A string representing the file’s ID

Raises:



246
247
248
249
250
251
252
253
254
# File 'lib/filestore/simple_store.rb', line 246

def self.get_id(store)
	for i in 0..2 do	
		id = UUIDTools::UUID.random_create.to_s
		
		return id if not store.metaManager.has_id?(id) 
	end
	
	raise FileStoreException, "Couldn't find unique ID"
end

.is_directory_locked?(rootPath) ⇒ Boolean

Determines wether the store path is already locked by another instance of SimpleFileStore

Returns:

  • (Boolean)


237
238
239
# File 'lib/filestore/simple_store.rb', line 237

def self.is_directory_locked?(rootPath)
	return File.exists?(File.join(rootPath, SimpleFileStore::STORE_LOCK_FILE))
end

.recover_store(store) ⇒ Object

Recover an existing file store

Arguments: store: The file store instance to recover



310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/filestore/simple_store.rb', line 310

def self.recover_store(store)
	# trying to recover existing file store
	begin
		meta = YAML.load_file(store.metaFile)
		
		raise FileStoreException, "Store directory not found" if not File.directory?(meta[:storePath])
		raise FileStoreException, "Deleted directory not found" if not File.directory?(meta[:deletedPath])
		raise FileStoreException, "Rollback directory not found" if not File.directory?(meta[:rollbackPath])
		
		#
		# Recovery was successful
		#
	rescue Exception => e
		raise FileStoreException, "Unable to recover file store from path #{store.rootPath}.\n#{e.message}"
	end
end

Instance Method Details

#add(file, meta = {}, shouldMove = true) ⇒ Object

Adds a file to the store

Arguments: file: The file to be stored meta: Optional meta data to be stored along with the physical file shouldMove: Determines wether to original file should be deleted

Returns:

The newly created ID for the file

Raises:



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/filestore/simple_store.rb', line 82

def add(file, meta = {}, shouldMove = true)
	raise FileStoreException, "File #{file} not found" if not File.exists?(file)
	raise FileStoreException, "File #{file} isn't readable" if not File.readable?(file)
	raise FileStoreException, "File #{file} can't be removed" if not File.writable?(file)
	
	meta = {} if meta.nil?
	id = ""
	
	begin
		dir = SimpleFileStore.get_daily_directory(@storePath)
		@logger.info "Adding file #{file} to directory #{dir}"
		id = SimpleFileStore.get_id(self)
		@logger.info "Using file id #{id}"
		dstPath = File.join(dir, id)
		@logger.info "Created destination path #{dstPath}"
		
		shouldMove ? (@logger.info("Moving file"); FileUtils.mv(file, dstPath)) : 
			(@logger.info("Copying file"); FileUtils.copy_file(file, dstPath))
		
		self.inform ObserverAction.new(:type => ObserverAction::TYPE_STORE_ADD, 
        :objects => [file, meta], :msg => "Added file to file store")
	rescue Exception => e
		raise FileStoreException, "Couldn't add file #{file} to store.", e.backtrace
	end
	
	meta[:path] = dstPath
	@metaManager.add_or_update(id, meta)
	
	return id
end

#get(id) ⇒ Object

Retrieves a file identified by it’s ID

Arguments: id: The files ID to retrieve

Returns: A hash of file object (:path) and corresponding meta data (:data) representing the file in the store

Raises:



122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/filestore/simple_store.rb', line 122

def get(id)
	raise FileStoreException, "No ID given" if id.nil? or id == ''
	raise FileStoreException, "No file for ID #{id} found" if not @metaManager.has_id?(id)
	
	md = @metaManager.get_data(id)
	path = md[:path]

	raise FileStoreException, "No valid meta data found for ID #{id}" if md.nil? or not File.exists?(path)
	
	self.inform ObserverAction.new :type => ObserverAction::TYPE_STORE_GET, 
      :objects => [id], :msg => "Returning file from file store"
	
	return { :path => File.new(path), :data => md }
end

#locked?Boolean

Determines wether this store is locked

Returns:

  • (Boolean)


204
205
206
# File 'lib/filestore/simple_store.rb', line 204

def locked?
	return @locked
end

#remove(id) ⇒ Object

Moves a file from the current to the deleted store

Arguments: id: The ID identifying the file to be moved

Raises:



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/filestore/simple_store.rb', line 142

def remove(id)
	raise FileStoreException, "No file ID given for removal" if id == '' or id.nil?
	raise FileStoreException, "File ID for removal not found in store" if not @metaManager.has_id?(id)
	
	file = @metaManager.get_data(id)[:path]
	
	begin
		@metaManager.remove(id)
		
		dir = SimpleFileStore.get_daily_directory(@deletedPath)
		dstPath = File.join(dir, id)
		
		FileUtils.move(file, dstPath)
		
		self.inform ObserverAction.new :type => ObserverAction::TYPE_STORE_REMOVE, 
        :objects => [id], :msg => "Deleted file from store"
	rescue Exception => e
		raise FileStoreException, "Couldn't move file #{file} to deleted store.\n#{e.message}"
	end
end

#restore(id) ⇒ Object

Restores a file identified by it’s id

Arguments: id: The file ID

Raises:



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/filestore/simple_store.rb', line 168

def restore(id)
	raise FileStoreException, "No file ID given for restore" if id == '' or id.nil?
	
	begin
	  md = @metaManager.restore id
      @logger.debug "Restoring meta data #{md}"
      file = md[:path]
      
		dir = SimpleFileStore.get_daily_directory(@storePath)
		dstPath = File.join(dir, id)
		
		FileUtils.move(file, dstPath)
		
		self.inform ObserverAction.new :type => ObserverAction::TYPE_STORE_RESTORE, 
        :objects => [id], :msg => "Restored file from store"
	rescue Exception => e
		raise FileStoreException, "Couldn't restore file #{file} from deleted store.\n#{e.message}"
		#
		# Delete restored entry from metaManager
		@metaManager.delete(id)
	end
end

#shutdownObject

Shuts down the file store



193
194
195
196
197
198
199
200
# File 'lib/filestore/simple_store.rb', line 193

def shutdown
	@metaManager.shutdown
	
	release_lock
	
	self.inform ObserverAction.new :type => ObserverAction::TYPE_STORE_SHUTDOWN, 
      :msg => "File store shutdown"
end