require 'caruby/util/collection' require 'caruby/import/java' require 'caruby/domain/java_attribute_metadata' require 'caruby/domain/resource_attributes' require 'caruby/domain/resource_introspection' require 'caruby/domain/resource_dependency' module CaRuby # Exception raised if a meta-data setting is missing or invalid. class MetadataError < RuntimeError; end # Adds introspected metadata to a Class. module ResourceMetadata include ResourceIntrospection, ResourceDependency, ResourceAttributes attr_reader :domain_module # Associates meta-data with a Resource class. When a Resource class is added to a ResourceModule, # the ResourceModule extends the Resource class with ResourceMetadata and calls this # {#add_metadata} method with itself as the mod argument. The ResourceModule is accessed # by the {#domain_module} method. def add_metadata(mod) @domain_module = mod init_attributes # in ResourceAttributes introspect # in ResourceIntrospection end # @return the domain type for attribute, or nil if attribute is not a domain attribute def domain_type(attribute) attr_md = attribute_metadata(attribute) attr_md.type if attr_md.domain? end # Prints this classifier's content to the log. def pretty_print(q) # the Java property descriptors property_descriptors = java_attributes.wrap { |attr| attribute_metadata(attr).property_descriptor } # build a map of relevant display label => attributes prop_printer = property_descriptors.wrap { |pd| PROP_DESC_PRINTER.wrap(pd) } prop_syms = property_descriptors.map { |pd| pd.name.to_sym }.to_set aliases = @alias_std_attr_map.keys - attributes.to_a - prop_syms alias_attr_hash = aliases.to_compact_hash { |aliaz| @alias_std_attr_map[aliaz] } dependents_printer = dependent_attributes.wrap { |attr| DEPENDENT_ATTR_PRINTER.wrap(attribute_metadata(attr)) } owner_printer = owners.wrap { |type| TYPE_PRINTER.wrap(type) } inverses = @attributes.to_compact_hash do |attr| attr_md = attribute_metadata(attr) "#{attr_md.type.qp}.#{attr_md.inverse}" if attr_md.inverse end domain_attr_printer = domain_attributes.to_compact_hash { |attr| domain_type(attr).qp } map = { "Java properties" => prop_printer, "standard attributes" => attributes, "aliases to standard attributes" => alias_attr_hash, "secondary key" => secondary_key_attributes, "mandatory attributes" => mandatory_attributes, "domain attributes" => domain_attr_printer, "creatable domain attributes" => creatable_domain_attributes, "updatable domain attributes" => updatable_domain_attributes, "fetched domain attributes" => fetched_domain_attributes, "cascaded domain attributes" => cascaded_attributes, "owners" => owner_printer, "owner attributes" => owner_attributes, "inverse attributes" => inverses, "dependent attributes" => dependents_printer, "default values" => defaults }.delete_if { |key, value| value.nil_or_empty? } # one indented line per entry, all but the last line ending in a comma content = map.map { |label, value| " #{label}=>#{format_print_value(value)}" }.join(",\n") # print the content to the log q.text("#{qp} structure:\n#{content}") end protected # Adds the given subclass to this class's {ResourceMetadata#domain_module}. def introspect_subclass(klass) # introspect this class if necessary unless @domain_module then raise TypeError.new("Can't introspect #{qp}") unless superclass and superclass.include?(Resource) superclass.introspect_subclass(self) end @domain_module.add_class(klass) end def self.extend_class(klass, mod) klass.extend(self) klass.add_metadata(mod) end private # A proc to print the unqualified class name. TYPE_PRINTER = PrintWrapper.new { |type| type.qp } DEPENDENT_ATTR_PRINTER = PrintWrapper.new do |attr_md| flags = [] flags << :logical if attr_md.logical? flags << :autogenerated if attr_md.autogenerated? flags << :disjoint if attr_md.disjoint? flags.empty? ? "#{attr_md}" : "#{attr_md}(#{flags.join(',')})" end # A proc to print the property descriptor name. PROP_DESC_PRINTER = PrintWrapper.new { |pd| pd.name } def format_print_value(value) case value when String then value when Class then value.qp else value.pp_s(:single_line) end end end end