Skip to content

Commit b357fc7

Browse files
authored
Support Fee Extension standard in rfc 8748 (#2855)
* Support Fee Extension standard in rfc 8748 Adding support to the final version of RFC 8748. Compared with draft-0.12, the only meaningful change is in the namespace. The rest is either schema-tightening that reflects actual usage, or optional server-side features that we do not support. We reuse draft-0.12 tests, only changing namespace uris in the input and output files for the new version. * Addressing reviews
1 parent 754e7fb commit b357fc7

File tree

42 files changed

+1396
-124
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1396
-124
lines changed

core/src/main/java/google/registry/flows/domain/DomainDeleteFlow.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
import google.registry.model.domain.fee06.FeeDeleteResponseExtensionV06;
7878
import google.registry.model.domain.fee11.FeeDeleteResponseExtensionV11;
7979
import google.registry.model.domain.fee12.FeeDeleteResponseExtensionV12;
80+
import google.registry.model.domain.feestdv1.FeeDeleteResponseExtensionStdV1;
8081
import google.registry.model.domain.metadata.MetadataExtension;
8182
import google.registry.model.domain.rgp.GracePeriodStatus;
8283
import google.registry.model.domain.secdns.SecDnsCreateExtension;
@@ -428,6 +429,9 @@ private Money getGracePeriodCost(
428429
@Nullable
429430
private FeeTransformResponseExtension.Builder getDeleteResponseBuilder() {
430431
Set<String> uris = nullToEmpty(sessionMetadata.getServiceExtensionUris());
432+
if (uris.contains(ServiceExtension.FEE_1_00.getUri())) {
433+
return new FeeDeleteResponseExtensionStdV1.Builder();
434+
}
431435
if (uris.contains(ServiceExtension.FEE_0_12.getUri())) {
432436
return new FeeDeleteResponseExtensionV12.Builder();
433437
}

core/src/main/java/google/registry/model/domain/fee/Fee.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ private static Fee createWithCustomDescription(
6464

6565
public static final ImmutableSet<String> FEE_EXTENSION_URIS =
6666
ImmutableSet.of(
67+
ServiceExtension.FEE_1_00.getUri(),
6768
ServiceExtension.FEE_0_12.getUri(),
6869
ServiceExtension.FEE_0_11.getUri(),
6970
ServiceExtension.FEE_0_6.getUri());
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package google.registry.model.domain.feestdv1;
16+
17+
import com.google.common.base.Ascii;
18+
import google.registry.model.domain.Period;
19+
import google.registry.model.domain.fee.FeeCheckCommandExtensionItem;
20+
import jakarta.xml.bind.annotation.XmlAttribute;
21+
import jakarta.xml.bind.annotation.XmlElement;
22+
import jakarta.xml.bind.annotation.XmlType;
23+
import java.util.Locale;
24+
import java.util.Optional;
25+
import org.joda.money.CurrencyUnit;
26+
import org.joda.time.DateTime;
27+
28+
/**
29+
* An individual price check item in version 1.0 of the fee extension on domain check commands.
30+
* Items look like:
31+
*
32+
* <pre>{@code
33+
* <fee:command name="renew" phase="sunrise" subphase="hello">
34+
* <fee:period unit="y">1</fee:period>
35+
* <fee:class>premium</fee:class>
36+
* <fee:date>2017-05-17T13:22:21.0Z</fee:date>
37+
* </fee:command>
38+
* }</pre>
39+
*/
40+
@XmlType(propOrder = {"period", "feeClass", "feeDate"})
41+
public class FeeCheckCommandExtensionItemStdV1 extends FeeCheckCommandExtensionItem {
42+
43+
/** The default validity period (if not specified) is 1 year for all operations. */
44+
static final Period DEFAULT_PERIOD = Period.create(1, Period.Unit.YEARS);
45+
46+
@XmlAttribute(name = "name")
47+
String commandName;
48+
49+
@XmlAttribute String phase;
50+
51+
@XmlAttribute String subphase;
52+
53+
@XmlElement(name = "class")
54+
String feeClass;
55+
56+
@XmlElement(name = "date")
57+
DateTime feeDate;
58+
59+
/** Version 1.0 does not support domain name or currency in fee extension items. */
60+
@Override
61+
public boolean isDomainNameSupported() {
62+
return false;
63+
}
64+
65+
@Override
66+
public String getDomainName() {
67+
throw new UnsupportedOperationException("Domain not supported");
68+
}
69+
70+
@Override
71+
public CurrencyUnit getCurrency() {
72+
return null; // This version of the fee extension doesn't specify currency per-item.
73+
}
74+
75+
@Override
76+
public String getUnparsedCommandName() {
77+
return commandName;
78+
}
79+
80+
@Override
81+
public CommandName getCommandName() {
82+
// Require the xml string to be lowercase.
83+
if (commandName != null && commandName.toLowerCase(Locale.ENGLISH).equals(commandName)) {
84+
try {
85+
return CommandName.valueOf(Ascii.toUpperCase(commandName));
86+
} catch (IllegalArgumentException e) {
87+
// Swallow this and return UNKNOWN below because there's no matching CommandName.
88+
}
89+
}
90+
return CommandName.UNKNOWN;
91+
}
92+
93+
@Override
94+
public String getPhase() {
95+
return phase;
96+
}
97+
98+
@Override
99+
public String getSubphase() {
100+
return subphase;
101+
}
102+
103+
@Override
104+
public FeeCheckResponseExtensionItemStdV1.Builder createResponseBuilder() {
105+
return new FeeCheckResponseExtensionItemStdV1.Builder();
106+
}
107+
108+
@Override
109+
public Optional<DateTime> getEffectiveDate() {
110+
return Optional.ofNullable(feeDate);
111+
}
112+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package google.registry.model.domain.feestdv1;
16+
17+
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
18+
19+
import com.google.common.collect.ImmutableList;
20+
import google.registry.model.ImmutableObject;
21+
import google.registry.model.domain.fee.FeeCheckCommandExtension;
22+
import google.registry.model.domain.fee.FeeCheckResponseExtensionItem;
23+
import jakarta.xml.bind.annotation.XmlElement;
24+
import jakarta.xml.bind.annotation.XmlRootElement;
25+
import jakarta.xml.bind.annotation.XmlType;
26+
import java.util.List;
27+
import org.joda.money.CurrencyUnit;
28+
29+
/** Version 1.0 of the fee extension that may be present on domain check commands. */
30+
@XmlRootElement(name = "check")
31+
@XmlType(propOrder = {"currency", "items"})
32+
public class FeeCheckCommandExtensionStdV1 extends ImmutableObject
33+
implements FeeCheckCommandExtension<
34+
FeeCheckCommandExtensionItemStdV1, FeeCheckResponseExtensionStdV1> {
35+
36+
CurrencyUnit currency;
37+
38+
@Override
39+
public CurrencyUnit getCurrency() {
40+
return currency;
41+
}
42+
43+
@XmlElement(name = "command")
44+
List<FeeCheckCommandExtensionItemStdV1> items;
45+
46+
@Override
47+
public ImmutableList<FeeCheckCommandExtensionItemStdV1> getItems() {
48+
return nullToEmptyImmutableCopy(items);
49+
}
50+
51+
@Override
52+
public FeeCheckResponseExtensionStdV1 createResponse(
53+
ImmutableList<? extends FeeCheckResponseExtensionItem> items) {
54+
ImmutableList.Builder<FeeCheckResponseExtensionItemStdV1> builder =
55+
new ImmutableList.Builder<>();
56+
for (FeeCheckResponseExtensionItem item : items) {
57+
if (item instanceof FeeCheckResponseExtensionItemStdV1) {
58+
builder.add((FeeCheckResponseExtensionItemStdV1) item);
59+
}
60+
}
61+
return FeeCheckResponseExtensionStdV1.create(currency, builder.build());
62+
}
63+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package google.registry.model.domain.feestdv1;
16+
17+
import static google.registry.util.CollectionUtils.forceEmptyToNull;
18+
19+
import com.google.common.base.Ascii;
20+
import com.google.common.collect.ImmutableList;
21+
import google.registry.model.Buildable;
22+
import google.registry.model.ImmutableObject;
23+
import google.registry.model.domain.Period;
24+
import google.registry.model.domain.fee.Fee;
25+
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
26+
import jakarta.xml.bind.annotation.XmlAttribute;
27+
import jakarta.xml.bind.annotation.XmlElement;
28+
import jakarta.xml.bind.annotation.XmlType;
29+
import java.util.List;
30+
import org.joda.time.DateTime;
31+
32+
/** The version 1.0 response command entity for a domain check on a single resource. */
33+
@XmlType(propOrder = {"period", "fee", "feeClass", "effectiveDate", "notAfterDate"})
34+
public class FeeCheckResponseExtensionItemCommandStdV1 extends ImmutableObject {
35+
36+
/** The command that was checked. */
37+
@XmlAttribute(name = "name")
38+
String commandName;
39+
40+
/** The phase that was checked. */
41+
@XmlAttribute String phase;
42+
43+
/** The subphase that was checked. */
44+
@XmlAttribute String subphase;
45+
46+
/** The period that was checked. */
47+
Period period;
48+
49+
/**
50+
* The magnitude of the fee, in the specified units, with an optional description.
51+
*
52+
* <p>This is a list because a single operation can involve multiple fees.
53+
*/
54+
List<Fee> fee;
55+
56+
/**
57+
* The type of the fee.
58+
*
59+
* <p>We will use "premium" for fees on premium names, and omit the field otherwise.
60+
*/
61+
@XmlElement(name = "class")
62+
String feeClass;
63+
64+
/** The effective date that the check is to be performed on (if specified in the query). */
65+
@XmlElement(name = "date")
66+
DateTime effectiveDate;
67+
68+
/** The date after which the quoted fee is no longer valid (if applicable). */
69+
@XmlElement(name = "notAfter")
70+
DateTime notAfterDate;
71+
72+
public String getFeeClass() {
73+
return feeClass;
74+
}
75+
76+
/** Builder for {@link FeeCheckResponseExtensionItemCommandStdV1}. */
77+
public static class Builder extends Buildable.Builder<FeeCheckResponseExtensionItemCommandStdV1> {
78+
79+
public Builder setCommandName(CommandName commandName) {
80+
getInstance().commandName = Ascii.toLowerCase(commandName.name());
81+
return this;
82+
}
83+
84+
public Builder setPhase(String phase) {
85+
getInstance().phase = phase;
86+
return this;
87+
}
88+
89+
public Builder setSubphase(String subphase) {
90+
getInstance().subphase = subphase;
91+
return this;
92+
}
93+
94+
public Builder setPeriod(Period period) {
95+
getInstance().period = period;
96+
return this;
97+
}
98+
99+
public Builder setEffectiveDate(DateTime effectiveDate) {
100+
getInstance().effectiveDate = effectiveDate;
101+
return this;
102+
}
103+
104+
public Builder setNotAfterDate(DateTime notAfterDate) {
105+
getInstance().notAfterDate = notAfterDate;
106+
return this;
107+
}
108+
109+
public Builder setFee(List<Fee> fees) {
110+
getInstance().fee = forceEmptyToNull(ImmutableList.copyOf(fees));
111+
return this;
112+
}
113+
114+
public Builder setClass(String feeClass) {
115+
getInstance().feeClass = feeClass;
116+
return this;
117+
}
118+
}
119+
}

0 commit comments

Comments
 (0)