require 'assit' require 'semantic_naming' require 'active_rdf' require 'fileutils' module TaliaCore # The TaliaCore initializer is responsible for setting up the Talia core # system, e.g. making the neccessary connections, setting up the # basic namespaces, etc. # # The basic mechanism works like the Rails initializer: Options can be # added to the Hash in a block that is passed to the run method of the # intializers. # # There are two settings that can be made before the configuration is started: # # <tt>environmemnt</tt> is used to define the environment. This is used to # select the configuration options from the files. This option will default # to <tt>ENV['RAILS_ENV']</tt> if Talia runs in Rails. Otherwise the default # will be "development". # # <tt>talia_root</tt> is the root directory for the Talia installation. If # unset, the will default to <tt>RAILS_ROOT</tt> in Rails and to the current # directory if Talia is used as a standalone module. This will be used to find # the configuration and data files. # # Usually these options need only to be set if running Talia standalone. In # this case, assign <tt>TaliaCore::Initializer.talia_root</tt> and/or # <tt>TaliaCore::Initializer.environment</tt> before running the # configuration. # # The options may also be stored in a configuration file; the name of # the file is passed to the initializer. # # = Example config # # # If working with Rails, this code goes to the environment.rb # # # Set the root directory (optional, for Rails it's automatic) # TaliaCore::Initializer.talia_root = "/my_directory/my_talia_root/" # # Set the environment (optional, automatic for rails) # TaliaCore::Initializer.environment = "development" # # # Run the initializer, giving a config file # # See the example config files for options # TaliaCore::Initializer.run("talia_core.yml") do |config| # # Give more confi options. These will overwrite the ones from the # # config file # config['standalone_db'] = "true" # end # # = Configuration options for <tt>talia_core.yml</tt> # # [*local_uri*] URL of the current installation. This should be set to # the URL where Talia is installed # [*rdf_connection_file*] Name of the configuration file that contains the # connection parameters for the RDF store. # [*rdf_connection*] Used to place the RDF options directly in the configuration # file. the *rdf_connection_file* setting will take precedence, # though. # [*db_file*] File with the database configuration for ActiveRecord. When running # from within RAILS, Talia will *always* use the Rails configuration # [*db_connection*] Used to place the DB options directly in the file. *db_file* # will take precedence, if present # [*standalone_db*] If set to true, Talia will be configured to use the ActiveRecord # database connection without Rails. # [*ardf_log_level*] Used to indicate the log level for the ActiveRDF library (integer value) # [*db_log*] Log file for the database/ActiveRecord. Does not take effect if # running from inside Rails # [*data_directory_location*] Root directory for the FileRecord file storage # [*namespaces*] Declares the namespaces that can be used within Talia # (a number of "namespace": "url" pairs) # [*iip_root_directory_location*] The directory that is used for the pyramidal files # that will be served by the IIP server # [*iip_server_uri*] The URI to the IIP server. When using the default server, this will # be the URL that calls the iipsrv.fcgi # [*vips_command*] Path to the "vips" command, which is used to create the pyramidal images # [*convert_command*] Path to the "convert" command from ImageMagick, which creates the thumbs # [*thumb_options*] Options for thumbnail images. These can contain "height", "width" and the # "force" option. If the "force" option is set, the thumbnails will be the # exact dimensions given (with a transparent background around the border). # Otherwise the aspect ratio of the image will be preserved. # [*environment*] The environment for the session, that is "development", "production" or "test". # If running from Rails, this will inherit Rails' setting # [*standalone_log*] Log file to be used when in standalone mode (not using Rails) # [*standalone_log_level*] Log level for the <tt>standalone_log</tt> # [*assert*] If true, the <tt>assit</tt> assertions are enabled in the code. Defaults to true. # [*auto_ontologies*] If set to a directory, Talia will automatically (re-)load the ontologies # from that directory on startup # [*site_name*] Site name string. May (or may not) be used in the application. class Initializer # Is used to set the root directory manually. Must be written before # the configuration is run. cattr_writer :talia_root # Is used to manually set the environment. Must be written before # the configuration is run. cattr_writer :environment # Indicates if the system has been initialized cattr_reader :initialized @@initialized ||= false # Indicates if the initialization was started, # but not finished cattr_reader :init_started @@init_started ||= false class << self # Runs the initialization. You can pass a block to this method, which # is run with one parameter: A hash containing the configuration. # # If a configuration file is given, the contents will be read before the # block is called, the block values will overwrite the settings from the # file. # # For now, the values are documented in the code below and in the default # configuration file. def run(config_file = nil, &initializer) raise(Errors::SystemInitializationError, "System cannot be initialized twice") if(@@initialized || @@init_started) @@init_started = true # Set the talia root first set_talia_root # Set the environmnet set_environment # Load the config file if one is given if(config_file) config_file_path = File.join(TALIA_ROOT, 'config', "#{config_file}.yml") @config = YAML::load(File.open(config_file_path)) else # Create the default configuration @config = create_default_config() end # Start logging set_logger # Set the logger talia_logger.info("TaliaCore initializing with environmnet #{@environment}") # Call the user code initializer.call(@config) if(initializer) # Initialize the database connection config_db # Initialize the ActiveRDF connection config_rdf # Configure the namespaces config_namespaces # Configure the data directory config_data_directory # Configure the iip root directory config_iip_root_directory # Configure the ontologies load_ontologies # Load the Ruby Core extensions load_core_ext # register the default mime types register_mime_types # set the $ASSERT flag if(@config["assert"]) $ASSERT = true end @@initialized = true # Set the environment to the configuration @config["environment"] = @@environment # Make the configuration available as a constant TaliaCore.const_set(:CONFIG, @config) talia_logger.info("TaliaCore initialization complete") end def talia_logger @logger end protected # Creates the default values for the config hash def create_default_config config = Hash.new # The name of the local node config["local_uri"] = "http://test.dummy/" # Connect options for ActiveRDF # Defaults to in-memory RDFLite config["rdf_connection"] = { :type => :rdflite } # Indicates if the DB backend (ActiveRecord) is # used "standalone", which means "outside" a # rails application. # For the standalone case, the Talia # initializer will make the database connections. # Otherwise, Rails will handle that. config["standalone_db"] = false # Configuration for standalone database connection config["db_connection"] = nil # Additional namespaces that will be registered at # startup. If present, this is expected to be a Hash with # :shortcut => URI pairs config["namespaces"] = nil # Whether to set the $ASSERT flag that activates the simple assertions config["assert"] = true # Where to find the data directory which will be contain the data config["data_directory_location"] = File.join(TALIA_ROOT, 'data') return config end # Creates a logger if no logger is defined # At the moment, this just creates a logger to the default director def set_logger @logger ||= if(defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER) RAILS_DEFAULT_LOGGER else log_name = @config['standalone_log'] || File.join(TALIA_ROOT, 'log', "talia_core_#{@environment}.log") log_level = @config['standalone_log_level'] ? Logger.const_get(@config['standalone_log_level']) : default_log_level FileUtils.makedirs(File.dirname(log_name)) logger = Logger.new(log_name) logger.level = log_level logger end end # Get the default log level for the standalone log def default_log_level case(@environment) when 'development', 'test': Logger::DEBUG else Logger::WARN end end # Set the Talia root directory first. Use the configured directory # if given, otherwise go for the RAILS_ROOT/current directory. def set_talia_root root = if(@@talia_root) @@talia_root elsif(defined?(RAILS_ROOT)) RAILS_ROOT else '.' end # Use the full path for the root Object.const_set(:TALIA_ROOT, File.expand_path(root)) end # Set the environmet to be used for config selection def set_environment if(@@environment) @environment = @@environment elsif(ENV['RAILS_ENV']) @environment = ENV['RAILS_ENV'] else @environment = "development" end @@environment = @environment end # Gets connection options from a file. The default_opts are the ones # that will be used if no file is given. If both file and default are given, # the method will overwrite the defaults. def connection_opts(default_opts, config_file) options = default_opts # First check for the file if(config_file) if(default_opts) talia_logger.warn("Database options will be overwritten by config file values.") end config_path = File.join(TALIA_ROOT, 'config', "#{config_file}.yml") options = YAML::load(File.open(config_path))[@environment] end options end # The connection options for the standalone database connection def db_connection_opts connection_opts(@config["db_connection"], @config["db_file"]) end # Configure the database connection def config_db # Initialize the database connection if(@config["standalone_db"]) talia_logger.info("TaliaCore using standalone database") ActiveRecord::Base.configurations['talia'] = db_connection_opts ActiveRecord::Base.establish_connection(:talia) ActiveRecord::Base.logger = talia_logger else talia_logger.info("TaliaCore using exisiting database connection.") unless(ActiveRecord::Base.logger) talia_logger.info("ActiveRecord logger not active, setting it to Talia logger") ActiveRecord::Base.logger = talia_logger end end talia_logger.info("Setting Active Record to full STI use.") unless(ActiveRecord::Base.store_full_sti_class) ActiveRecord::Base.store_full_sti_class = true end # Get the RDF configuration options def rdf_connection_opts options = connection_opts(@config["rdf_connection"], @config["rdf_connection_file"]) # Make the keys into symbols, as needed by ActiveRDF rdf_cfg = Hash.new options.each { |key, value| rdf_cfg[key.to_sym] = value } rdf_cfg end # Configure the RDF connection def config_rdf # Logginging goes to standard talia logger ActiveRdfLogger.logger = talia_logger ActiveRDF::ConnectionPool.add_data_source(rdf_connection_opts) end # Configure the namespaces def config_namespaces # Register the local name N::Namespace.shortcut(:local, @config["local_uri"]) talia_logger.info("Local Domain: #{N::LOCAL}") # Register namespace for database dupes N::Namespace.shortcut(:talia, "http://talia.discovery-project.eu/wiki/TaliaInternal#") # Register additional namespaces if(@config["namespaces"]) assit_kind_of(Hash, @config["namespaces"]) @config["namespaces"].each_pair do |shortcut, uri| N::Namespace.shortcut(shortcut, uri) end end end # Configure the data directory def config_data_directory data_directory = if(@config['data_directory_location']) # Replace the data directory location variables @config["data_directory_location"].gsub(/TALIA_ROOT/, TALIA_ROOT) else File.join(TALIA_ROOT, 'data') end @config['data_directory_location'] = data_directory end # Configure the data directory def config_iip_root_directory data_directory = if(@config['iip_root_directory_location']) # Replace the iip root directory location variables @config["iip_root_directory_location"].gsub(/TALIA_ROOT/, TALIA_ROOT) else File.join(TALIA_ROOT, 'iip_root') end @config['iip_root_directory_location'] = data_directory end # Autoload ontologies, if configured def load_ontologies return unless(@config['auto_ontologies'] && !['false', 'no'].include?(@config['auto_ontologies'].downcase)) onto_dir = File.join(TALIA_ROOT, @config['auto_ontologies']) raise(Errors::SystemInitializationError, "Cannot find configured ontology dir #{onto_dir}") unless(File.directory?(onto_dir)) adapter = ActiveRDF::ConnectionPool.write_adapter raise(Errors::SystemInitializationError, "Ontology autoloading without a context-aware adapter deletes all RDF data. This is only allowed in testing, please load the ontology manually.") unless(adapter.contexts? || (@environment == 'testing')) raise(Errors::SystemInitializationError, "Ontology autoloading requires 'load' capability on the adapter.") unless(adapter.respond_to?(:load)) # Clear out the RDF if(adapter.contexts?) TaliaCore::RdfImport.clear_file_contexts else adapter.respond_to?(:clear) ? adapter.clear : TaliaUtil::Util::flush_rdf end loaded_ontos = [] Dir.foreach(onto_dir) do |file| if(file =~ /\.owl$|\.rdf$|\.rdfs$/) file = File.expand_path(File.join(onto_dir, file)) adapter.contexts? ? TaliaCore::RdfImport.import_file(file, 'rdfxml', :auto) : TaliaCore::RdfImport.import_file(file, 'rdfxml') loaded_ontos << File.basename(file) end end klasses, updated = TaliaUtil::RdfUpdate::rdfs_from_owl puts "Ontologies autoloaded: #{loaded_ontos.join(', ')} (#{updated} of #{klasses} updated)" end def load_core_ext path_to_core_ext = File.join(TALIA_CODE_ROOT, 'lib', 'core_ext') Dir[path_to_core_ext + '/**/*.rb'].each { |f| require f} end # Register the default mime types def register_mime_types # Add new mime types for use in respond_to blocks: # Mime::Type.register "text/richtext", :rtf # Mime::Type.register_alias "text/html", :iphone Mime::Type.register "application/rdf+xml", :rdf # The are used for serving "static" widget content by mime type Mime::Type.register "image/gif", :gif, [], %w( gif ) Mime::Type.register "image/jpeg", :jpeg, [], %w( jpeg jpg jpe jfif pjpeg pjp ) Mime::Type.register "image/png", :png, [], %w( png ) Mime::Type.register "image/tiff", :tiff, [], %w( tiff tif ) Mime::Type.register "image/bmp", :bmp, [], %w( bmp ) Mime::Type.register "video/isivideo", :isivideo, [], %w( fvi ) Mime::Type.register "video/mpeg", :mpeg, [], %w( mpeg mpg mpe mpv vbs mpegv ) Mime::Type.register "video/x-mpeg2", :xmpeg2, [], %w( mpv2 mp2v ) Mime::Type.register "video/msvideo", :msvideo, [], %w( avi ) Mime::Type.register "video/quicktime", :quicktime, [], %w( qt mov moov ) Mime::Type.register "video/vivo", :vivo, [], %w( viv vivo ) Mime::Type.register "video/wavelet", :wavelet, [], %w( wv ) Mime::Type.register "video/x-sgi-movie", :xsgimovie, [], %w( movie ) Mime::Type.register "application/pdf", :pdf, [], %w( pdf ) %w( hnml tei tei-p4 tei-p5 gml wittei).each do |type| Mime::Type.register "application/xml+#{type}", type.gsub(/-/, '_').to_sym, [], [ type ] end end end end # Add logger to the module def self.logger Initializer.talia_logger end end