indexing description: "Represents an endpoint address" license: "MIT license (see ../../license.txt)" author: "Beat Strasser " date: "$Date$" revision: "$Revision$" class P2P_ENDPOINT_ADDRESS inherit P2P_STRING_UTILS redefine out, is_equal end P2P_EXCEPTION_LOG redefine out, is_equal end create make_from_uri, make, make_with_service, make_with_id feature {NONE} -- Initialization make_from_uri (uri: STRING) is -- Create endpoint address from URI require Address_valid: uri /= Void do parse_uri (trimmed (uri)) if is_valid and not valid_address then parse_status := status_protocol_address_invalid end end make (a_protocol_name, a_protocol_address: STRING) is -- Create endpoint address by components require Protocol_valid: a_protocol_name /= Void and a_protocol_address /= Void do protocol_name := a_protocol_name is_url := not protocol_name.has (colon) protocol_address := a_protocol_address if valid_address then parse_status := status_ok end end make_with_service (a_protocol_name, a_protocol_address, a_service_name, a_service_parameter: STRING) is -- Create endpoint address with service name (and possible parameter) require Protocol_valid: a_protocol_name /= Void and a_protocol_address /= Void Service_name_valid: a_service_name /= Void and not a_service_name.is_empty Service_parameter_valid: a_service_parameter /= Void implies (not a_service_parameter.is_empty and a_service_name /= Void) do make (a_protocol_name, a_protocol_address) service_name := a_service_name.twin if a_service_parameter /= Void then service_parameter := a_service_parameter.twin end end make_with_id (a_peer_id: P2P_ID; a_service_name, a_service_parameter: STRING) is -- Create endpoint address by components require Id_valid: a_peer_id /= Void and a_peer_id.is_valid Service_name_valid: a_service_name /= Void implies not a_service_name.is_empty Service_parameter_valid: a_service_parameter /= Void implies (not a_service_parameter.is_empty and a_service_name /= Void) do if a_service_name /= Void then make_with_service (urn_namespace_jxta, a_peer_id.out, a_service_name, a_service_parameter) else make (urn_namespace_jxta, a_peer_id.out) end end feature -- Access protocol_name: STRING protocol_address: STRING service_name: STRING service_parameter: STRING out: STRING is -- Full string representation do Result := out_without_service if service_name /= Void then if is_url then Result.append_character (service_separator) else Result.append_character (urn_service_separator) end Result.append (service_name) if service_parameter /= Void then Result.append_character (service_separator) Result.append (service_parameter) end end end out_without_service: STRING is -- String representation without service part do create Result.make (100) if is_url then Result.append (protocol_name) Result.append (protocol_name_separator) Result.append (protocol_address) else Result.append (protocol_name) Result.append_character (colon) Result.append (protocol_address) end end ip_host: STRING is -- IP Host address require Valid: is_valid local sep: INTEGER do sep := protocol_address.last_index_of (ip_port_separator, protocol_address.count) if sep /= 0 then Result := protocol_address.substring (1, sep - 1) else Result := protocol_address end ensure Result_set: Result /= Void end ip_port: INTEGER is -- IP Port require Valid: is_valid local sep: INTEGER port_part: STRING do sep := protocol_address.last_index_of (ip_port_separator, protocol_address.count) if sep /= 0 then port_part := protocol_address.substring (sep + 1, protocol_address.count) if port_part.is_integer then Result := port_part.to_integer end end end peer_id: P2P_PEER_ID is -- Valid JXTA peer id, if protocol is jxta require Valid: is_valid do if protocol_name.is_equal (urn_namespace_jxta) then create Result.make_from_urn (protocol_address) if not Result.is_valid then Result := Void end end end address_with_resolved_host_name: like Current is -- Copy of current endpoint address, but with resolved host name. -- Returns Void, when the host name can't be resolved. require Valid: is_valid local host: STRING i, code: INTEGER failed, is_hostname: BOOLEAN h_address: HOST_ADDRESS do if not failed then -- detect if protocol address is a host name host := ip_host if host /= Void then from i := 1 until i > host.count or is_hostname loop code := host.item_code (i) is_hostname := (code /= 46 and (code < 48 or code > 57)) i := i + 1 end end -- create address copy if is_hostname then -- resolve host name to ip create h_address.make h_address.set_address_from_name (host) if service_name /= Void then create Result.make_with_service (protocol_name, h_address.host_address + ":" + ip_port.out, service_name, service_parameter) else create Result.make (protocol_name, h_address.host_address + ":" + ip_port.out) end else Result := twin end end rescue failed := True log_exceptions retry end feature -- Status is_valid: BOOLEAN is -- True when parse_status ok do Result := parse_status = Status_ok end is_url: BOOLEAN has_ipv6_address: BOOLEAN is -- Is `ip_host' an ipv6 address? require Valid: is_valid local host: STRING do host := ip_host Result := host.item (1).is_equal ('[') and host.item (host.count).is_equal (']') end parse_status: INTEGER Status_invalid: INTEGER is 0 Status_ok: INTEGER is 1 Status_not_absolute: INTEGER is 2 Status_protocol_name_missing: INTEGER is 3 Status_protocol_address_missing: INTEGER is 4 Status_protocol_address_invalid: INTEGER is 5 feature -- Comparison is_equal (other: like Current): BOOLEAN is -- True when both are valid and are equal do Result := is_equal_without_service (other) and equal (service_name, other.service_name) and equal (service_parameter, other.service_parameter) ensure then Result_set: Result = (is_equal_without_service (other) and equal (service_name, other.service_name) and equal (service_parameter, other.service_parameter)) end is_equal_without_service (other: like Current): BOOLEAN is -- True when protocol name and address is equal require Other_existent: other /= Void do Result := is_valid and other.is_valid and protocol_name.is_equal (other.protocol_name) and protocol_address.is_equal (other.protocol_address) ensure Result_set: Result = (is_valid and other.is_valid and protocol_name.is_equal (other.protocol_name) and protocol_address.is_equal (other.protocol_address)) end feature {NONE} -- Implementation Protocol_name_separator: STRING is "://" Ip_port_separator, Colon: CHARACTER is ':' Dash: CHARACTER is '-' Service_separator: CHARACTER is '/' Urn_name: STRING is "urn" Urn_namespace_jxta: STRING is "jxta" Urn_service_separator: CHARACTER is '#' Protocol_name_tcp: STRING is "tcp" parse_uri (uri: STRING) is -- Extract values from URI require uri /= Void do if uri.has_substring (protocol_name_separator) then parse_url (uri) end end parse_url (url: STRING) is -- Extract values from URL require url /= Void local pname, paddress, sname: INTEGER do -- protocol name pname := url.substring_index (protocol_name_separator, 1) if pname <= 0 then parse_status := status_not_absolute elseif pname = 1 then parse_status := status_protocol_name_missing else protocol_name := url.substring (1, pname - 1) -- protocol address paddress := url.index_of (service_separator, pname + 3) if paddress <= 0 then protocol_address := url.substring (pname + 3, url.count) parse_status := status_ok elseif paddress = pname + 3 then parse_status := status_protocol_address_missing else protocol_address := url.substring (pname + 3, paddress - 1) parse_status := status_ok if paddress /= url.count then -- service name sname := url.index_of (service_separator, paddress + 1) if sname <= 0 then service_name := url.substring (paddress + 1, url.count) else service_name := url.substring (paddress + 1, sname - 1) -- service parameters if sname /= url.count then service_parameter := url.substring (sname + 1, url.count) end end end end is_url := True end end valid_address: BOOLEAN is -- Is `protocol_address' valid for the given `protocol_name'? do if protocol_name /= Void and protocol_address /= Void then Result := not protocol_name.is_equal (protocol_name_tcp) or protocol_address.has (ip_port_separator) end end invariant Protocol_set: is_valid implies (protocol_name /= Void and protocol_address /= Void) Status_valid: parse_status >= status_invalid and parse_status <= status_protocol_address_invalid end