class Blufin::ScannerJavaEmbeddedObjects
This class scans embedded objects -> IE: AbstractAccount.
Constants
- EMBEDDED
- EMBEDDED_ANNOTATION
- KEY_NESTED_TABLE
- KEY_TYPE_JAVA
- OBJECT
- OBJECT_LINK
- OBJECT_LIST
- PATH_TO_EMBEDDED
Public Class Methods
new(site, error_handler)
click to toggle source
@return void
# File lib/core/code_scanners/scanner_java_embedded_objects.rb, line 21 def initialize(site, error_handler) return unless @@data.nil? @@data = {} @site = Blufin::SiteResolver::validate_site(site) @site_name = Blufin::SiteResolver::get_site_name(@site) @site_path = Blufin::SiteResolver::get_site_location(@site) @site_domain = Blufin::SiteResolver::get_site_domain(@site) @error_handler = error_handler object_paths = %W( #{Blufin::Config::get_path('Paths', 'BlufinJava')}/#{PATH_TO_EMBEDDED}/dto/#{Blufin::YmlSchemaValidator::CONFIG} #{Blufin::Config::get_path('Paths', 'BlufinJava')}/#{PATH_TO_EMBEDDED}/dto/#{Blufin::YmlSchemaValidator::COMMON} #{Blufin::Config::get_path('Paths', 'BlufinJava')}/#{PATH_TO_EMBEDDED}/dto/#{Blufin::YmlSchemaValidator::APP}) object_paths.each do |object_path| Blufin::Files::get_files_in_dir(object_path).each do |file| file_schema = nil file_class = nil file_data = {} file_line = 0 file_ref = nil file_parts = file.split('/') field_data = nil annotation_data_found = false annotation_ruby_found = false previous_was_implements = false Blufin::Files::read_file(file).each do |line| file_line += 1 type = nil field = nil line.gsub!("\n", '') line.gsub!(/\/\*+.+\*+\//, '') line.gsub!(/\/{2,}.+\z/, '') line.strip! next if line == '' # Extract Schema. if file_schema.nil? fs = file.split('/') file_schema = fs[fs.length - 2] end annotation_data_found = true if !annotation_data_found && line =~ /\A@Data\z/ annotation_ruby_found = true if !annotation_ruby_found && line =~ /\A@ParsedByRuby\z/ # Extract Reference (from @Embedded annotation) if file_ref.nil? && line =~ /\A@Embedded\("[\S]+"\)\z/ file_ref = line file_ref.gsub!(/\A#{EMBEDDED_ANNOTATION}\("/, '') file_ref.gsub!(/"\)\z/, '') end # Extract Class. if file_class.nil? && line =~ /\Apublic\s+abstract\s+class/ file_class = extract_class_name(line) @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_OBJECT_INVALID_ABSTRACTION, file, nil, nil, file_class) add_error_abstract_dto_implementation(line, file, file_class) next elsif file_class.nil? && line =~ /\Apublic\s+class\s+/ file_class = extract_class_name(line) add_error_abstract_dto_implementation(line, file, file_class) next end # Start parsing fields only once class name has been resolved. unless file_class.nil? # Extract Data. if line =~ /\A@Implements/ # @Implements(DataType.INT) if line =~ /\A@Implements\(DataType\.[A-Z_]+\)\z/ data_type = line.gsub(/\A@Implements\(DataType\./, '').gsub(/\)\z/, '') field_data = add_data_type(file, data_type) elsif line =~ /\A@Implements\(value\s=\sDataType\.[A-Z_]+(,\sextra\s=\s"[A-Za-z0-9]+")?(,\sflags\s=\s{[A-Za-z0-9.,_\s]+})?(,\sfkey\s=\s"[a-z_.]+")?(,\sencrypted\s=\s(true|false))?\)\z/ # Extract DataType data_type = line.gsub(/\A@Implements\(value\s=\sDataType\./, '').gsub(/(,\s(.)+)?\)\z/, '') # Extract Extra if line =~/,\sextra\s=\s"[A-Za-z0-9]+"/ extra = line.split('extra = "') extra = extra[1].gsub(/"(,\s(.)+)?\)\z/, '') else extra = nil end field_data = add_data_type(file, data_type, extra) # Extract Flags if line =~/,\sflags\s=\s{[A-Za-z0-9.,_\s]+}/ flags = line.gsub(/\A(.)+flags\s=\s{/, '').gsub(/}(,\s*.+)?\)\z/, '') # Adjust AUTO_INCREMENT flag with value (if necessary). flags = flags.gsub(Blufin::YmlSchemaValidator::FLAG_AUTO_INCREMENT, "#{Blufin::YmlSchemaValidator::FLAG_AUTO_INCREMENT}(#{extra})") if data_type == 'INT_AUTO' && extra.to_i > 0 flags = flags.split(/\s?,\s?/) flags = flags.map { |n| n.gsub(/\ADataTypeFlag\./, '') } field_data = field_data.merge({ :flag => flags }) end # Extract Fkey if line =~/,\sfkey\s=\s"[a-z_.]+"/ fkey = line.gsub(/\A(.)+fkey\s=\s"/, '').gsub(/"(.)+\z/, '') field_data = field_data.merge({ :fkey => "#{file_schema}.#{fkey}" }) end # Extract Encrypted if line =~/,\sencrypted\s=\s(true|false)/ encrypted = line.gsub(/\A(.)+encrypted\s=\s/, '').gsub(/e(.)+\z/, '') encrypted ="#{encrypted}e" field_data = field_data.merge({ :encrypted => encrypted }) @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_ANNOTATION_UNNECESSARY, file, nil, nil, 'encrypted = false') if encrypted == 'false' end elsif line =~ /\A@ImplementsObject\(value\s=\s"[a-z_]+",\srelation\s=\sRelation\.(ONE_TO_ONE|ONE_TO_MANY|MANY_TO_MANY)\)\z/ data_type = line.gsub(/\A@ImplementsObject\(value\s=\s"[a-z_]+",\srelation\s=\sRelation\./, '').gsub(/\)\z/, '') case data_type when 'ONE_TO_ONE' data_type = OBJECT nested_table = line.gsub(/\A@ImplementsObject\(value\s=\s"/, '').gsub(/"(.)+\z/, '') when 'ONE_TO_MANY' data_type = OBJECT_LIST nested_table = line.gsub(/\A@ImplementsObject\(value\s=\s"/, '').gsub(/"(.)+\z/, '') when 'MANY_TO_MANY' data_type = OBJECT_LINK # TODO - FINISH once OBJECT_LINK needs to be supported. raise RuntimeError, "#{OBJECT_LINK} not yet supported for @Embedded Objects." else raise RuntimeError, "Unrecognized data-type: #{data_type}" end field_data = { :type => data_type, :nested_table => "#{file_schema}.#{nested_table}" } else @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_OBJECT_INVALID_LINE, file, nil, nil, "#{file_line.to_s.rjust(2)}: #{line}") end previous_was_implements = true elsif previous_was_implements && line =~ /\Aprivate\s+(List<)?[A-Za-z0-9_]+(>)?\s+[A-Za-z0-9_]+;\z/ next if field_data.inspect == '{}' line_split = line.gsub(/\A(private)\s+/, '').split(' ') type_java = line_split[0] field = line_split[line_split.length - 1].gsub(/;\z/, '') field = Blufin::Strings::camel_case_to_snake_case(field).gsub(/>/, '') raise RuntimeError, "Expected :type key to exist for field: #{field}, instead got: #{field_data.inspect}" if field_data[:type].nil? field_data[:type_java] = type_java type = field_data[:type] # Throw error if field is encrypted and config (schema). @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_CONFIG_CANNOT_BE_ENCRYPTED, file, nil, nil, field) if field_data[:encrypted] && file_schema == Blufin::YmlSchemaValidator::CONFIG if type == Blufin::YmlSchemaValidator::TYPE_BOOLEAN @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_DATA_TYPE_INVALID, file, nil, nil, ['Boolean', type_java]) unless type_java == 'Boolean' elsif [ Blufin::YmlSchemaValidator::TYPE_DATETIME, Blufin::YmlSchemaValidator::TYPE_DATETIME_INSERT, Blufin::YmlSchemaValidator::TYPE_DATETIME_UPDATE ].include?(type) @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_DATA_TYPE_INVALID, file, nil, nil, ['ZonedDateTime', type_java]) unless type_java == 'ZonedDateTime' elsif type == Blufin::YmlSchemaValidator::TYPE_DATE @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_DATA_TYPE_INVALID, file, nil, nil, ['LocalDate', type_java]) unless type_java == 'LocalDate' elsif type =~ Blufin::YmlSchemaValidator::REGEX_DECIMAL @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_DATA_TYPE_INVALID, file, nil, nil, ['BigDecimal', type_java]) unless type_java == 'BigDecimal' elsif type == Blufin::YmlSchemaValidator::TYPE_INT_TINY @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_DATA_TYPE_INVALID, file, nil, nil, ['Byte', type_java]) unless type_java == 'Byte' elsif type == Blufin::YmlSchemaValidator::TYPE_INT_SMALL @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_DATA_TYPE_INVALID, file, nil, nil, ['Short', type_java]) unless type_java == 'Short' elsif type == Blufin::YmlSchemaValidator::TYPE_INT_BIG @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_DATA_TYPE_INVALID, file, nil, nil, ['Long', type_java]) unless type_java == 'Long' elsif [ Blufin::YmlSchemaValidator::TYPE_INT, Blufin::YmlSchemaValidator::TYPE_INT_AUTO ].include?(type) @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_DATA_TYPE_INVALID, file, nil, nil, ['Integer', type_java]) unless type_java == 'Integer' elsif [ Blufin::YmlSchemaValidator::TYPE_TEXT, Blufin::YmlSchemaValidator::TYPE_TEXT_LONG ].include?(type) @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_DATA_TYPE_INVALID, file, nil, nil, ['String', type_java]) unless type_java == 'String' elsif type == Blufin::YmlSchemaValidator::TYPE_ENUM raise RuntimeError, 'ENUM should never be used with @Embedded objects. Only use ENUM_SYSTEM because enums need to be shared across apps.' elsif type == Blufin::YmlSchemaValidator::TYPE_ENUM_CUSTOM raise RuntimeError, 'ENUM_CUSTOM should never be used with @Embedded objects. Only use ENUM_SYSTEM because enums need to be shared across apps.' elsif type == Blufin::YmlSchemaValidator::TYPE_ENUM_SYSTEM # Do nothing. elsif type =~ Blufin::YmlSchemaValidator::REGEX_VARCHAR @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_DATA_TYPE_INVALID, file, nil, nil, ['String', type_java]) unless type_java == 'String' elsif type == OBJECT # Do nothing. elsif type == OBJECT_LIST object_list_regex = /\A[a-z_]+list\z/ @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_OBJECT_INVALID_REGEX, file, nil, nil, [field, Blufin::YmlCommon::convert_regex_to_string(object_list_regex)]) unless field =~ object_list_regex field = field.gsub(/_list\z/, '') elsif type == OBJECT_LINK # TODO - FINISH once OBJECT_LINK need to be supported. raise RuntimeError, 'OBJECT_LINK is not currently supported by @Embedded objects.' else raise RuntimeError, "Unrecognized type in #{__FILE__}: #{type}" end file_data[field] = field_data field_data = {} else previous_was_implements = false next if line == '}' next if line =~ /\/\*\*/ next if line =~ /\*\// next if line =~ /@Override/ next if line =~ /@JsonIgnore/ next if line =~ /public\sInteger\sgetParentId\(\)\s{/ next if line =~ /return\sget[A-Za-z]+\(\);/ @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_OBJECT_INVALID_LINE, file, nil, nil, "#{file_line.to_s.rjust(2)}: #{line}") end end end # Make sure we have a valid schema (defined through annotation) and that it's not nil. unless file_schema.to_s =~ /(#{Blufin::YmlSchemaValidator::VALID_SCHEMAS_REGEX})/ @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_OBJECT_INVALID_SCHEMA, file, nil, nil, file_schema) next end # Make sure that the file reference matches the same REGEX that schema tables would be (IE: lowercase & snake-case). if file_ref.nil? @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_OBJECT_NO_ANNOTATION, file, nil, nil, nil) next elsif file_ref !~ /\A[a-z_]+\z/ @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_OBJECT_INVALID_REF_REGEX, file, nil, nil, file_ref) elsif file_ref.length > Blufin::YmlSchemaValidator::MAX_TABLE_CHARACTERS @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_OBJECT_INVALID_REF_LENGTH, file, nil, nil, file_ref) end # Make sure class starts with the word "Embedded" (and is not nil). if file_class.nil? || !(file_class =~ /#{EMBEDDED}[A-Za-z]/) @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_OBJECT_INVALID_NAME, file, nil, nil, file_class) next end # Make sure we've found some fields (at least 1). if file_data.nil? @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_OBJECT_DATA_NOT_FOUND, file, nil, nil, file_class) next end @@data[file_ref] = { :schema => file_schema, :table => file_ref, :class => file_class.gsub(/\A#{EMBEDDED}/, ''), :data => file_data } # Make sure we have correct annotations. @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_ANNOTATION_MISSING, file, nil, nil, '@Data') unless annotation_data_found @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_ANNOTATION_MISSING, file, nil, nil, '@ParsedByRuby') unless annotation_ruby_found end end # Add Dependents. @@data.each do |key, value| hierarchy = [] hierarchy = extract_hierarchy(key, hierarchy) @@data[key][:dependents] = hierarchy if hierarchy.any? data = value[:data] schema = value[:schema] table = value[:table] if data.is_a?(Hash) && data.any? data.each do |key_inner, value_inner| type = value_inner[:type] table_nested = value_inner[:nested_table] if [Blufin::YmlSchemaValidator::RESOURCE_TYPE_OBJECT, Blufin::YmlSchemaValidator::RESOURCE_TYPE_OBJECT_LIST].include?(type) child_key = "#{table}_#{Blufin::YmlSchemaValidator::ID}" child_object = @@data[table_nested.split('.')[1]][:data][child_key] raise RuntimeError, "Expected #{table_nested}.#{child_key} to have :fkey, instead got: #{child_object}" unless child_object.has_key?(:fkey) @@data[table_nested.split('.')[1]][:data][child_key] = child_object.merge({ :child_of => "#{table}", :child_type => "DataType.#{type}"}) end end end end end end
Public Instance Methods
get_data()
click to toggle source
Returns data Hash. @return Hash
# File lib/core/code_scanners/scanner_java_embedded_objects.rb, line 329 def get_data @@data end
Private Instance Methods
add_data_type(file, data_type, extra = nil)
click to toggle source
Adds a data type. @return Hash
# File lib/core/code_scanners/scanner_java_embedded_objects.rb, line 367 def add_data_type(file, data_type, extra = nil) converted_data_type = data_type # Validate the EXTRA data. if converted_data_type == 'VARCHAR' && !extra.nil? if extra.to_i > 0 converted_data_type = "VARCHAR(#{extra})" else @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_EXTRA_VALUE_INVALID, file, nil, nil, ['Integer (> 0)', extra.to_s]) return {} end end { :type => converted_data_type } end
add_error_abstract_dto_implementation(line, file, class_name)
click to toggle source
Adds an error if class does not implement PersistentDto. @return void
# File lib/core/code_scanners/scanner_java_embedded_objects.rb, line 361 def add_error_abstract_dto_implementation(line, file, class_name) @error_handler.add_error(Blufin::YmlErrorHandler::EMBEDDED_OBJECT_INVALID_EXTENSION, file, nil, nil, class_name) unless line =~ /extends\s+PersistentDtoEmbedded\s+{\z/ end
extract_class_name(line)
click to toggle source
Extracts class name from a file line. @return String
# File lib/core/code_scanners/scanner_java_embedded_objects.rb, line 355 def extract_class_name(line) line.gsub(/\Apublic\s+(abstract)?\s?class\s?/, '').split(' ')[0] end
extract_hierarchy(prefix, hierarchy)
click to toggle source
Used to recursively loop through @@data to find nested objects. @return ?
# File lib/core/code_scanners/scanner_java_embedded_objects.rb, line 337 def extract_hierarchy(prefix, hierarchy) @@data.each do |key, value| unless value[:data].nil? value[:data].each do |field, field_data| unless field_data[:nested_table].nil? if field =~ /\A#{prefix}_[a-z]+\z/ hierarchy << field extract_hierarchy(field, hierarchy) end end end end end hierarchy end