Skip to content

Commit 9d26cf7

Browse files
sappeninadrianhopebailie
authored andcommitted
Initial discussion-point commit of proposed InterledgerAddress per IL-RFC 15 (#18)
* Initial discussion-point commit of proposed InterledgerAddress per RFC 15 * Updates InterledgerAdderss definition to conform to RFC 15 * Transitioned to Interface so multiple implementations of InterledgerAddress can exist. * Made InterledgerAddress immutable * Made InterledgerAddress implementation disallows null per https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained * Added unit tests * Remove old InterledgerAddress class * Remove old InterledgerAddress class (and unused unit tests) * Update Javadoc to abide by checkstyle * Add package-info.java * Misc changes per code review comments * Move core classes back to org.interledger.ilp package per code review comments. * Improve Javadoc comments. * Add more unit tests.
1 parent be5b85b commit 9d26cf7

15 files changed

+628
-201
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@
99
*~
1010

1111
# OSX
12-
**/.DS_Store
12+
**/.DS_Store
13+
/*.iml
14+
/.idea
15+
/classes
Lines changed: 63 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -1,190 +1,89 @@
11
package org.interledger.ilp;
22

3-
import java.nio.charset.Charset;
4-
import java.util.regex.Pattern;
3+
import java.util.Objects;
54

65
/**
7-
* An interledger account address.
8-
*
9-
* @author adrianhopebailie
6+
* Interledger Protocol (ILP) Addresses identify Ledger accounts (or groups of Ledger accounts) in
7+
* an ILP network, and provide a way to route a payment to its intended destination.
108
*
9+
* <p>Interledger Addresses can be subdivided into two categories:</p>
10+
*
11+
* <p> <b>Destination Addresses</b> are complete addresses that can receive payments. A destination
12+
* address always maps to one account in a ledger, though it can also provide more specific
13+
* information, such as an invoice ID or a sub-account. Destination addresses MUST NOT end in a
14+
* period (.) character. </p>
15+
*
16+
* <p> <b>Address Prefixes</b> are incomplete addresses representing a grouping of
17+
* destination addresses. Many depths of grouping are possible, for example: groups of accounts or
18+
* sub-accounts; an individual ledger or sub-ledger; or entire neighborhoods of ledgers. Address
19+
* prefixes MUST end in a period (.) character. </p>
20+
*
21+
* <p> The formal specification for an Interledger Addresses is defined in <a
22+
* href="https://github.com/interledger/rfcs/tree/master/0015-ilp-addresses">Interledger RFC
23+
* #15</a>. </p>
24+
*
25+
* @see "https://github.com/interledger/rfcs/tree/master/0015-ilp-addresses"
1126
*/
12-
public class InterledgerAddress {
13-
14-
// US-ASCII is basically IA5 and we're only using a limited set
15-
private static Charset IA5 = Charset.forName("US-ASCII");
16-
private static Pattern REGEX = Pattern.compile("^[a-zA-Z0-9._~-]+$");
17-
18-
private String address;
19-
20-
/**
21-
* Constructs an Interledger Address from the binary data assumed to be encoded in the
22-
* IA5 character set (currently treated as US-ASCII).
23-
* @param binaryData
24-
* The raw data representing a IA5/US-ASCII encoded string Interledger address.
25-
*/
26-
public InterledgerAddress(byte[] binaryData) {
27-
address = new String(binaryData, IA5);
28-
if (!isValid(address)) {
29-
throw new IllegalArgumentException("Invalid characters in address.");
30-
}
31-
}
32-
33-
/**
34-
* Constructs an Interledger Address from the given string.
35-
* @param address
36-
* A string representing an Interledger address
37-
*/
38-
public InterledgerAddress(String address) {
39-
if (!isValid(address)) {
40-
throw new IllegalArgumentException("Invalid characters in address.");
41-
}
42-
this.address = address;
43-
}
44-
45-
/**
46-
* Forms an Interledger Address based on a ledger prefix and a path. For example, given
47-
* the prefix 'ilpdemo.red.' and path 'bob', the method will return the address 'ilpdemo.red.bob'
48-
*
49-
* @param ledgerPrefix
50-
* The ledger prefix that should form part of the final Interledger address
51-
* @param path
52-
* A path to add to the prefix to form a final Interledger address.
53-
* @return
54-
* An Interledger address that is the combination of the ledger prefix and the given path.
55-
*/
56-
public static InterledgerAddress fromPrefixAndPath(InterledgerAddress ledgerPrefix, String path) {
57-
if (!isValid(path)) {
58-
throw new IllegalArgumentException("Invalid characters in path.");
59-
}
60-
61-
//TODO: why this restriction - cant we infer that it should end in a '.' if it doesnt already?
62-
String prefix = ledgerPrefix.toString();
63-
if (!isLedgerPrefix(prefix)) {
64-
throw new IllegalArgumentException("A ledger prefix should end in '.' (dot).");
65-
}
66-
67-
if (path.startsWith(prefix)) {
68-
return new InterledgerAddress(path);
69-
}
70-
71-
return new InterledgerAddress(prefix + path);
72-
}
73-
74-
/**
75-
* Forms an Interledger Address by removing the given prefix from the current address.
76-
* For example, given the address 'ilpdemo.red.bob' and prefix 'ilpdemo.red.', the method will
77-
* return the address 'bob'
78-
*
79-
* @param prefix
80-
* The prefix to remove from the current Interledger address.
81-
* @return
82-
* A new Interledger address with the given prefix removed.
83-
*/
84-
public InterledgerAddress trimPrefix(InterledgerAddress prefix) {
85-
String prefixStr = prefix.toString();
86-
87-
//TODO: why this restriction - cant we infer that it should end in a '.' if it doesnt already?
88-
if (!isLedgerPrefix(prefixStr)) {
89-
throw new IllegalArgumentException("A ledger prefix should end in '.' (dot).");
90-
}
91-
92-
if (!address.startsWith(prefixStr)) {
93-
throw new IllegalArgumentException(
94-
"Invalid ILP Address prefix [" + prefixStr + "] for address [" + address + "]");
95-
}
96-
97-
return new InterledgerAddress(address.substring(prefixStr.length()));
98-
}
27+
public interface InterledgerAddress {
9928

10029
/**
101-
* Tests if this Interledger address starts with the specified prefix.
102-
*
103-
* @param prefix
104-
* The prefix.
105-
* @return
106-
* True if the address begins with the specified prefix, false otherwise.
30+
* Return this address's value as a non-null {@link String}. For example:
31+
* <code>us.usd.bank.account</code>
32+
*
33+
* @return A {@link String} representation of this Interledger address.
10734
*/
108-
public boolean startsWith(InterledgerAddress prefix) {
109-
return address.startsWith(prefix.toString());
110-
}
35+
String getValue();
11136

11237
/**
11338
* Tests if this Interledger address represents a ledger prefix.
114-
*
115-
* @return
116-
* True if the address is a ledger prefix, false otherwise.
39+
*
40+
* @return True if the address is a ledger prefix, false otherwise.
11741
*/
118-
public boolean isLedgerPrefix() {
119-
return InterledgerAddress.isLedgerPrefix(this.address);
42+
default boolean isLedgerPrefix() {
43+
return getValue().endsWith(".");
12044
}
12145

12246
/**
123-
* Tests if the given address represents a ledger prefix.
124-
*
125-
* @return
126-
* True if the address is a ledger prefix, false otherwise.
47+
* Tests if this InterledgerAddress starts with the specified {@code addressSegment}.
48+
*
49+
* @param addressSegment An {@link String} prefix to compare against.
50+
* @return {@code true} if this InterledgerAddress begins with the specified prefix, {@code
51+
* false} otherwise.
12752
*/
128-
public static boolean isLedgerPrefix(String address) {
129-
return address.endsWith(".");
53+
default boolean startsWith(final String addressSegment) {
54+
Objects.requireNonNull(addressSegment, "addressSegment must not be null!");
55+
return this.getValue().startsWith(addressSegment);
13056
}
13157

13258
/**
133-
* Tests if the given string represents a valid Interledger address. A valid address is a non
134-
* empty sequence of upper and lower case US-ASCII characters and numbers including the special
135-
* characters '.', '~', '_', and '-'.
136-
*
137-
* @param address
138-
* The address to test.
139-
* @return
140-
* True if the address is valid, false otherwise.
59+
* Tests if this InterledgerAddress starts with the specified {@code interledgerAddress}.
60+
*
61+
* @param interledgerAddress An {@link InterledgerAddress} prefix to compare against.
62+
* @return {@code true} if this InterledgerAddress begins with the specified prefix, {@code false}
63+
* otherwise.
14164
*/
142-
public static boolean isValid(String address) {
143-
if (address == null) {
144-
return false;
145-
}
146-
return REGEX.matcher(address).matches();
65+
default boolean startsWith(final InterledgerAddress interledgerAddress) {
66+
Objects.requireNonNull(interledgerAddress, "interledgerAddress must not be null!");
67+
return this.startsWith(interledgerAddress.toString());
14768
}
14869

14970
/**
150-
* Returns the address as a sequence of bytes using the IA5 character encoding scheme.
71+
* Return a new InterledgerAddress by postfixing the supplied {@code segment} to this address.
72+
*
73+
* <p>This method can be used to construct both address prefixes and destination addresses. For
74+
* example, if the value of this address is '<code>us.usd.</code>', then calling this method with
75+
* an argument of '<code>bob</code>' would result in a new Interledger Address with a value of
76+
* '<code>us.usd.bob</code>', which is a destination address.</p>
77+
*
78+
* <p>Likewise, if the value of this address is '<code>us.usd.pacific.</code>', then calling this
79+
* method with an argument of '<code>creditunions.</code>' would result in a new Interledger
80+
* Address with a value of '<code>us.usd.pacific.creditunions.</code>', which is an address
81+
* prefix. </p>
82+
*
83+
* @param addressSegment A {@link String} to be appended to this address as an additional
84+
* segment.
85+
* @return A new instance of InterledgerAddress representing the original address with a newly
86+
* specified final segment.
15187
*/
152-
public byte[] toByteArray() {
153-
return address.getBytes(IA5);
154-
}
155-
156-
@Override
157-
public String toString() {
158-
return address;
159-
}
160-
161-
@Override
162-
public int hashCode() {
163-
final int prime = 31;
164-
int result = 1;
165-
result = prime * result + ((address == null) ? 0 : address.hashCode());
166-
return result;
167-
}
168-
169-
@Override
170-
public boolean equals(Object obj) {
171-
if (this == obj) {
172-
return true;
173-
}
174-
if (obj == null) {
175-
return false;
176-
}
177-
if (getClass() != obj.getClass()) {
178-
return false;
179-
}
180-
InterledgerAddress other = (InterledgerAddress) obj;
181-
if (address == null) {
182-
if (other.address != null) {
183-
return false;
184-
}
185-
} else if (!address.equals(other.address)) {
186-
return false;
187-
}
188-
return true;
189-
}
88+
InterledgerAddress with(String addressSegment);
19089
}

0 commit comments

Comments
 (0)