mirror of
https://github.com/google/nomulus
synced 2026-06-09 16:33:02 +00:00
Compare commits
20 Commits
nomulus-20
...
nomulus-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bc07349a4 | ||
|
|
00522fb618 | ||
|
|
ad992beff9 | ||
|
|
ba91141505 | ||
|
|
c1ce73db49 | ||
|
|
00ceb6a7df | ||
|
|
c731b18304 | ||
|
|
5fd6e6cdaa | ||
|
|
53b92d602e | ||
|
|
b3fc57c7f7 | ||
|
|
bd70cd91a5 | ||
|
|
73725e94fe | ||
|
|
c3f8ec8c85 | ||
|
|
3894ca6971 | ||
|
|
5f06581572 | ||
|
|
17b851de42 | ||
|
|
d30cc202d2 | ||
|
|
0998d5485c | ||
|
|
1bff89085b | ||
|
|
d9d83205c7 |
30
.gemini/skills/java-ast-refactoring/SKILL.md
Normal file
30
.gemini/skills/java-ast-refactoring/SKILL.md
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: java-ast-refactoring
|
||||
description: "AST-aware Java refactoring using OpenRewrite. Use when asked to structurally refactor Java code, change class names, change method signatures/overloads, replace builder patterns, modify annotations, or perform cross-file structural replacements. Note: Renaming fields or local variables/parameters is not supported natively via simple YAML recipes in the standard openrewrite modules."
|
||||
---
|
||||
|
||||
# AST-Aware Java Refactoring
|
||||
|
||||
This skill uses OpenRewrite to perform Abstract Syntax Tree (AST) based refactoring on Java codebases. This is highly preferred over text-based regex or python scripts because it understands Java semantics, correctly updates imports, and preserves formatting.
|
||||
|
||||
## Parameter and Field Renaming (Last Resort)
|
||||
|
||||
Because OpenRewrite's YAML recipes do not natively support simple variable or field renaming, a custom script is provided:
|
||||
```bash
|
||||
python3 .gemini/skills/java-ast-refactoring/scripts/safe_rename.py <filepath> <old_name> <new_name>
|
||||
```
|
||||
**CRITICAL:** Running this python script is a LAST RESORT. It is a regex-based token replacement that ignores strings and comments, but it lacks true AST understanding. ALWAYS prefer using OpenRewrite recipes (`rewrite.yml`) for structural changes like renaming classes, methods, or moving targets, as OpenRewrite correctly handles imports, types, and cross-file references safely.
|
||||
|
||||
## Usage
|
||||
|
||||
1. Create a `rewrite.yml` recipe file in the workspace root. Refer to `.gemini/skills/java-ast-refactoring/references/rewrite_recipes.md` for syntax.
|
||||
2. Execute the script:
|
||||
```bash
|
||||
./.gemini/skills/java-ast-refactoring/scripts/run_rewrite.sh rewrite.yml
|
||||
```
|
||||
3. The script will safely apply the AST transformations and then automatically run `./gradlew spotlessApply` and `google-java-format --replace` on the modified files to automatically fix any Checkstyle line-length and import ordering issues caused by longer/shorter identifiers. Verify the output using `git diff`.
|
||||
4. **MANDATORY:** Always run `./gradlew build -x test` (or the equivalent compile task) after running OpenRewrite to ensure no compilation errors were introduced.
|
||||
|
||||
## Known Limitations & Troubleshooting
|
||||
* **Static Imports Dropped on Class Rename:** When using `ChangeType` to rename a class, OpenRewrite may sometimes drop static imports for fields/constants belonging to the old class instead of updating them to the new class. If compilation fails due to "cannot find symbol" for a constant after a class rename, manually restore the static import (e.g., `import static com.new.ClassName.CONSTANT;`).
|
||||
* **Continuous Improvement:** If any new issues or edge cases are found while running the refactoring (e.g., build failures, formatting issues, or missed transformations), proactively update this skill file (`SKILL.md`) and its accompanying scripts (`scripts/run_rewrite.sh`, `scripts/safe_rename.py`) to permanently fix the issue for future use.
|
||||
@@ -0,0 +1,82 @@
|
||||
# OpenRewrite Recipe Reference
|
||||
|
||||
OpenRewrite uses declarative YAML recipes to perform structural refactorings.
|
||||
|
||||
## Recipe Structure
|
||||
|
||||
A recipe file must have a `type`, a `name` (which you will activate), and a `recipeList` containing specific core recipes to execute sequentially.
|
||||
|
||||
```yaml
|
||||
type: specs.openrewrite.org/v1beta/recipe
|
||||
name: com.example.MyRefactoring
|
||||
recipeList:
|
||||
- <CoreRecipe>:
|
||||
<argument1>: <value>
|
||||
```
|
||||
|
||||
## Core Recipes for Common Operations
|
||||
|
||||
### 1. Change Method Name
|
||||
```yaml
|
||||
- org.openrewrite.java.ChangeMethodName:
|
||||
methodPattern: java.util.Collections emptyList()
|
||||
newMethodName: emptyList
|
||||
```
|
||||
|
||||
### 2. Change Method Target to Static
|
||||
Moves a method call to a new static method target. Useful for replacing custom utility methods with standard ones.
|
||||
```yaml
|
||||
- org.openrewrite.java.ChangeMethodTargetToStatic:
|
||||
methodPattern: google.registry.model.eppinput.EppInputs createDomain(java.lang.String, java.lang.String)
|
||||
fullyQualifiedTargetTypeName: google.registry.model.domain.DomainCommand.Create
|
||||
returnType: google.registry.model.domain.DomainCommand.Create.Builder
|
||||
```
|
||||
|
||||
### 3. Change Type (Rename/Move Class)
|
||||
Updates the class name and automatically updates all imports across the codebase.
|
||||
*Note: OpenRewrite occasionally drops `import static` references to fields inside the renamed class. Be prepared to manually restore them if a compilation error occurs.*
|
||||
```yaml
|
||||
- org.openrewrite.java.ChangeType:
|
||||
oldFullyQualifiedTypeName: org.joda.time.Instant
|
||||
newFullyQualifiedTypeName: java.time.Instant
|
||||
```
|
||||
|
||||
### 4. Remove Unused Imports
|
||||
```yaml
|
||||
- org.openrewrite.java.RemoveUnusedImports
|
||||
```
|
||||
|
||||
### 5. Change Annotation
|
||||
```yaml
|
||||
- org.openrewrite.java.ChangeAnnotation:
|
||||
annotationPattern: @org.junit.Ignore
|
||||
newAnnotation: @org.junit.jupiter.api.Disabled
|
||||
```
|
||||
|
||||
### 6. Remove Annotation
|
||||
```yaml
|
||||
- org.openrewrite.java.RemoveAnnotation:
|
||||
annotationPattern: @java.lang.SuppressWarnings("unchecked")
|
||||
```
|
||||
|
||||
### 7. Change Method Arguments
|
||||
Reorders or removes arguments based on a target signature. `newArgumentTemplate` uses 0-based indexing.
|
||||
```yaml
|
||||
- org.openrewrite.java.ChangeMethodAccessLevel:
|
||||
methodPattern: com.google.common.collect.ImmutableList of(..)
|
||||
newAccessLevel: protected
|
||||
```
|
||||
|
||||
### 8. Add Import
|
||||
```yaml
|
||||
- org.openrewrite.java.AddImport:
|
||||
type: java.util.List
|
||||
```
|
||||
|
||||
## Method Patterns
|
||||
OpenRewrite uses a specific pointcut expression language for `methodPattern`:
|
||||
* `[return-type] [fully-qualified-class-name] [method-name]([parameter-types])`
|
||||
* `*` matches any type.
|
||||
* `..` matches any number of parameters.
|
||||
* Example: `java.lang.String split(java.lang.String, int)`
|
||||
* Example: `* java.util.List add(..)`
|
||||
87
.gemini/skills/java-ast-refactoring/scripts/run_rewrite.sh
Executable file
87
.gemini/skills/java-ast-refactoring/scripts/run_rewrite.sh
Executable file
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2026 The Nomulus Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Wrapper script to dynamically execute OpenRewrite without modifying build.gradle
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <path-to-rewrite.yml>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RECIPE_FILE=$(realpath "$1")
|
||||
if [ ! -f "$RECIPE_FILE" ]; then
|
||||
echo "Error: Recipe file $RECIPE_FILE not found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract the name of the recipe from the YAML to activate it
|
||||
RECIPE_NAME=$(grep -oP '(?<=name: ).*' "$RECIPE_FILE" | head -n 1)
|
||||
|
||||
if [ -z "$RECIPE_NAME" ]; then
|
||||
echo "Error: Could not extract 'name:' from $RECIPE_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
INIT_SCRIPT="rewrite-init.gradle"
|
||||
|
||||
cat << EOF > "$INIT_SCRIPT"
|
||||
initscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.openrewrite.rewrite:org.openrewrite.rewrite.gradle.plugin:7.33.0")
|
||||
}
|
||||
}
|
||||
|
||||
rootProject {
|
||||
apply plugin: org.openrewrite.gradle.RewritePlugin
|
||||
|
||||
rewrite {
|
||||
activeRecipe("$RECIPE_NAME")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
rewrite("org.openrewrite.recipe:rewrite-testing-frameworks:2.14.0")
|
||||
rewrite("org.openrewrite.recipe:rewrite-migrate-java:2.11.0")
|
||||
rewrite("org.openrewrite.recipe:rewrite-spring:5.7.0")
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
apply plugin: org.openrewrite.gradle.RewritePlugin
|
||||
}
|
||||
EOF
|
||||
|
||||
# Copy the recipe file to the workspace root temporarily so OpenRewrite finds it
|
||||
cp "$RECIPE_FILE" ./rewrite.yml
|
||||
|
||||
echo "Executing OpenRewrite recipe: $RECIPE_NAME"
|
||||
./gradlew --init-script "$INIT_SCRIPT" rewriteRun --no-parallel --no-configuration-cache
|
||||
|
||||
echo "Running code formatters to fix Checkstyle line-length and import ordering..."
|
||||
./gradlew spotlessApply
|
||||
|
||||
# Automatically handle line-wrapping and formatting for all files modified by OpenRewrite
|
||||
MODIFIED_JAVA_FILES=$(git diff --name-only --diff-filter=d | grep "\.java$" || true)
|
||||
if [ -n "$MODIFIED_JAVA_FILES" ]; then
|
||||
echo "Applying google-java-format to all modified Java files to enforce LineLength..."
|
||||
echo "$MODIFIED_JAVA_FILES" | xargs -r google-java-format --replace
|
||||
fi
|
||||
|
||||
# Clean up temporary files
|
||||
rm "$INIT_SCRIPT"
|
||||
rm ./rewrite.yml
|
||||
64
.gemini/skills/java-ast-refactoring/scripts/safe_rename.py
Normal file
64
.gemini/skills/java-ast-refactoring/scripts/safe_rename.py
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2026 The Nomulus Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
|
||||
def usage():
|
||||
print("Usage: python safe_rename.py <filepath> <old_name> <new_name>")
|
||||
print("Safely renames an identifier in a Java file, ignoring strings and comments.")
|
||||
sys.exit(1)
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 4:
|
||||
usage()
|
||||
|
||||
filepath = sys.argv[1]
|
||||
old_name = sys.argv[2]
|
||||
new_name = sys.argv[3]
|
||||
|
||||
if not os.path.exists(filepath):
|
||||
print(f"Error: File {filepath} not found.")
|
||||
sys.exit(1)
|
||||
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Regex to tokenize Java source safely.
|
||||
token_pattern = re.compile(
|
||||
r'(?P<string>"(?:\\.|[^"\\])*")|'
|
||||
r'(?P<char>\'(?:\\.|[^\'\\])*\')|'
|
||||
r'(?P<line_comment>//.*)|'
|
||||
r'(?P<block_comment>/\*[\s\S]*?\*/)|'
|
||||
r'(?P<ident>[a-zA-Z_$][a-zA-Z0-9_$]*)'
|
||||
)
|
||||
|
||||
def replacer(match):
|
||||
if match.group('ident') == old_name:
|
||||
return new_name
|
||||
return match.group(0)
|
||||
|
||||
new_content = token_pattern.sub(replacer, content)
|
||||
|
||||
if content == new_content:
|
||||
print(f"No occurrences of '{old_name}' found to rename in {filepath}.")
|
||||
else:
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(new_content)
|
||||
print(f"Successfully renamed '{old_name}' to '{new_name}' in {filepath}.")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
40
.gemini/skills/pr-polisher/SKILL.md
Normal file
40
.gemini/skills/pr-polisher/SKILL.md
Normal file
@@ -0,0 +1,40 @@
|
||||
---
|
||||
name: pr-polisher
|
||||
description: Automated pre-flight checklist to polish PRs. Use this before declaring a task or PR complete to automatically verify license headers, commit hygiene, formatting, and codebase mandates.
|
||||
---
|
||||
|
||||
# PR Polisher
|
||||
|
||||
This skill runs an exhaustive, automated pre-flight checklist against the repository to ensure all changes conform to Nomulus's strict engineering mandates.
|
||||
|
||||
## When to Use
|
||||
|
||||
You MUST activate and execute this workflow immediately before you are about to declare a PR, task, or codebase refactor "done" or ready for human review. Do not declare the task complete until this workflow succeeds with 0 errors.
|
||||
|
||||
## Workflow Execution Steps
|
||||
|
||||
1. **Run the Automated Analysis Script**
|
||||
Execute the packaged Python diff-checker script. This script automatically checks commit messages, working tree status, `package-lock.json` modifications, copyright years on new files, and a litany of anti-patterns using regex (e.g., fully-qualified names, incorrect clock injections, generic exception catching).
|
||||
|
||||
```bash
|
||||
python3 ./pr-polisher/scripts/check_diff.py
|
||||
```
|
||||
|
||||
2. **Run Formatting Validation**
|
||||
Always run the project's formatting tools to ensure checkstyle passes.
|
||||
```bash
|
||||
./gradlew spotlessCheck
|
||||
# OR if formatting is needed:
|
||||
./gradlew spotlessApply && ./gradlew javaIncrementalFormatApply
|
||||
```
|
||||
|
||||
3. **Verify Test Coverage Additions**
|
||||
Review your diff (`git diff HEAD^`). If you have added any *new* public methods or modified core logic, manually verify that you have added tests to the corresponding `Test.java` file. A code review is not thorough if it only checks for compilation.
|
||||
|
||||
4. **Address Errors & Amend**
|
||||
If any script throws an error, or if formatting changes were applied, you must stage those fixes and amend your commit:
|
||||
```bash
|
||||
git add -u
|
||||
git commit --amend --no-edit
|
||||
```
|
||||
Loop back to Step 1 until the `check_diff.py` script returns `0 ERRORS` and the working directory is clean.
|
||||
189
.gemini/skills/pr-polisher/scripts/check_diff.py
Executable file
189
.gemini/skills/pr-polisher/scripts/check_diff.py
Executable file
@@ -0,0 +1,189 @@
|
||||
#!/usr/bin/env python3
|
||||
import subprocess
|
||||
import re
|
||||
import sys
|
||||
import datetime
|
||||
|
||||
# Color codes
|
||||
RED = "\03.3[91m"
|
||||
YELLOW = "\03.3[93m"
|
||||
GREEN = "\03.3[92m"
|
||||
RESET = "\03.3[0m"
|
||||
|
||||
errors_found = 0
|
||||
warnings_found = 0
|
||||
|
||||
def log_error(msg):
|
||||
global errors_found
|
||||
errors_found += 1
|
||||
print(f"{RED}[ERROR]{RESET} {msg}")
|
||||
|
||||
def log_warning(msg):
|
||||
global warnings_found
|
||||
warnings_found += 1
|
||||
print(f"{YELLOW}[WARNING]{RESET} {msg}")
|
||||
|
||||
def log_success(msg):
|
||||
print(f"{GREEN}[OK]{RESET} {msg}")
|
||||
|
||||
def run_cmd(cmd):
|
||||
return subprocess.check_output(cmd, shell=True, text=True).strip()
|
||||
|
||||
def check_commit_message():
|
||||
print("--- Checking Commit Message ---")
|
||||
try:
|
||||
msg = run_cmd("git log -1 --pretty=format:%B")
|
||||
lines = msg.split('\n')
|
||||
subject = lines[0]
|
||||
if len(subject) > 50:
|
||||
log_error(f"Commit subject exceeds 50 characters ({len(subject)} chars): '{subject}'")
|
||||
if not subject[0].isupper():
|
||||
log_error(f"Commit subject must be capitalized: '{subject}'")
|
||||
if subject[-1] in ['.', '!', '?']:
|
||||
log_error(f"Commit subject must not end with punctuation: '{subject}'")
|
||||
else:
|
||||
log_success("Commit message format looks good.")
|
||||
except Exception as e:
|
||||
log_error(f"Failed to check commit message: {e}")
|
||||
|
||||
def check_workspace_clean():
|
||||
print("\n--- Checking Workspace State ---")
|
||||
status = run_cmd("git status --porcelain")
|
||||
if status:
|
||||
log_error("Workspace is not clean. Uncommitted changes found:\n" + status)
|
||||
else:
|
||||
log_success("Working directory is clean.")
|
||||
|
||||
def check_package_lock():
|
||||
print("\n--- Checking package-lock.json ---")
|
||||
diff_files = run_cmd("git diff HEAD^ --name-only").split('\n')
|
||||
if "console-webapp/package-lock.json" in diff_files:
|
||||
log_error("console-webapp/package-lock.json is modified in the diff. Unless NPM dependencies were explicitly changed, revert this file using: git checkout console-webapp/package-lock.json")
|
||||
else:
|
||||
log_success("console-webapp/package-lock.json is untouched.")
|
||||
|
||||
def check_license_headers():
|
||||
print("\n--- Checking License Headers on New Files ---")
|
||||
current_year = str(datetime.datetime.now().year)
|
||||
added_files = run_cmd("git diff HEAD^ --name-status --diff-filter=A").split('\n')
|
||||
added_java_files = [f.split('\t')[-1] for f in added_files if f.endswith('.java')]
|
||||
|
||||
expected_header = f"// Copyright {current_year} The Nomulus Authors. All Rights Reserved."
|
||||
for f in added_java_files:
|
||||
try:
|
||||
with open(f, 'r') as file:
|
||||
content = file.read()
|
||||
if expected_header not in content:
|
||||
log_error(f"Missing or incorrect copyright year in {f}. Expected: {expected_header}")
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
if not added_java_files:
|
||||
log_success("No new Java files added.")
|
||||
|
||||
def check_diff_anti_patterns():
|
||||
print("\n--- Checking Code Anti-Patterns in Diff ---")
|
||||
diff = run_cmd("git diff HEAD^ -U0")
|
||||
current_file = ""
|
||||
|
||||
# Regex Patterns
|
||||
fqn_pattern = re.compile(r'(?<!import\s)(java\.[a-z0-9.]+\.[A-Z][a-zA-Z0-9]+|google\.registry\.[a-z0-9.]+\.[A-Z][a-zA-Z0-9]+)')
|
||||
visibility_pattern = re.compile(r'/\*\s*package\s*\*/')
|
||||
utc_pattern = re.compile(r'ZoneId\.of\("UTC"\)')
|
||||
now_pattern = re.compile(r'(Instant\.now\(\)|OffsetDateTime\.now\(\)|System\.currentTimeMillis\(\))')
|
||||
catch_generic_pattern = re.compile(r'catch\s*\(\s*(Exception|Throwable)\s+[a-zA-Z0-9_]+\s*\)')
|
||||
is_equal_optional_pattern = re.compile(r'\.isEqualTo\(Optional\.of\(')
|
||||
sleep_pattern = re.compile(r'Thread\.sleep\(')
|
||||
suppress_pattern = re.compile(r'@SuppressWarnings\(')
|
||||
wrong_nullable_pattern = re.compile(r'import\s+(?!javax\.annotation\.Nullable;)[a-zA-Z0-9_.]+\.Nullable;')
|
||||
utility_class_pattern = re.compile(r'\b(DateTimeUtils|CacheUtils)\.[a-z]')
|
||||
redundant_tx_pattern = re.compile(r'tm\(\)\.transact\(\s*\(\)\s*->\s*tm\(\)\.reTransact')
|
||||
mutable_collection_pattern = re.compile(r'new\s+(ArrayList|HashMap|HashSet)\s*[<()]')
|
||||
|
||||
suppress_count = 0
|
||||
|
||||
for line in diff.split('\n'):
|
||||
if line.startswith('+++ b/'):
|
||||
current_file = line[6:]
|
||||
suppress_count = 0
|
||||
continue
|
||||
|
||||
if line.startswith('+') and not line.startswith('+++') and current_file.endswith('.java'):
|
||||
code_line = line[1:]
|
||||
|
||||
# FQN Check
|
||||
fqn_matches = fqn_pattern.findall(code_line)
|
||||
if fqn_matches:
|
||||
# Skip if the match is exactly part of an import or package declaration
|
||||
if not code_line.strip().startswith('import') and not code_line.strip().startswith('package'):
|
||||
log_warning(f"[{current_file}] Potential Fully-Qualified Name found: {fqn_matches}. Use imports instead.")
|
||||
|
||||
# Package visibility
|
||||
if visibility_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Found '/* package */' modifier. Leave modifier blank instead.")
|
||||
|
||||
# Time zones
|
||||
if utc_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Found ZoneId.of(\"UTC\"). Use statically imported ZoneOffset.UTC instead.")
|
||||
|
||||
# System clocks
|
||||
if now_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Found un-injected clock (Instant.now / System.currentTimeMillis). Inject Clock instead.")
|
||||
|
||||
# Catch generic
|
||||
if catch_generic_pattern.search(code_line):
|
||||
log_warning(f"[{current_file}] Catching generic Exception/Throwable. Use specific exceptions.")
|
||||
|
||||
# Truth Optionals
|
||||
if is_equal_optional_pattern.search(code_line):
|
||||
log_warning(f"[{current_file}] Found .isEqualTo(Optional.of(...)). Use Truth's .hasValue(...) instead.")
|
||||
|
||||
# Thread.sleep
|
||||
if sleep_pattern.search(code_line):
|
||||
log_warning(f"[{current_file}] Found Thread.sleep(). Use Sleeper instead in tests.")
|
||||
|
||||
# SuppressWarnings
|
||||
if suppress_pattern.search(code_line):
|
||||
suppress_count += 1
|
||||
if suppress_count > 1:
|
||||
log_error(f"[{current_file}] Multiple @SuppressWarnings detected. They must be merged (e.g. {{\"unchecked\", \"foo\"}}).")
|
||||
else:
|
||||
suppress_count = 0
|
||||
|
||||
# Wrong Nullable
|
||||
if wrong_nullable_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Found incorrect Nullable import. Always use javax.annotation.Nullable.")
|
||||
|
||||
# Missing static imports for utilities
|
||||
if utility_class_pattern.search(code_line):
|
||||
if not code_line.strip().startswith('import'):
|
||||
log_warning(f"[{current_file}] Found un-statically imported method from DateTimeUtils/CacheUtils. Use static imports.")
|
||||
|
||||
# Redundant transaction wrapping
|
||||
if redundant_tx_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Found redundant transaction wrapping (tm().transact(() -> tm().reTransact(...))).")
|
||||
|
||||
# Mutable collection instantiation
|
||||
if mutable_collection_pattern.search(code_line):
|
||||
log_warning(f"[{current_file}] Found mutable collection instantiation (ArrayList/HashMap/HashSet). Prefer Guava Immutable collections.")
|
||||
|
||||
def main():
|
||||
print("========================================")
|
||||
print(" NOMULUS PR POLISHER CHECKLIST ")
|
||||
print("========================================\n")
|
||||
|
||||
check_commit_message()
|
||||
check_workspace_clean()
|
||||
check_package_lock()
|
||||
check_license_headers()
|
||||
check_diff_anti_patterns()
|
||||
|
||||
print("\n========================================")
|
||||
if errors_found == 0 and warnings_found == 0:
|
||||
print(f"{GREEN}SUCCESS: All checks passed. PR is polished!{RESET}")
|
||||
else:
|
||||
print(f"RESULTS: {RED}{errors_found} ERRORS{RESET}, {YELLOW}{warnings_found} WARNINGS{RESET}")
|
||||
print("Please address the above issues before declaring the PR complete.")
|
||||
sys.exit(1 if errors_found > 0 else 0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
48
.github/workflows/update-dependency-reminder.yml
vendored
Normal file
48
.github/workflows/update-dependency-reminder.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: Request Lockfile Review
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
branches: ["master"]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
review-lockfiles:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
# We intentionally do NOT use actions/checkout here.
|
||||
# This keeps the environment completely secure and satisfies CodeQL.
|
||||
|
||||
- name: Check files via GitHub API
|
||||
id: check_files
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const prNumber = context.payload.pull_request.number;
|
||||
|
||||
// Get the list of files in the PR directly from the API
|
||||
const { data: files } = await github.rest.pulls.listFiles({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: prNumber,
|
||||
per_page: 100
|
||||
});
|
||||
|
||||
// Look for any file **ending** in gradle.lockfile
|
||||
const hasLockfile = files.some(file => file.filename.endsWith('gradle.lockfile'));
|
||||
core.setOutput('has_lockfile', hasLockfile ? 'true' : 'false');
|
||||
|
||||
- name: Post unresolved review comment
|
||||
if: steps.check_files.outputs.has_lockfile == 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
await github.rest.pulls.createReview({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.payload.pull_request.number,
|
||||
event: 'REQUEST_CHANGES',
|
||||
body: `### ⚠️ Attention Required: Lockfile Detected\nThis pull request contains modifications to one or more \`*.lockfile\` files. Please confirm that you have run update_dependency.sh to push new dependencies to the private repo.\n\n_Someone with Admin role must manually dismiss this review before merging._`
|
||||
});
|
||||
@@ -58,6 +58,7 @@ dependencies {
|
||||
implementation deps['com.google.code.findbugs:jsr305']
|
||||
implementation deps['com.google.guava:guava']
|
||||
implementation deps['jakarta.inject:jakarta.inject-api']
|
||||
implementation deps['org.freemarker:freemarker']
|
||||
implementation deps['com.google.flogger:flogger']
|
||||
implementation deps['io.github.java-diff-utils:java-diff-utils']
|
||||
implementation deps['com.google.truth:truth']
|
||||
|
||||
@@ -34,7 +34,7 @@ commons-collections:commons-collections:3.2.2=checkstyle
|
||||
info.picocli:picocli:4.7.7=checkstyle
|
||||
io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
io.github.java-diff-utils:java-diff-utils:4.16=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
io.github.java-diff-utils:java-diff-utils:4.17=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
jakarta.inject:jakarta.inject-api:2.0.1=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
javax.inject:javax.inject:1=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
junit:junit:4.13.2=testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
@@ -60,6 +60,7 @@ org.codehaus.plexus:plexus-classworlds:2.6.0=checkstyle
|
||||
org.codehaus.plexus:plexus-component-annotations:2.1.0=checkstyle
|
||||
org.codehaus.plexus:plexus-container-default:2.1.0=checkstyle
|
||||
org.codehaus.plexus:plexus-utils:3.3.0=checkstyle
|
||||
org.freemarker:freemarker:2.3.34=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
org.jacoco:org.jacoco.agent:0.8.14=jacocoAgent,jacocoAnt
|
||||
org.jacoco:org.jacoco.ant:0.8.14=jacocoAnt
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright 2026 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.util;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import freemarker.core.HTMLOutputFormat;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.Template;
|
||||
import freemarker.template.TemplateExceptionHandler;
|
||||
import jakarta.inject.Inject;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* A utility class for rendering FreeMarker templates.
|
||||
*
|
||||
* <p>This renderer is configured to use HTML as the default output format, which enables automatic
|
||||
* escaping of all interpolated variables. It also uses the "computer" number format to ensure
|
||||
* consistent formatting of numeric values across different locales.
|
||||
*/
|
||||
public class TemplateRenderer {
|
||||
|
||||
private final Configuration configuration;
|
||||
|
||||
@Inject
|
||||
public TemplateRenderer() {
|
||||
this.configuration = new Configuration(Configuration.VERSION_2_3_32);
|
||||
this.configuration.setClassLoaderForTemplateLoading(getClass().getClassLoader(), "");
|
||||
this.configuration.setDefaultEncoding("UTF-8");
|
||||
this.configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
|
||||
this.configuration.setLogTemplateExceptions(false);
|
||||
this.configuration.setWrapUncheckedExceptions(true);
|
||||
this.configuration.setFallbackOnNullLoopVariable(false);
|
||||
this.configuration.setOutputFormat(HTMLOutputFormat.INSTANCE);
|
||||
this.configuration.setNumberFormat("computer");
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the specified template with the given data model.
|
||||
*
|
||||
* @param templatePath the path to the template file relative to the classpath root
|
||||
* @param dataModel an immutable map containing the data to be used in the template
|
||||
* @return the rendered template as a string
|
||||
* @throws RuntimeException if the template cannot be found, parsed, or processed
|
||||
*/
|
||||
public String render(String templatePath, ImmutableMap<String, Object> dataModel) {
|
||||
try {
|
||||
Template template = configuration.getTemplate(templatePath);
|
||||
StringWriter writer = new StringWriter();
|
||||
template.process(dataModel, writer);
|
||||
return writer.toString();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(String.format("Error rendering template %s", templatePath), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright 2026 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.util;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link TemplateRenderer}. */
|
||||
class TemplateRendererTest {
|
||||
|
||||
private final TemplateRenderer renderer = new TemplateRenderer();
|
||||
|
||||
@Test
|
||||
void testRender_success() {
|
||||
ImmutableMap<String, Object> data =
|
||||
ImmutableMap.of(
|
||||
"name", "World", "score", 42, "showMessage", true, "message", "Keep going!");
|
||||
String result = renderer.render("google/registry/util/test_template.ftl", data);
|
||||
assertThat(result).isEqualTo("Hello World!\nYour score is 42.\nMessage: Keep going!\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRender_conditional_false() {
|
||||
ImmutableMap<String, Object> data =
|
||||
ImmutableMap.of("name", "User", "score", 0, "showMessage", false);
|
||||
String result = renderer.render("google/registry/util/test_template.ftl", data);
|
||||
assertThat(result).isEqualTo("Hello User!\nYour score is 0.\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRender_htmlEscaping() {
|
||||
ImmutableMap<String, Object> data =
|
||||
ImmutableMap.of("name", "<b>World</b>", "score", 42, "showMessage", false);
|
||||
String result = renderer.render("google/registry/util/test_template.ftl", data);
|
||||
assertThat(result).contains("Hello <b>World</b>!");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRender_missingTemplate_throwsException() {
|
||||
assertThrows(
|
||||
RuntimeException.class,
|
||||
() -> renderer.render("non/existent/template.ftl", ImmutableMap.of()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRender_missingVariable_throwsException() {
|
||||
// The template expects 'name', 'score', and 'showMessage', but the map is empty.
|
||||
assertThrows(
|
||||
RuntimeException.class,
|
||||
() -> renderer.render("google/registry/util/test_template.ftl", ImmutableMap.of()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRender_unusedVariable_ignored() {
|
||||
ImmutableMap<String, Object> data =
|
||||
ImmutableMap.of(
|
||||
"name",
|
||||
"User",
|
||||
"score",
|
||||
100,
|
||||
"showMessage",
|
||||
false,
|
||||
"unusedKey",
|
||||
"This should be ignored");
|
||||
String result = renderer.render("google/registry/util/test_template.ftl", data);
|
||||
assertThat(result).isEqualTo("Hello User!\nYour score is 100.\n");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<#-- Copyright 2026 The Nomulus Authors. All Rights Reserved. -->
|
||||
Hello ${name}!
|
||||
Your score is ${score}.
|
||||
<#if showMessage>
|
||||
Message: ${message}
|
||||
</#if>
|
||||
@@ -90,15 +90,15 @@ PRESUBMITS = {
|
||||
# License check
|
||||
PresubmitCheck(
|
||||
r".*Copyright 20\d{2} The Nomulus Authors\. All Rights Reserved\.",
|
||||
("java", "js", "soy", "sql", "py", "sh", "gradle", "ts"), {
|
||||
("java", "js", "sql", "py", "sh", "gradle", "ts", "ftl"), {
|
||||
".git", "/build/", "node_modules/", "LoggerConfig.java", "registrar_bin.",
|
||||
"registrar_dbg.", "google-java-format-diff.py",
|
||||
"nomulus.golden.sql", "soyutils_usegoog.js", "javascript/checks.js"
|
||||
"nomulus.golden.sql", "javascript/checks.js"
|
||||
}, REQUIRED):
|
||||
"File did not include the license header.",
|
||||
|
||||
# Files must end in a newline
|
||||
PresubmitCheck(r".*\n$", ("java", "js", "soy", "sql", "py", "sh", "gradle", "ts", "xml"),
|
||||
PresubmitCheck(r".*\n$", ("java", "js", "sql", "py", "sh", "gradle", "ts", "xml", "ftl"),
|
||||
{"node_modules/", ".idea"}, REQUIRED):
|
||||
"Source files must end in a newline.",
|
||||
|
||||
@@ -127,33 +127,6 @@ PRESUBMITS = {
|
||||
"System.(out|err).println is only allowed in tools/ packages. Please "
|
||||
"use a logger instead.",
|
||||
|
||||
# Various Soy linting checks
|
||||
PresubmitCheck(
|
||||
r".* (/\*)?\* {?@param ",
|
||||
"soy",
|
||||
{},
|
||||
):
|
||||
"In SOY please use the ({@param name: string} /** User name. */) style"
|
||||
" parameter passing instead of the ( * @param name User name.) style "
|
||||
"parameter passing.",
|
||||
PresubmitCheck(
|
||||
r'.*\{[^}]+\w+:\s+"',
|
||||
"soy",
|
||||
{},
|
||||
):
|
||||
"Please don't use double-quoted string literals in Soy parameters",
|
||||
PresubmitCheck(
|
||||
r'.*autoescape\s*=\s*"[^s]',
|
||||
"soy",
|
||||
{},
|
||||
):
|
||||
"All soy templates must use strict autoescaping",
|
||||
PresubmitCheck(
|
||||
r".*noAutoescape",
|
||||
"soy",
|
||||
{},
|
||||
):
|
||||
"All soy templates must use strict autoescaping",
|
||||
PresubmitCheck(
|
||||
r".*\nimport\s+(?:static\s+)?.*\.shaded\..*",
|
||||
"java",
|
||||
|
||||
@@ -23,7 +23,11 @@ import { MaterialModule } from './material.module';
|
||||
|
||||
import { BackendService } from './shared/services/backend.service';
|
||||
|
||||
import { provideHttpClient } from '@angular/common/http';
|
||||
import {
|
||||
HttpClientXsrfModule,
|
||||
provideHttpClient,
|
||||
withInterceptorsFromDi,
|
||||
} from '@angular/common/http';
|
||||
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
|
||||
import { BillingInfoComponent } from './billingInfo/billingInfo.component';
|
||||
import {
|
||||
@@ -118,6 +122,10 @@ export class SelectedRegistrarModule {}
|
||||
MaterialModule,
|
||||
SelectedRegistrarModule,
|
||||
SnackBarModule,
|
||||
HttpClientXsrfModule.withOptions({
|
||||
cookieName: 'X-CSRF-Token',
|
||||
headerName: 'X-CSRF-Token',
|
||||
}),
|
||||
],
|
||||
providers: [
|
||||
BackendService,
|
||||
@@ -130,7 +138,7 @@ export class SelectedRegistrarModule {}
|
||||
subscriptSizing: 'dynamic',
|
||||
},
|
||||
},
|
||||
provideHttpClient(),
|
||||
provideHttpClient(withInterceptorsFromDi()),
|
||||
],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
||||
@@ -94,7 +94,6 @@ processTestResources {
|
||||
|
||||
configurations {
|
||||
jaxb
|
||||
soy
|
||||
devtool
|
||||
|
||||
nonprodImplementation.extendsFrom implementation
|
||||
@@ -120,7 +119,7 @@ configurations {
|
||||
// For reasons we do not understand, marking the following dependencies as
|
||||
// compileOnly instead of compile does not exclude them from runtimeClasspath.
|
||||
all {
|
||||
// servlet-api:3.1 pulled in but not used by soy compiler
|
||||
// servlet-api:3.1 pulled in but not used
|
||||
exclude group: 'javax.servlet', module: 'javax.servlet-api'
|
||||
}
|
||||
}
|
||||
@@ -166,10 +165,6 @@ dependencies {
|
||||
implementation deps['com.google.flogger:flogger']
|
||||
implementation deps['com.google.guava:guava']
|
||||
implementation deps['com.google.protobuf:protobuf-java']
|
||||
// Might need to add this back if we re-add nebula-lint
|
||||
// gradleLint.ignore('unused-dependency') {
|
||||
implementation deps['com.google.gwt:gwt-user']
|
||||
// }
|
||||
implementation deps['com.google.cloud:google-cloud-compute']
|
||||
implementation deps['com.google.cloud:google-cloud-core']
|
||||
implementation deps['com.google.cloud:google-cloud-storage']
|
||||
@@ -181,9 +176,9 @@ dependencies {
|
||||
implementation deps['com.google.oauth-client:google-oauth-client-jetty']
|
||||
implementation deps['com.google.oauth-client:google-oauth-client-servlet']
|
||||
implementation deps['com.google.re2j:re2j']
|
||||
implementation deps['com.google.template:soy']
|
||||
implementation deps['org.freemarker:freemarker']
|
||||
implementation deps['com.googlecode.json-simple:json-simple']
|
||||
implementation deps['com.jcraft:jsch']
|
||||
implementation deps['com.github.mwiede:jsch']
|
||||
implementation deps['com.zaxxer:HikariCP']
|
||||
implementation deps['com.squareup.okhttp3:okhttp']
|
||||
implementation deps['dnsjava:dnsjava']
|
||||
@@ -299,9 +294,6 @@ dependencies {
|
||||
jaxb deps['org.glassfish.jaxb:jaxb-runtime']
|
||||
jaxb deps['org.glassfish.jaxb:jaxb-xjc']
|
||||
|
||||
// Dependency needed for soy to java compilation.
|
||||
soy deps['com.google.template:soy']
|
||||
|
||||
// Flyway classes needed to generate the golden file.
|
||||
implementation deps['org.flywaydb:flyway-core']
|
||||
implementation deps['org.flywaydb:flyway-database-postgresql']
|
||||
@@ -371,62 +363,7 @@ task jaxbToJava {
|
||||
}
|
||||
}
|
||||
|
||||
task soyToJava {
|
||||
// Relative paths of soy directories.
|
||||
def spec11SoyDir = "google/registry/reporting/spec11/soy"
|
||||
def toolsSoyDir = "google/registry/tools/soy"
|
||||
|
||||
def soyRelativeDirs = [spec11SoyDir, toolsSoyDir]
|
||||
soyRelativeDirs.each {
|
||||
inputs.dir "${resourcesSourceDir}/${it}"
|
||||
outputs.dir "${generatedDir}/${it}"
|
||||
}
|
||||
|
||||
ext.soyToJava = { javaPackage, outputDirectory, soyFiles ->
|
||||
project.services.get(ExecOperations).javaexec {
|
||||
mainClass = "com.google.template.soy.SoyParseInfoGenerator"
|
||||
classpath = configurations.soy
|
||||
jvmArgs = ["--sun-misc-unsafe-memory-access=allow", "--enable-native-access=ALL-UNNAMED"]
|
||||
args = ["--javaPackage", "${javaPackage}",
|
||||
"--outputDirectory", "${outputDirectory}",
|
||||
"--javaClassNameSource", "filename",
|
||||
"--srcs", "${soyFiles.join(',')}"]
|
||||
}
|
||||
|
||||
// Replace the "@link" tags after the "@deprecated" tags in the generated
|
||||
// files. The soy compiler doesn't generate imports for these, causing
|
||||
// us to get warnings when we generate javadocs.
|
||||
// TODO(b/200296387): To be fair, the deprecations are accurate: we're
|
||||
// using the old "SoyInfo" classes instead of the new "Templates" files.
|
||||
// When we convert to the new classes, this hack can go away.
|
||||
def outputs = fileTree(outputDirectory) {
|
||||
include '**/*.java'
|
||||
}
|
||||
|
||||
outputs.each { file ->
|
||||
project.services.get(ExecOperations).exec {
|
||||
commandLine = ['sed', '-i""', '-e', 's/@link/LINK/g', file.getCanonicalPath()]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doLast {
|
||||
soyToJava('google.registry.tools.soy',
|
||||
"${generatedDir}/${toolsSoyDir}",
|
||||
fileTree(
|
||||
dir: "${resourcesSourceDir}/${toolsSoyDir}",
|
||||
include: ['**/*.soy']))
|
||||
|
||||
soyToJava('google.registry.reporting.spec11.soy',
|
||||
"${generatedDir}/${spec11SoyDir}",
|
||||
fileTree(
|
||||
dir: "${resourcesSourceDir}/${spec11SoyDir}",
|
||||
include: ['**/*.soy']))
|
||||
}
|
||||
}
|
||||
|
||||
compileJava.dependsOn jaxbToJava
|
||||
compileJava.dependsOn soyToJava
|
||||
|
||||
// Make testing artifacts available to be depended up on by other projects.
|
||||
// TODO: factor out google.registry.testing to be a separate project.
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
aopalliance:aopalliance:1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
args4j:args4j:2.33=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
args4j:args4j:2.33=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.charleskorn.kaml:kaml:0.20.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.21=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.core:jackson-core:2.20.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -27,6 +26,7 @@ com.github.jnr:jnr-posix:3.1.22=compileClasspath,deploy_jar,nonprodCompileClassp
|
||||
com.github.jnr:jnr-unixsocket:0.38.25=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-x86asm:1.0.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.github.mwiede:jsch:2.28.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.android:annotations:4.1.1.4=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api-client:google-api-client-jackson2:2.0.1=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.api-client:google-api-client-jackson2:2.7.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
@@ -81,13 +81,13 @@ com.google.api:gax-grpc:2.80.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:gax-httpjson:2.74.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.api:gax-httpjson:2.80.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:gax:2.74.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-admin-directory:directory_v1-rev20260227-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-admin-directory:directory_v1-rev20260421-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-bigquery:v2-rev20251012-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20250606-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-dataflow:v1b3-rev20260405-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-dataflow:v1b3-rev20260503-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-dns:v1-rev20260421-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-drive:v3-rev20260428-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-gmail:v1-rev20260427-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-gmail:v1-rev20260511-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-groupssettings:v1-rev20220614-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-healthcare:v1-rev20240130-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-iam:v2-rev20250502-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -138,38 +138,30 @@ com.google.cloud:google-cloud-tasks:2.51.0=compileClasspath,deploy_jar,nonprodCo
|
||||
com.google.cloud:grpc-gcp:1.9.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:libraries-bom:26.48.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud:proto-google-cloud-firestore-bundle-v1:3.37.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.code.gson:gson:2.10.1=soy
|
||||
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.code.gson:gson:2.13.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.common.html.types:types:1.0.8=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.dagger:dagger-compiler:2.59.2=annotationProcessor,testAnnotationProcessor
|
||||
com.google.dagger:dagger-spi:2.59.2=annotationProcessor,testAnnotationProcessor
|
||||
com.google.dagger:dagger:2.59.2=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.devtools.ksp:symbol-processing-api:2.2.20-2.0.3=annotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotation:2.48.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.20.0=soy
|
||||
com.google.errorprone:error_prone_annotations:2.36.0=checkstyle
|
||||
com.google.errorprone:error_prone_annotations:2.48.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.errorprone:error_prone_check_api:2.48.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_core:2.48.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.escapevelocity:escapevelocity:1.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.flatbuffers:flatbuffers-java:24.3.25=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.flogger:flogger-system-backend:0.7.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.flogger:flogger:0.7.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.flogger:google-extensions:0.7.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.flogger:flogger-system-backend:0.7.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.flogger:flogger:0.7.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.flogger:google-extensions:0.7.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.googlejavaformat:google-java-format:1.34.1=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.guava:failureaccess:1.0.1=soy
|
||||
com.google.guava:failureaccess:1.0.3=annotationProcessor,checkstyle,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.guava:guava-parent:32.1.1-jre=soy
|
||||
com.google.guava:guava-testlib:33.3.0-jre=testRuntimeClasspath
|
||||
com.google.guava:guava-testlib:33.6.0-jre=testCompileClasspath
|
||||
com.google.guava:guava:32.1.1-jre=soy
|
||||
com.google.guava:guava:33.4.8-jre=checkstyle
|
||||
com.google.guava:guava:33.5.0-jre=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.guava:guava:33.6.0-jre=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,checkstyle,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.gwt:gwt-user:2.10.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-apache-v2:2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.http-client:google-http-client-apache-v2:2.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-appengine:1.46.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
@@ -179,11 +171,8 @@ com.google.http-client:google-http-client-jackson2:1.46.3=compileClasspath,deplo
|
||||
com.google.http-client:google-http-client-jackson2:2.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-protobuf:2.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client:2.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.inject:guice:7.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.j2objc:j2objc-annotations:3.0.0=checkstyle
|
||||
com.google.j2objc:j2objc-annotations:3.1=annotationProcessor,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.jsinterop:jsinterop-annotations:1.0.1=soy
|
||||
com.google.jsinterop:jsinterop-annotations:2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.monitoring-client:contrib:1.0.7=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.monitoring-client:metrics:1.0.7=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.monitoring-client:stackdriver:1.0.7=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -195,16 +184,13 @@ com.google.oauth-client:google-oauth-client-servlet:1.36.0=deploy_jar,nonprodRun
|
||||
com.google.oauth-client:google-oauth-client-servlet:1.39.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.oauth-client:google-oauth-client:1.39.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.protobuf:protobuf-java-util:4.33.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.protobuf:protobuf-java-util:4.35.0-RC2=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.protobuf:protobuf-java:3.21.7=soy
|
||||
com.google.protobuf:protobuf-java-util:4.35.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.protobuf:protobuf-java:4.33.2=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.protobuf:protobuf-java:4.35.0-RC2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.protobuf:protobuf-java:4.35.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.re2j:re2j:1.8=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.template:soy:2024-02-26=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.truth:truth:1.4.5=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.googlecode.json-simple:json-simple:1.1.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.ibm.icu:icu4j:73.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
com.jcraft:jsch:0.1.55=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.ibm.icu:icu4j:73.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.lmax:disruptor:3.4.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.puppycrawl.tools:checkstyle:10.24.0=checkstyle
|
||||
com.squareup.okhttp3:okhttp:4.12.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -252,7 +238,7 @@ io.apicurio:apicurio-registry-protobuf-schema-utilities:3.0.0.M2=compileClasspat
|
||||
io.github.classgraph:classgraph:4.8.162=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
io.github.java-diff-utils:java-diff-utils:4.16=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.github.java-diff-utils:java-diff-utils:4.17=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.github.ss-bhatt:testcontainers-valkey:1.0.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-alts:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-alts:1.81.0=testCompileClasspath,testRuntimeClasspath
|
||||
@@ -351,7 +337,7 @@ jakarta-regexp:jakarta-regexp:1.4=compileClasspath,deploy_jar,nonprodCompileClas
|
||||
jakarta.activation:jakarta.activation-api:2.1.4=jaxb
|
||||
jakarta.activation:jakarta.activation-api:2.2.0-M1=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
jakarta.activation:jakarta.activation-api:2.2.0-M2=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
jakarta.inject:jakarta.inject-api:2.0.1=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
jakarta.inject:jakarta.inject-api:2.0.1=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
jakarta.mail:jakarta.mail-api:2.2.0-M1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
jakarta.persistence:jakarta.persistence-api:3.2.0=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
jakarta.servlet:jakarta.servlet-api:6.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -360,10 +346,8 @@ jakarta.xml.bind:jakarta.xml.bind-api:4.0.4=deploy_jar,nonprodRuntimeClasspath,r
|
||||
jakarta.xml.bind:jakarta.xml.bind-api:4.0.5=jaxb
|
||||
jakarta.xml.bind:jakarta.xml.bind-api:4.1.0-M1=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
javax.annotation:javax.annotation-api:1.3.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
javax.annotation:jsr250-api:1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
javax.inject:javax.inject:1=annotationProcessor,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
javax.inject:javax.inject:1=annotationProcessor,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
javax.jdo:jdo2-api:2.3-20090302111651=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
javax.validation:validation-api:1.0.0.GA=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
joda-time:joda-time:2.14.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
junit:junit:4.13.2=nonprodCompileClasspath,nonprodRuntimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
net.arnx:nashorn-promise:0.1.1=testRuntimeClasspath
|
||||
@@ -438,10 +422,9 @@ org.bouncycastle:bcpg-jdk18on:1.84=compileClasspath,deploy_jar,nonprodCompileCla
|
||||
org.bouncycastle:bcpkix-jdk18on:1.84=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.bouncycastle:bcprov-jdk18on:1.84=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.bouncycastle:bcutil-jdk18on:1.84=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.checkerframework:checker-compat-qual:2.5.3=annotationProcessor,compileClasspath,nonprodCompileClasspath,soy,testAnnotationProcessor,testCompileClasspath
|
||||
org.checkerframework:checker-compat-qual:2.5.3=annotationProcessor,compileClasspath,nonprodCompileClasspath,testAnnotationProcessor,testCompileClasspath
|
||||
org.checkerframework:checker-compat-qual:2.5.6=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.checkerframework:checker-qual:3.19.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
org.checkerframework:checker-qual:3.33.0=soy
|
||||
org.checkerframework:checker-qual:3.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.checkerframework:checker-qual:3.49.3=checkstyle
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.24=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
@@ -465,8 +448,9 @@ org.eclipse.jetty:jetty-server:12.1.9=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-session:12.1.9=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-util:12.1.9=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-xml:12.1.9=testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-core:12.6.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-database-postgresql:12.6.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-core:12.6.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-database-postgresql:12.6.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.freemarker:freemarker:2.3.34=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:codemodel:4.0.8=jaxb
|
||||
org.glassfish.jaxb:jaxb-core:4.0.6=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:jaxb-core:4.0.8=jaxb
|
||||
@@ -476,7 +460,6 @@ org.glassfish.jaxb:jaxb-xjc:4.0.8=jaxb
|
||||
org.glassfish.jaxb:txw2:4.0.6=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:txw2:4.0.8=jaxb
|
||||
org.glassfish.jaxb:xsom:4.0.8=jaxb
|
||||
org.gwtproject:gwt-user:2.10.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.hamcrest:hamcrest-core:1.3=nonprodCompileClasspath,nonprodRuntimeClasspath
|
||||
org.hamcrest:hamcrest-core:3.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.hamcrest:hamcrest-library:3.0=testCompileClasspath,testRuntimeClasspath
|
||||
@@ -514,7 +497,6 @@ org.jetbrains:annotations:13.0=annotationProcessor,testAnnotationProcessor
|
||||
org.jetbrains:annotations:17.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jline:jline:3.30.5=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.joda:joda-money:2.0.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.json:json:20230618=soy
|
||||
org.json:json:20251224=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jsoup:jsoup:1.22.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jspecify:jspecify:1.0.0=annotationProcessor,checkstyle,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -535,17 +517,12 @@ org.mockito:mockito-junit-jupiter:5.23.0=testCompileClasspath,testRuntimeClasspa
|
||||
org.objenesis:objenesis:3.3=testRuntimeClasspath
|
||||
org.ogce:xpp3:1.1.6=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-analysis:9.5=soy
|
||||
org.ow2.asm:asm-analysis:9.7.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.5=soy
|
||||
org.ow2.asm:asm-commons:9.7.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.9=jacocoAnt
|
||||
org.ow2.asm:asm-tree:9.5=soy
|
||||
org.ow2.asm:asm-tree:9.7.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-tree:9.9=jacocoAnt
|
||||
org.ow2.asm:asm-util:9.5=soy
|
||||
org.ow2.asm:asm-util:9.7.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm:9.5=soy
|
||||
org.ow2.asm:asm:9.7.1=compileClasspath,nonprodCompileClasspath
|
||||
org.ow2.asm:asm:9.8=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm:9.9=jacocoAnt
|
||||
@@ -582,7 +559,6 @@ org.testcontainers:postgresql:1.21.4=compileClasspath,deploy_jar,nonprodCompileC
|
||||
org.testcontainers:selenium:1.21.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.testcontainers:testcontainers:1.21.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.threeten:threetenbp:1.7.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.w3c.css:sac:1.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.webjars.npm:viz.js-graphviz-java:2.1.3=testRuntimeClasspath
|
||||
org.xerial.snappy:snappy-java:1.1.10.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.xmlresolver:xmlresolver:5.2.2=checkstyle
|
||||
|
||||
@@ -54,9 +54,15 @@ public class BatchModule {
|
||||
static final int DEFAULT_MAX_QPS = 10;
|
||||
|
||||
@Provides
|
||||
@Parameter("url")
|
||||
static String provideUrl(HttpServletRequest req) {
|
||||
return extractRequiredParameter(req, "url");
|
||||
@Parameter("replyTo")
|
||||
static String provideReplyTo(HttpServletRequest req) {
|
||||
return extractRequiredParameter(req, "replyTo");
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter("receiver")
|
||||
static String provideReceiver(HttpServletRequest req) {
|
||||
return extractRequiredParameter(req, "receiver");
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -16,30 +16,35 @@ package google.registry.batch;
|
||||
|
||||
import static google.registry.request.Action.Method.GET;
|
||||
import static google.registry.request.Action.Method.POST;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.api.services.gmail.Gmail;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import dagger.Lazy;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.groups.GmailClient;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.UrlConnectionService;
|
||||
import google.registry.request.UrlConnectionUtils;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.EmailMessage;
|
||||
import google.registry.util.Retrier;
|
||||
import jakarta.inject.Inject;
|
||||
import java.net.URL;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import jakarta.mail.internet.AddressException;
|
||||
import jakarta.mail.internet.InternetAddress;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Action that executes a canned script specified by the caller.
|
||||
*
|
||||
* <p>This class provides a hook for invoking hard-coded methods. The main use case is to verify in
|
||||
* Sandbox and Production environments new features that depend on environment-specific
|
||||
* configurations. For example, the {@code DelegatedCredential}, which requires correct GWorkspace
|
||||
* configuration, has been tested this way. Since it is a hassle to add or remove endpoints, we keep
|
||||
* this class all the time.
|
||||
* configurations.
|
||||
*
|
||||
* <p>This action can be invoked using the Nomulus CLI command: {@code nomulus -e ${env} curl
|
||||
* --service BACKEND -X POST -u '/_dr/task/executeCannedScript}'}
|
||||
* --service BACKEND -X POST -d 'sender=sender@example.com' -d 'receiver=receiver@example.com' -u
|
||||
* '/_dr/task/executeCannedScript'}
|
||||
*/
|
||||
@Action(
|
||||
service = Action.Service.BACKEND,
|
||||
@@ -50,39 +55,69 @@ import javax.net.ssl.HttpsURLConnection;
|
||||
public class CannedScriptExecutionAction implements Runnable {
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
@Inject UrlConnectionService urlConnectionService;
|
||||
@Inject Lazy<Gmail> gmail;
|
||||
@Inject Retrier retrier;
|
||||
|
||||
@Inject
|
||||
@Config("isEmailSendingEnabled")
|
||||
boolean isEmailSendingEnabled;
|
||||
|
||||
@Inject Response response;
|
||||
|
||||
@Inject
|
||||
@Parameter("url")
|
||||
String url;
|
||||
@Parameter("replyTo")
|
||||
String replyTo;
|
||||
|
||||
@Inject
|
||||
@Parameter("receiver")
|
||||
String receiver;
|
||||
|
||||
@Config("invoiceReplyToEmailAddress")
|
||||
Optional<InternetAddress> replyToEmailAddressFromConfig;
|
||||
|
||||
@Inject
|
||||
CannedScriptExecutionAction() {}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Integer responseCode = null;
|
||||
String responseContent = null;
|
||||
// For b/510340944, validating a new G Workspace user can send email. Code below can be
|
||||
// removed or changed afterward.
|
||||
try {
|
||||
logger.atInfo().log("Connecting to: %s", url);
|
||||
HttpsURLConnection connection =
|
||||
(HttpsURLConnection) urlConnectionService.createConnection(new URL(url));
|
||||
responseCode = connection.getResponseCode();
|
||||
logger.atInfo().log("Code: %d", responseCode);
|
||||
logger.atInfo().log("Headers: %s", connection.getHeaderFields());
|
||||
responseContent = new String(UrlConnectionUtils.getResponseBytes(connection), UTF_8);
|
||||
logger.atInfo().log("Response: %s", responseContent);
|
||||
logger.atInfo().log("Sending email to %s with replyTo %s", receiver, replyTo);
|
||||
GmailClient gmailClient =
|
||||
new GmailClient(gmail, retrier, isEmailSendingEnabled, new InternetAddress(replyTo));
|
||||
gmailClient.sendEmail(
|
||||
EmailMessage.newBuilder()
|
||||
.addRecipient(new InternetAddress(receiver))
|
||||
.setSubject(String.format("Email with manually set replyTo header %s", replyTo))
|
||||
.setBody("See subject")
|
||||
.build());
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
gmailClient.sendEmail(
|
||||
EmailMessage.newBuilder()
|
||||
.setSubject(
|
||||
String.format(
|
||||
"Email with injected replyTo header %s", replyToEmailAddressFromConfig))
|
||||
.setBody("See header")
|
||||
.setRecipients(ImmutableList.of(new InternetAddress(receiver)))
|
||||
.setReplyToEmailAddress(replyToEmailAddressFromConfig)
|
||||
.setContentType(MediaType.HTML_UTF_8)
|
||||
.build());
|
||||
response.setPayload("Emails sent successfully.");
|
||||
} catch (AddressException e) {
|
||||
logger.atWarning().withCause(e).log(
|
||||
"Invalid email address: sender=%s, receiver=%s", replyTo, receiver);
|
||||
response.setStatus(400);
|
||||
response.setPayload("Invalid email address provided.");
|
||||
} catch (Exception e) {
|
||||
logger.atWarning().withCause(e).log("Connection to %s failed", url);
|
||||
logger.atSevere().withCause(e).log("Failed to send email");
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (responseCode != null) {
|
||||
response.setStatus(responseCode);
|
||||
}
|
||||
if (responseContent != null) {
|
||||
response.setPayload(responseContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import static google.registry.beam.rde.RdePipeline.TupleTags.DOMAIN_FRAGMENTS;
|
||||
import static google.registry.beam.rde.RdePipeline.TupleTags.EXTERNAL_HOST_FRAGMENTS;
|
||||
import static google.registry.beam.rde.RdePipeline.TupleTags.HOST_TO_PENDING_DEPOSIT;
|
||||
import static google.registry.beam.rde.RdePipeline.TupleTags.PENDING_DEPOSIT;
|
||||
import static google.registry.beam.rde.RdePipeline.TupleTags.REFERENCED_CONTACTS;
|
||||
import static google.registry.beam.rde.RdePipeline.TupleTags.REFERENCED_HOSTS;
|
||||
import static google.registry.beam.rde.RdePipeline.TupleTags.REVISION_ID;
|
||||
import static google.registry.beam.rde.RdePipeline.TupleTags.SUPERORDINATE_DOMAINS;
|
||||
@@ -131,9 +130,8 @@ import org.apache.beam.sdk.values.TypeDescriptor;
|
||||
*
|
||||
* After the most recent (live) domain resources are loaded from the corresponding history objects,
|
||||
* we marshall them to deposit fragments and emit the (pending deposit: deposit fragment) pairs for
|
||||
* further processing. We also find all the contacts and hosts referenced by a given domain and emit
|
||||
* pairs of (contact/host repo ID: pending deposit) for all RDE pending deposits for further
|
||||
* processing.
|
||||
* further processing. We also find all the hosts referenced by a given domain and emit pairs of
|
||||
* (host repo ID: pending deposit) for all RDE pending deposits for further processing.
|
||||
*
|
||||
* <h3>{@link Host}</h3>
|
||||
*
|
||||
@@ -358,7 +356,6 @@ public class RdePipeline implements Serializable {
|
||||
|
||||
private <T extends HistoryEntry> EppResource loadResourceByHistoryEntryId(
|
||||
Class<T> historyEntryClazz, String repoId, long revisionId) {
|
||||
|
||||
return tm().transact(
|
||||
() ->
|
||||
tm().loadByKey(
|
||||
@@ -372,8 +369,8 @@ public class RdePipeline implements Serializable {
|
||||
* Remove unreferenced resources by joining the (repoId, pendingDeposit) pair with the (repoId,
|
||||
* revisionId) on the repoId.
|
||||
*
|
||||
* <p>The (repoId, pendingDeposit) pairs denote resources (contact, host) that are referenced from
|
||||
* a domain, that are to be included in the corresponding pending deposit.
|
||||
* <p>The (repoId, pendingDeposit) pairs denote hosts that are referenced from a domain, that are
|
||||
* to be included in the corresponding pending deposit.
|
||||
*
|
||||
* <p>The (repoId, revisionId) paris come from the most recent history entry query, which can be
|
||||
* used to load the embedded resources themselves.
|
||||
@@ -423,7 +420,7 @@ public class RdePipeline implements Serializable {
|
||||
Counter domainFragmentCounter = Metrics.counter("RDE", "DomainFragment");
|
||||
Counter referencedHostCounter = Metrics.counter("RDE", "ReferencedHost");
|
||||
return domainHistories.apply(
|
||||
"Map DomainHistory to DepositFragment " + "and emit referenced Contact and Host",
|
||||
"Map DomainHistory to DepositFragment and emit referenced Host",
|
||||
ParDo.of(
|
||||
new DoFn<KV<String, Long>, KV<PendingDeposit, DepositFragment>>() {
|
||||
@ProcessElement
|
||||
@@ -465,8 +462,7 @@ public class RdePipeline implements Serializable {
|
||||
});
|
||||
}
|
||||
})
|
||||
.withOutputTags(
|
||||
DOMAIN_FRAGMENTS, TupleTagList.of(REFERENCED_CONTACTS).and(REFERENCED_HOSTS)));
|
||||
.withOutputTags(DOMAIN_FRAGMENTS, TupleTagList.of(REFERENCED_HOSTS)));
|
||||
}
|
||||
|
||||
private PCollectionTuple processHostHistories(
|
||||
@@ -627,9 +623,6 @@ public class RdePipeline implements Serializable {
|
||||
protected static final TupleTag<KV<PendingDeposit, DepositFragment>> DOMAIN_FRAGMENTS =
|
||||
new TupleTag<>() {};
|
||||
|
||||
protected static final TupleTag<KV<String, PendingDeposit>> REFERENCED_CONTACTS =
|
||||
new TupleTag<>() {};
|
||||
|
||||
protected static final TupleTag<KV<String, PendingDeposit>> REFERENCED_HOSTS =
|
||||
new TupleTag<>() {};
|
||||
|
||||
|
||||
@@ -68,6 +68,8 @@ public class BsaCredential {
|
||||
|
||||
private final Keyring keyring;
|
||||
|
||||
private final Gson gson;
|
||||
|
||||
private final Clock clock;
|
||||
|
||||
@Nullable private String authToken;
|
||||
@@ -79,11 +81,13 @@ public class BsaCredential {
|
||||
@Config("bsaAuthUrl") String authUrl,
|
||||
@Config("bsaAuthTokenExpiry") Duration authTokenExpiry,
|
||||
Keyring keyring,
|
||||
Gson gson,
|
||||
Clock clock) {
|
||||
this.urlConnectionService = urlConnectionService;
|
||||
this.authUrl = authUrl;
|
||||
this.authTokenExpiry = authTokenExpiry;
|
||||
this.keyring = keyring;
|
||||
this.gson = gson;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@@ -143,8 +147,7 @@ public class BsaCredential {
|
||||
// TODO: catch json syntax exception
|
||||
@SuppressWarnings("unchecked")
|
||||
String idToken =
|
||||
new Gson()
|
||||
.fromJson(new String(getResponseBytes(connection), UTF_8), Map.class)
|
||||
gson.fromJson(new String(getResponseBytes(connection), UTF_8), Map.class)
|
||||
.getOrDefault(ID_TOKEN, "")
|
||||
.toString();
|
||||
if (idToken.isEmpty()) {
|
||||
|
||||
@@ -60,12 +60,15 @@ public final class CacheModule {
|
||||
public static Optional<UnifiedJedis> provideJedis(
|
||||
@ApplicationDefaultCredential GoogleCredentialsBundle credentialsBundle,
|
||||
@Config("valkeyHostsAndPorts") Optional<ImmutableList<String>> valkeyHostsAndPorts,
|
||||
@Config("valkeySslSocketFactory") SSLSocketFactory valkeySslSocketFactory) {
|
||||
if (valkeyHostsAndPorts.map(ImmutableList::isEmpty).orElse(true)) {
|
||||
@Config("valkeyCertificateAuthority") Optional<String> valkeyCertificateAuthority) {
|
||||
if (valkeyHostsAndPorts.map(ImmutableList::isEmpty).orElse(true)
|
||||
|| valkeyCertificateAuthority.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
ImmutableSet<HostAndPort> hostsAndPorts =
|
||||
valkeyHostsAndPorts.get().stream().map(HostAndPort::from).collect(toImmutableSet());
|
||||
SSLSocketFactory valkeySslSocketFactory =
|
||||
createValkeySslSocketFactory(valkeyCertificateAuthority.get());
|
||||
JedisClientConfig clientConfig =
|
||||
DefaultJedisClientConfig.builder()
|
||||
.ssl(true)
|
||||
@@ -111,11 +114,7 @@ public final class CacheModule {
|
||||
return new MultilayerHostCache(jedisClient.get(), cacheMetrics);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Config("valkeySslSocketFactory")
|
||||
static SSLSocketFactory provideValkeySslSocketFactory(
|
||||
@Config("valkeyCertificateAuthority") String valkeyCertificateAuthority) {
|
||||
private static SSLSocketFactory createValkeySslSocketFactory(String valkeyCertificateAuthority) {
|
||||
try {
|
||||
ImmutableList<X509Certificate> trustedCerts =
|
||||
CertificateFactory.getInstance("X.509")
|
||||
|
||||
@@ -19,16 +19,6 @@ import dagger.Provides;
|
||||
import dagger.Subcomponent;
|
||||
import google.registry.batch.BatchModule;
|
||||
import google.registry.dns.DnsModule;
|
||||
import google.registry.flows.contact.ContactCheckFlow;
|
||||
import google.registry.flows.contact.ContactCreateFlow;
|
||||
import google.registry.flows.contact.ContactDeleteFlow;
|
||||
import google.registry.flows.contact.ContactInfoFlow;
|
||||
import google.registry.flows.contact.ContactTransferApproveFlow;
|
||||
import google.registry.flows.contact.ContactTransferCancelFlow;
|
||||
import google.registry.flows.contact.ContactTransferQueryFlow;
|
||||
import google.registry.flows.contact.ContactTransferRejectFlow;
|
||||
import google.registry.flows.contact.ContactTransferRequestFlow;
|
||||
import google.registry.flows.contact.ContactUpdateFlow;
|
||||
import google.registry.flows.custom.CustomLogicModule;
|
||||
import google.registry.flows.domain.DomainCheckFlow;
|
||||
import google.registry.flows.domain.DomainClaimsCheckFlow;
|
||||
@@ -54,6 +44,8 @@ import google.registry.flows.session.HelloFlow;
|
||||
import google.registry.flows.session.LoginFlow;
|
||||
import google.registry.flows.session.LogoutFlow;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/** Dagger component for flow classes. */
|
||||
@FlowScope
|
||||
@@ -69,16 +61,6 @@ public interface FlowComponent {
|
||||
FlowRunner flowRunner();
|
||||
|
||||
// Flows must be added here and in FlowComponentModule below.
|
||||
ContactCheckFlow contactCheckFlow();
|
||||
ContactCreateFlow contactCreateFlow();
|
||||
ContactDeleteFlow contactDeleteFlow();
|
||||
ContactInfoFlow contactInfoFlow();
|
||||
ContactTransferApproveFlow contactTransferApproveFlow();
|
||||
ContactTransferCancelFlow contactTransferCancelFlow();
|
||||
ContactTransferQueryFlow contactTransferQueryFlow();
|
||||
ContactTransferRejectFlow contactTransferRejectFlow();
|
||||
ContactTransferRequestFlow contactTransferRequestFlow();
|
||||
ContactUpdateFlow contactUpdateFlow();
|
||||
DomainCheckFlow domainCheckFlow();
|
||||
DomainClaimsCheckFlow domainClaimsCheckFlow();
|
||||
DomainCreateFlow domainCreateFlow();
|
||||
@@ -118,40 +100,16 @@ public interface FlowComponent {
|
||||
// TODO(b/29874464): fix this in a cleaner way.
|
||||
@Provides
|
||||
static Flow provideFlow(FlowComponent flows, Class<? extends Flow> clazz) {
|
||||
return clazz.equals(ContactCheckFlow.class) ? flows.contactCheckFlow()
|
||||
: clazz.equals(ContactCreateFlow.class) ? flows.contactCreateFlow()
|
||||
: clazz.equals(ContactDeleteFlow.class) ? flows.contactDeleteFlow()
|
||||
: clazz.equals(ContactInfoFlow.class) ? flows.contactInfoFlow()
|
||||
: clazz.equals(ContactTransferApproveFlow.class) ? flows.contactTransferApproveFlow()
|
||||
: clazz.equals(ContactTransferCancelFlow.class) ? flows.contactTransferCancelFlow()
|
||||
: clazz.equals(ContactTransferQueryFlow.class) ? flows.contactTransferQueryFlow()
|
||||
: clazz.equals(ContactTransferRejectFlow.class) ? flows.contactTransferRejectFlow()
|
||||
: clazz.equals(ContactTransferRequestFlow.class) ? flows.contactTransferRequestFlow()
|
||||
: clazz.equals(ContactUpdateFlow.class) ? flows.contactUpdateFlow()
|
||||
: clazz.equals(DomainCheckFlow.class) ? flows.domainCheckFlow()
|
||||
: clazz.equals(DomainClaimsCheckFlow.class) ? flows.domainClaimsCheckFlow()
|
||||
: clazz.equals(DomainCreateFlow.class) ? flows.domainCreateFlow()
|
||||
: clazz.equals(DomainDeleteFlow.class) ? flows.domainDeleteFlow()
|
||||
: clazz.equals(DomainInfoFlow.class) ? flows.domainInfoFlow()
|
||||
: clazz.equals(DomainRenewFlow.class) ? flows.domainRenewFlow()
|
||||
: clazz.equals(DomainRestoreRequestFlow.class) ? flows.domainRestoreRequestFlow()
|
||||
: clazz.equals(DomainTransferApproveFlow.class) ? flows.domainTransferApproveFlow()
|
||||
: clazz.equals(DomainTransferCancelFlow.class) ? flows.domainTransferCancelFlow()
|
||||
: clazz.equals(DomainTransferQueryFlow.class) ? flows.domainTransferQueryFlow()
|
||||
: clazz.equals(DomainTransferRejectFlow.class) ? flows.domainTransferRejectFlow()
|
||||
: clazz.equals(DomainTransferRequestFlow.class) ? flows.domainTransferRequestFlow()
|
||||
: clazz.equals(DomainUpdateFlow.class) ? flows.domainUpdateFlow()
|
||||
: clazz.equals(HostCheckFlow.class) ? flows.hostCheckFlow()
|
||||
: clazz.equals(HostCreateFlow.class) ? flows.hostCreateFlow()
|
||||
: clazz.equals(HostDeleteFlow.class) ? flows.hostDeleteFlow()
|
||||
: clazz.equals(HostInfoFlow.class) ? flows.hostInfoFlow()
|
||||
: clazz.equals(HostUpdateFlow.class) ? flows.hostUpdateFlow()
|
||||
: clazz.equals(PollAckFlow.class) ? flows.pollAckFlow()
|
||||
: clazz.equals(PollRequestFlow.class) ? flows.pollRequestFlow()
|
||||
: clazz.equals(HelloFlow.class) ? flows.helloFlow()
|
||||
: clazz.equals(LoginFlow.class) ? flows.loginFlow()
|
||||
: clazz.equals(LogoutFlow.class) ? flows.logoutFlow()
|
||||
: null;
|
||||
String simpleName = clazz.getSimpleName();
|
||||
// The method name is the same as the class name but with the first character being lowercase
|
||||
String methodName = Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
|
||||
try {
|
||||
Method method = FlowComponent.class.getMethod(methodName);
|
||||
method.setAccessible(true);
|
||||
return (Flow) method.invoke(flows);
|
||||
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.flows.contact;
|
||||
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.flows.exceptions.ContactsProhibitedException;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow that is meant to check whether a contact can be provisioned.
|
||||
*
|
||||
* @error {@link ContactsProhibitedException}
|
||||
*/
|
||||
@Deprecated
|
||||
@ReportingSpec(ActivityReportField.CONTACT_CHECK)
|
||||
public final class ContactCheckFlow extends ContactsProhibitedFlow {
|
||||
@Inject ContactCheckFlow() {}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.flows.contact;
|
||||
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.flows.exceptions.ContactsProhibitedException;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow meant to create a new contact.
|
||||
*
|
||||
* @error {@link ContactsProhibitedException}
|
||||
*/
|
||||
@Deprecated
|
||||
@ReportingSpec(ActivityReportField.CONTACT_CREATE)
|
||||
public final class ContactCreateFlow extends ContactsProhibitedFlow {
|
||||
@Inject ContactCreateFlow() {}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.flows.contact;
|
||||
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.flows.exceptions.ContactsProhibitedException;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow that is meant to delete a contact.
|
||||
*
|
||||
* @error {@link ContactsProhibitedException}
|
||||
*/
|
||||
@Deprecated
|
||||
@ReportingSpec(ActivityReportField.CONTACT_DELETE)
|
||||
public final class ContactDeleteFlow extends ContactsProhibitedFlow {
|
||||
@Inject
|
||||
ContactDeleteFlow() {}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.flows.contact;
|
||||
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.flows.exceptions.ContactsProhibitedException;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow that is meant to return information about a contact.
|
||||
*
|
||||
* @error {@link ContactsProhibitedException}
|
||||
*/
|
||||
@Deprecated
|
||||
@ReportingSpec(ActivityReportField.CONTACT_INFO)
|
||||
public final class ContactInfoFlow extends ContactsProhibitedFlow {
|
||||
@Inject
|
||||
ContactInfoFlow() {}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.flows.contact;
|
||||
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.flows.exceptions.ContactsProhibitedException;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow that is meant to approve a pending transfer on a contact.
|
||||
*
|
||||
* @error {@link ContactsProhibitedException}
|
||||
*/
|
||||
@Deprecated
|
||||
@ReportingSpec(ActivityReportField.CONTACT_TRANSFER_APPROVE)
|
||||
public final class ContactTransferApproveFlow extends ContactsProhibitedFlow {
|
||||
@Inject ContactTransferApproveFlow() {}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.flows.contact;
|
||||
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.flows.exceptions.ContactsProhibitedException;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow that is meant to cancel a pending transfer on a contact.
|
||||
*
|
||||
* @error {@link ContactsProhibitedException}
|
||||
*/
|
||||
@Deprecated
|
||||
@ReportingSpec(ActivityReportField.CONTACT_TRANSFER_CANCEL)
|
||||
public final class ContactTransferCancelFlow extends ContactsProhibitedFlow {
|
||||
@Inject ContactTransferCancelFlow() {}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.flows.contact;
|
||||
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.flows.exceptions.ContactsProhibitedException;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow that is meant to query a pending transfer on a contact.
|
||||
*
|
||||
* @error {@link ContactsProhibitedException}
|
||||
*/
|
||||
@Deprecated
|
||||
@ReportingSpec(ActivityReportField.CONTACT_TRANSFER_QUERY)
|
||||
public final class ContactTransferQueryFlow extends ContactsProhibitedFlow {
|
||||
@Inject ContactTransferQueryFlow() {}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.flows.contact;
|
||||
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.flows.exceptions.ContactsProhibitedException;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow that is meant to reject a pending transfer on a contact.
|
||||
*
|
||||
* @error {@link ContactsProhibitedException}
|
||||
*/
|
||||
@Deprecated
|
||||
@ReportingSpec(ActivityReportField.CONTACT_TRANSFER_REJECT)
|
||||
public final class ContactTransferRejectFlow extends ContactsProhibitedFlow {
|
||||
@Inject ContactTransferRejectFlow() {}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.flows.contact;
|
||||
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.flows.exceptions.ContactsProhibitedException;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow that is meant to request a transfer on a contact.
|
||||
*
|
||||
* @error {@link ContactsProhibitedException}
|
||||
*/
|
||||
@Deprecated
|
||||
@ReportingSpec(ActivityReportField.CONTACT_TRANSFER_REQUEST)
|
||||
public final class ContactTransferRequestFlow extends ContactsProhibitedFlow {
|
||||
@Inject
|
||||
ContactTransferRequestFlow() {}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.flows.contact;
|
||||
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.flows.exceptions.ContactsProhibitedException;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow meant to update a contact.
|
||||
*
|
||||
* @error {@link ContactsProhibitedException}
|
||||
*/
|
||||
@Deprecated
|
||||
@ReportingSpec(ActivityReportField.CONTACT_UPDATE)
|
||||
public final class ContactUpdateFlow extends ContactsProhibitedFlow {
|
||||
@Inject ContactUpdateFlow() {}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.flows.contact;
|
||||
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.Flow;
|
||||
import google.registry.flows.exceptions.ContactsProhibitedException;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
|
||||
/** Nomulus follows the Minimum Dataset Requirements, meaning it stores no contact information. */
|
||||
public abstract class ContactsProhibitedFlow implements Flow {
|
||||
@Override
|
||||
public EppResponse run() throws EppException {
|
||||
throw new ContactsProhibitedException();
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,9 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMark verifySignedMarks(
|
||||
ImmutableList<AbstractSignedMark> signedMarks, String domainLabel, Instant now)
|
||||
throws EppException {
|
||||
if (signedMarks.isEmpty()) {
|
||||
throw new SignedMarksListEmptyException();
|
||||
}
|
||||
if (signedMarks.size() > 1) {
|
||||
throw new TooManySignedMarksException();
|
||||
}
|
||||
@@ -77,21 +80,21 @@ public final class DomainFlowTmchUtils {
|
||||
|
||||
public SignedMark verifyEncodedSignedMark(EncodedSignedMark encodedSignedMark, Instant now)
|
||||
throws EppException {
|
||||
if (!encodedSignedMark.getEncoding().equals("base64")) {
|
||||
if (!"base64".equals(encodedSignedMark.getEncoding())) {
|
||||
throw new Base64RequiredForEncodedSignedMarksException();
|
||||
}
|
||||
byte[] signedMarkData;
|
||||
try {
|
||||
signedMarkData = encodedSignedMark.getBytes();
|
||||
} catch (IllegalStateException e) {
|
||||
throw new SignedMarkEncodingErrorException();
|
||||
throw new SignedMarkEncodingErrorException(e);
|
||||
}
|
||||
|
||||
SignedMark signedMark;
|
||||
try {
|
||||
signedMark = unmarshalEpp(SignedMark.class, signedMarkData);
|
||||
} catch (EppException e) {
|
||||
throw new SignedMarkParsingErrorException();
|
||||
throw new SignedMarkParsingErrorException(e);
|
||||
}
|
||||
|
||||
if (SignedMarkRevocationList.get().isSmdRevoked(signedMark.getId(), now)) {
|
||||
@@ -101,22 +104,22 @@ public final class DomainFlowTmchUtils {
|
||||
try {
|
||||
tmchXmlSignature.verify(signedMarkData);
|
||||
} catch (CertificateExpiredException e) {
|
||||
throw new SignedMarkCertificateExpiredException();
|
||||
throw new SignedMarkCertificateExpiredException(e);
|
||||
} catch (CertificateNotYetValidException e) {
|
||||
throw new SignedMarkCertificateNotYetValidException();
|
||||
throw new SignedMarkCertificateNotYetValidException(e);
|
||||
} catch (CertificateRevokedException e) {
|
||||
throw new SignedMarkCertificateRevokedException();
|
||||
throw new SignedMarkCertificateRevokedException(e);
|
||||
} catch (CertificateSignatureException e) {
|
||||
throw new SignedMarkCertificateSignatureException();
|
||||
throw new SignedMarkCertificateSignatureException(e);
|
||||
} catch (SignatureException | XMLSignatureException e) {
|
||||
throw new SignedMarkSignatureException();
|
||||
throw new SignedMarkSignatureException(e);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new SignedMarkCertificateInvalidException();
|
||||
throw new SignedMarkCertificateInvalidException(e);
|
||||
} catch (IOException
|
||||
| MarshalException
|
||||
| SAXException
|
||||
| ParserConfigurationException e) {
|
||||
throw new SignedMarkParsingErrorException();
|
||||
throw new SignedMarkParsingErrorException(e);
|
||||
}
|
||||
|
||||
if (now.isBefore(signedMark.getCreationTime())) {
|
||||
@@ -181,6 +184,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkCertificateRevokedException() {
|
||||
super("Signed mark certificate was revoked");
|
||||
}
|
||||
|
||||
public SignedMarkCertificateRevokedException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
/** Certificate used in signed mark signature has expired. */
|
||||
@@ -189,6 +197,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkCertificateNotYetValidException() {
|
||||
super("Signed mark certificate not yet valid");
|
||||
}
|
||||
|
||||
public SignedMarkCertificateNotYetValidException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
/** Certificate used in signed mark signature has expired. */
|
||||
@@ -196,6 +209,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkCertificateExpiredException() {
|
||||
super("Signed mark certificate has expired");
|
||||
}
|
||||
|
||||
public SignedMarkCertificateExpiredException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
/** Certificate parsing error, or possibly a bad provider or algorithm. */
|
||||
@@ -203,6 +221,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkCertificateInvalidException() {
|
||||
super("Signed mark certificate is invalid");
|
||||
}
|
||||
|
||||
public SignedMarkCertificateInvalidException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
/** Invalid signature on a signed mark. */
|
||||
@@ -210,6 +233,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkCertificateSignatureException() {
|
||||
super("Signed mark certificate not signed by ICANN");
|
||||
}
|
||||
|
||||
public SignedMarkCertificateSignatureException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
/** Invalid signature on a signed mark. */
|
||||
@@ -217,6 +245,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkSignatureException() {
|
||||
super("Signed mark signature is invalid");
|
||||
}
|
||||
|
||||
public SignedMarkSignatureException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
/** Signed marks must be encoded. */
|
||||
@@ -226,6 +259,13 @@ public final class DomainFlowTmchUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/** Signed marks list cannot be empty. */
|
||||
static class SignedMarksListEmptyException extends RequiredParameterMissingException {
|
||||
public SignedMarksListEmptyException() {
|
||||
super("Signed marks list cannot be empty");
|
||||
}
|
||||
}
|
||||
|
||||
/** Only one signed mark is allowed per application. */
|
||||
static class TooManySignedMarksException extends ParameterValuePolicyErrorException {
|
||||
public TooManySignedMarksException() {
|
||||
@@ -245,6 +285,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkParsingErrorException() {
|
||||
super("Error while parsing encoded signed mark data");
|
||||
}
|
||||
|
||||
public SignedMarkParsingErrorException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
/** Signed mark data is improperly encoded. */
|
||||
@@ -252,6 +297,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkEncodingErrorException() {
|
||||
super("Signed mark data is improperly encoded");
|
||||
}
|
||||
|
||||
public SignedMarkEncodingErrorException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,8 +43,8 @@ import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
import static google.registry.util.DateTimeUtils.END_INSTANT;
|
||||
import static google.registry.util.DateTimeUtils.isAtOrAfter;
|
||||
import static google.registry.util.DateTimeUtils.minusDays;
|
||||
import static google.registry.util.DateTimeUtils.plusYears;
|
||||
import static google.registry.util.DomainNameUtils.ACE_PREFIX;
|
||||
import static java.time.ZoneOffset.UTC;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
@@ -154,7 +154,7 @@ public class DomainFlowUtils {
|
||||
/** Warning message for allocation of collision domains in sunrise. */
|
||||
public static final String COLLISION_MESSAGE =
|
||||
"Domain on the name collision list was allocated. But by policy, the domain will not be "
|
||||
+ "delegated. Please visit https://www.icann.org/namecollision for more information on "
|
||||
+ "delegated. Please visit https://www.icann.org/namecollision for more information on "
|
||||
+ "name collision.";
|
||||
|
||||
/** Strict validator for ascii lowercase letters, digits, and "-", allowing "." as a separator */
|
||||
@@ -581,13 +581,12 @@ public class DomainFlowUtils {
|
||||
InternetDomainName domainName,
|
||||
Optional<Domain> domain,
|
||||
@Nullable CurrencyUnit topLevelCurrency,
|
||||
Instant currentDate,
|
||||
Instant now,
|
||||
DomainPricingLogic pricingLogic,
|
||||
Optional<AllocationToken> allocationToken,
|
||||
boolean isAvailable,
|
||||
@Nullable BillingRecurrence billingRecurrence)
|
||||
throws EppException {
|
||||
Instant now = currentDate;
|
||||
// Use the custom effective date specified in the fee check request, if there is one.
|
||||
if (feeRequest.getEffectiveDate().isPresent()) {
|
||||
now = feeRequest.getEffectiveDate().get();
|
||||
@@ -816,7 +815,7 @@ public class DomainFlowUtils {
|
||||
return fee.getType();
|
||||
}
|
||||
ImmutableList<FeeType> types = fee.parseDescriptionForTypes();
|
||||
if (types.size() == 0) {
|
||||
if (types.isEmpty()) {
|
||||
throw new FeeDescriptionParseException(fee.getDescription());
|
||||
} else if (types.size() > 1) {
|
||||
throw new FeeDescriptionMultipleMatchesException(fee.getDescription(), types);
|
||||
@@ -848,7 +847,7 @@ public class DomainFlowUtils {
|
||||
*/
|
||||
public static void validateRegistrationPeriod(Instant now, Instant newExpirationTime)
|
||||
throws EppException {
|
||||
if (now.atZone(UTC).plusYears(MAX_REGISTRATION_YEARS).toInstant().isBefore(newExpirationTime)) {
|
||||
if (plusYears(now, MAX_REGISTRATION_YEARS).isBefore(newExpirationTime)) {
|
||||
throw new ExceedsMaxRegistrationYearsException();
|
||||
}
|
||||
}
|
||||
@@ -907,7 +906,7 @@ public class DomainFlowUtils {
|
||||
return ImmutableSet.copyOf(union(difference(oldDsData, toRemove), toAdd));
|
||||
}
|
||||
|
||||
/** If a domain "clientUpdateProhibited" set, updates must clear it or fail. */
|
||||
/** If a domain has "clientUpdateProhibited" set, updates must clear it or fail. */
|
||||
static void verifyClientUpdateNotProhibited(Update command, Domain existingResource)
|
||||
throws ResourceHasClientUpdateProhibitedException {
|
||||
if (existingResource.getStatusValues().contains(StatusValue.CLIENT_UPDATE_PROHIBITED)
|
||||
@@ -996,7 +995,13 @@ public class DomainFlowUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/** Check that the claims period hasn't ended. */
|
||||
/**
|
||||
* Check that the claims period hasn't ended.
|
||||
*
|
||||
* @param tld the {@link Tld} to check
|
||||
* @param now the current {@link Instant}
|
||||
* @throws ClaimsPeriodEndedException if the claims period has ended
|
||||
*/
|
||||
static void verifyClaimsPeriodNotEnded(Tld tld, Instant now) throws ClaimsPeriodEndedException {
|
||||
if (!now.isBefore(tld.getClaimsPeriodEnd())) {
|
||||
throw new ClaimsPeriodEndedException(tld.getTldStr());
|
||||
@@ -1008,6 +1013,9 @@ public class DomainFlowUtils {
|
||||
*
|
||||
* <p>{@link BigDecimal} has a concept of significant figures, so zero is not always zero. E.g.
|
||||
* zero in USD is 0.00, whereas zero in Yen is 0, and zero in Dinars is 0.000 (!).
|
||||
*
|
||||
* @param currencyUnit the {@link CurrencyUnit}
|
||||
* @return zero in the given currency
|
||||
*/
|
||||
static BigDecimal zeroInCurrency(CurrencyUnit currencyUnit) {
|
||||
return Money.of(currencyUnit, BigDecimal.ZERO).getAmount();
|
||||
@@ -1016,6 +1024,12 @@ public class DomainFlowUtils {
|
||||
/**
|
||||
* Check that if there's a claims notice it's on the claims list, and that if there's not one it's
|
||||
* not on the claims list.
|
||||
*
|
||||
* @param domainName the {@link InternetDomainName} to check
|
||||
* @param claimsList the current {@link ClaimsList}
|
||||
* @param hasSignedMarks whether signed marks are present
|
||||
* @param hasClaimsNotice whether a claims notice is present
|
||||
* @throws EppException if the claims notice status is incorrect
|
||||
*/
|
||||
static void verifyClaimsNoticeIfAndOnlyIfNeeded(
|
||||
InternetDomainName domainName,
|
||||
@@ -1032,7 +1046,12 @@ public class DomainFlowUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/** Check that there are no code marks, which is a type of mark we don't support. */
|
||||
/**
|
||||
* Check that there are no code marks, which is a type of mark we don't support.
|
||||
*
|
||||
* @param launchCreate the {@link LaunchCreateExtension}
|
||||
* @throws UnsupportedMarkTypeException if code marks are present
|
||||
*/
|
||||
static void verifyNoCodeMarks(LaunchCreateExtension launchCreate)
|
||||
throws UnsupportedMarkTypeException {
|
||||
if (launchCreate.hasCodeMarks()) {
|
||||
@@ -1040,7 +1059,13 @@ public class DomainFlowUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a response extension listing the fees on a domain create. */
|
||||
/**
|
||||
* Create a response extension listing the fees on a domain create.
|
||||
*
|
||||
* @param feeCreate the {@link FeeTransformCommandExtension}
|
||||
* @param feesAndCredits the {@link FeesAndCredits}
|
||||
* @return the {@link FeeTransformResponseExtension}
|
||||
*/
|
||||
static FeeTransformResponseExtension createFeeCreateResponse(
|
||||
FeeTransformCommandExtension feeCreate, FeesAndCredits feesAndCredits) {
|
||||
return feeCreate
|
||||
@@ -1058,10 +1083,21 @@ public class DomainFlowUtils {
|
||||
* their flow. For example, if a grace period delete occurs, we must add -1 counters for the
|
||||
* associated NET_ADDS_#_YRS field, if it exists.
|
||||
*
|
||||
* <p>The steps are as follows: 1. Find all HistoryEntries under the domain modified in the past,
|
||||
* up to the maxSearchPeriod. 2. Only keep HistoryEntries with a DomainTransactionRecord that a)
|
||||
* hasn't been reported yet and b) matches the predicate 3. Return the transactionRecords under
|
||||
* the most recent HistoryEntry that fits the above criteria, with negated reportAmounts.
|
||||
* <p>The steps are as follows:
|
||||
*
|
||||
* <ol>
|
||||
* <li>Find all HistoryEntries under the domain modified in the past, up to the maxSearchPeriod.
|
||||
* <li>Only keep HistoryEntries with a DomainTransactionRecord that a) hasn't been reported yet
|
||||
* and b) matches the predicate
|
||||
* <li>Return the transactionRecords under the most recent HistoryEntry that fits the above
|
||||
* criteria, with negated reportAmounts.
|
||||
* </ol>
|
||||
*
|
||||
* @param domain the {@link Domain} to create records for
|
||||
* @param now the current {@link Instant}
|
||||
* @param maxSearchPeriod the {@link Duration} to search back
|
||||
* @param cancelableFields the set of {@link TransactionReportField}s that can be canceled
|
||||
* @return the set of canceling {@link DomainTransactionRecord}s
|
||||
*/
|
||||
public static ImmutableSet<DomainTransactionRecord> createCancelingRecords(
|
||||
Domain domain,
|
||||
@@ -1225,13 +1261,6 @@ public class DomainFlowUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/** Having a registrant is prohibited by registry policy. */
|
||||
public static class RegistrantProhibitedException extends ParameterValuePolicyErrorException {
|
||||
public RegistrantProhibitedException() {
|
||||
super("Having a registrant is prohibited by registry policy");
|
||||
}
|
||||
}
|
||||
|
||||
/** Too many nameservers set on this domain. */
|
||||
static class TooManyNameserversException extends ParameterValuePolicyErrorException {
|
||||
public TooManyNameserversException(String message) {
|
||||
@@ -1384,6 +1413,13 @@ public class DomainFlowUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/** Having a registrant is prohibited by registry policy. */
|
||||
public static class RegistrantProhibitedException extends ParameterValuePolicyErrorException {
|
||||
public RegistrantProhibitedException() {
|
||||
super("Having a registrant is prohibited by registry policy");
|
||||
}
|
||||
}
|
||||
|
||||
/** The fee description passed in the transform command cannot be parsed. */
|
||||
public static class FeeDescriptionParseException extends ParameterValuePolicyErrorException {
|
||||
public FeeDescriptionParseException(String description) {
|
||||
|
||||
@@ -34,8 +34,8 @@ import static google.registry.flows.domain.token.AllocationTokenFlowUtils.maybeA
|
||||
import static google.registry.flows.domain.token.AllocationTokenFlowUtils.verifyBulkTokenAllowedOnDomain;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_RENEW;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.plusYears;
|
||||
import static google.registry.util.DateTimeUtils.toLocalDate;
|
||||
import static java.time.ZoneOffset.UTC;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -192,11 +192,7 @@ public final class DomainRenewFlow implements MutatingFlow {
|
||||
existingDomain = maybeApplyBulkPricingRemovalToken(existingDomain, allocationToken);
|
||||
|
||||
Instant newExpirationTime =
|
||||
existingDomain
|
||||
.getRegistrationExpirationTime()
|
||||
.atZone(UTC)
|
||||
.plusYears(years)
|
||||
.toInstant(); // Uncapped
|
||||
plusYears(existingDomain.getRegistrationExpirationTime(), years); // Uncapped
|
||||
validateRegistrationPeriod(now, newExpirationTime);
|
||||
Optional<FeeRenewCommandExtension> feeRenew =
|
||||
eppInput.getSingleExtension(FeeRenewCommandExtension.class);
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
package google.registry.flows.domain;
|
||||
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
|
||||
import static com.google.common.collect.Sets.symmetricDifference;
|
||||
import static com.google.common.collect.Sets.union;
|
||||
@@ -58,17 +57,17 @@ import google.registry.flows.custom.DomainUpdateFlowCustomLogic.BeforeSaveParame
|
||||
import google.registry.flows.custom.EntityChanges;
|
||||
import google.registry.flows.domain.DomainFlowUtils.NameserversNotSpecifiedForTldWithNameserverAllowListException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.RegistrantProhibitedException;
|
||||
import google.registry.flows.exceptions.ContactsProhibitedException;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.billing.BillingBase.Reason;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainCommand.Update;
|
||||
import google.registry.model.domain.DomainCommand.Update.AddRemove;
|
||||
import google.registry.model.domain.DomainCommand.Update.Change;
|
||||
import google.registry.model.domain.DomainCommand.Update.DomainAddRemove;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.fee.FeeUpdateCommandExtension;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.domain.secdns.DomainDsData;
|
||||
import google.registry.model.domain.secdns.SecDnsUpdateExtension;
|
||||
import google.registry.model.domain.secdns.SecDnsUpdateExtension.Add;
|
||||
import google.registry.model.domain.secdns.SecDnsUpdateExtension.Remove;
|
||||
@@ -118,6 +117,7 @@ import java.util.Optional;
|
||||
* @error {@link NameserversNotSpecifiedForTldWithNameserverAllowListException}
|
||||
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
|
||||
* @error {@link RegistrantProhibitedException}
|
||||
* @error {@link ContactsProhibitedException}
|
||||
* @error {@link DomainFlowUtils.SecDnsAllUsageException}
|
||||
* @error {@link DomainFlowUtils.TooManyDsRecordsException}
|
||||
* @error {@link DomainFlowUtils.TooManyNameserversException}
|
||||
@@ -214,8 +214,8 @@ public final class DomainUpdateFlow implements MutatingFlow {
|
||||
private void verifyUpdateAllowed(Update command, Domain existingDomain, Instant now)
|
||||
throws EppException {
|
||||
verifyOptionalAuthInfo(authInfo, existingDomain);
|
||||
AddRemove add = command.getInnerAdd();
|
||||
AddRemove remove = command.getInnerRemove();
|
||||
DomainAddRemove add = command.getInnerAdd();
|
||||
DomainAddRemove remove = command.getInnerRemove();
|
||||
String tldStr = existingDomain.getTld();
|
||||
if (!isSuperuser) {
|
||||
verifyNoDisallowedStatuses(existingDomain, UPDATE_DISALLOWED_STATUSES);
|
||||
@@ -234,8 +234,8 @@ public final class DomainUpdateFlow implements MutatingFlow {
|
||||
}
|
||||
|
||||
private Domain performUpdate(Update command, Domain domain, Instant now) throws EppException {
|
||||
AddRemove add = command.getInnerAdd();
|
||||
AddRemove remove = command.getInnerRemove();
|
||||
DomainAddRemove add = command.getInnerAdd();
|
||||
DomainAddRemove remove = command.getInnerRemove();
|
||||
Optional<SecDnsUpdateExtension> secDnsUpdate =
|
||||
eppInput.getSingleExtension(SecDnsUpdateExtension.class);
|
||||
verifyAddsAndRemoves(domain.getNameservers(), add.getNameservers(), remove.getNameservers());
|
||||
@@ -251,28 +251,29 @@ public final class DomainUpdateFlow implements MutatingFlow {
|
||||
Domain.Builder domainBuilder =
|
||||
domain
|
||||
.asBuilder()
|
||||
// Handle the secDNS extension. As dsData in secDnsUpdate is read from EPP input and
|
||||
// does not have domainRepoId set, we create a copy of the existing dsData without
|
||||
// domainRepoId for comparison.
|
||||
// Handle the secDNS extension.
|
||||
.setDsData(
|
||||
secDnsUpdate.isPresent()
|
||||
? updateDsData(
|
||||
domain.getDsData().stream()
|
||||
.map(DomainDsData::cloneWithoutDomainRepoId)
|
||||
.collect(toImmutableSet()),
|
||||
secDnsUpdate.get())
|
||||
? updateDsData(domain.getDsData(), secDnsUpdate.get())
|
||||
: domain.getDsData())
|
||||
.setLastEppUpdateTime(now)
|
||||
.setLastEppUpdateRegistrarId(registrarId)
|
||||
.addStatusValues(add.getStatusValues())
|
||||
.removeStatusValues(remove.getStatusValues())
|
||||
.setAuthInfo(Optional.ofNullable(change.getAuthInfo()).orElse(domain.getAuthInfo()));
|
||||
.setLastEppUpdateRegistrarId(registrarId);
|
||||
|
||||
if (!add.getStatusValues().isEmpty()) {
|
||||
domainBuilder.addStatusValues(add.getStatusValues());
|
||||
}
|
||||
if (!remove.getStatusValues().isEmpty()) {
|
||||
domainBuilder.removeStatusValues(remove.getStatusValues());
|
||||
}
|
||||
|
||||
domainBuilder.setAuthInfo(
|
||||
Optional.ofNullable(change.getAuthInfo()).orElse(domain.getAuthInfo()));
|
||||
|
||||
if (!add.getNameservers().isEmpty()) {
|
||||
domainBuilder.addNameservers(add.getNameservers().stream().collect(toImmutableSet()));
|
||||
domainBuilder.addNameservers(add.getNameservers());
|
||||
}
|
||||
if (!remove.getNameservers().isEmpty()) {
|
||||
domainBuilder.removeNameservers(remove.getNameservers().stream().collect(toImmutableSet()));
|
||||
domainBuilder.removeNameservers(remove.getNameservers());
|
||||
}
|
||||
|
||||
Optional<DomainUpdateSuperuserExtension> superuserExt =
|
||||
|
||||
@@ -36,7 +36,6 @@ import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
||||
import com.google.cloud.tasks.v2.Task;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.batch.AsyncTaskEnqueuer;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.dns.RefreshDnsOnHostRenameAction;
|
||||
import google.registry.flows.EppException;
|
||||
@@ -59,8 +58,8 @@ import google.registry.model.eppinput.ResourceCommand;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.model.host.HostCommand.Update;
|
||||
import google.registry.model.host.HostCommand.Update.AddRemove;
|
||||
import google.registry.model.host.HostCommand.Update.Change;
|
||||
import google.registry.model.host.HostCommand.Update.HostAddRemove;
|
||||
import google.registry.model.host.HostHistory;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.persistence.VKey;
|
||||
@@ -122,7 +121,6 @@ public final class HostUpdateFlow implements MutatingFlow {
|
||||
@Inject @TargetId String targetId;
|
||||
@Inject @Superuser boolean isSuperuser;
|
||||
@Inject HostHistory.Builder historyBuilder;
|
||||
@Inject AsyncTaskEnqueuer asyncTaskEnqueuer;
|
||||
@Inject EppResponse.Builder responseBuilder;
|
||||
@Inject CloudTasksUtils cloudTasksUtils;
|
||||
|
||||
@@ -148,6 +146,7 @@ public final class HostUpdateFlow implements MutatingFlow {
|
||||
? tm().loadByKey(existingHost.getSuperordinateDomain()).cloneProjectedAtTime(now)
|
||||
: null;
|
||||
// Note that lookupSuperordinateDomain calls cloneProjectedAtTime on the domain for us.
|
||||
|
||||
Optional<Domain> newSuperordinateDomain =
|
||||
lookupSuperordinateDomain(validateHostName(newHostName), now);
|
||||
verifySuperordinateDomainNotInPendingDelete(newSuperordinateDomain.orElse(null));
|
||||
@@ -157,8 +156,8 @@ public final class HostUpdateFlow implements MutatingFlow {
|
||||
if (isHostRename && ForeignKeyUtils.loadKey(Host.class, newHostName, now).isPresent()) {
|
||||
throw new HostAlreadyExistsException(newHostName);
|
||||
}
|
||||
AddRemove add = command.getInnerAdd();
|
||||
AddRemove remove = command.getInnerRemove();
|
||||
HostAddRemove add = command.getInnerAdd();
|
||||
HostAddRemove remove = command.getInnerRemove();
|
||||
verifyAddsAndRemoves(
|
||||
existingHost.getStatusValues(), add.getStatusValues(), remove.getStatusValues());
|
||||
verifyAddsAndRemoves(
|
||||
|
||||
@@ -22,16 +22,6 @@ import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.SyntaxErrorException;
|
||||
import google.registry.flows.EppException.UnimplementedCommandException;
|
||||
import google.registry.flows.Flow;
|
||||
import google.registry.flows.contact.ContactCheckFlow;
|
||||
import google.registry.flows.contact.ContactCreateFlow;
|
||||
import google.registry.flows.contact.ContactDeleteFlow;
|
||||
import google.registry.flows.contact.ContactInfoFlow;
|
||||
import google.registry.flows.contact.ContactTransferApproveFlow;
|
||||
import google.registry.flows.contact.ContactTransferCancelFlow;
|
||||
import google.registry.flows.contact.ContactTransferQueryFlow;
|
||||
import google.registry.flows.contact.ContactTransferRejectFlow;
|
||||
import google.registry.flows.contact.ContactTransferRequestFlow;
|
||||
import google.registry.flows.contact.ContactUpdateFlow;
|
||||
import google.registry.flows.domain.DomainCheckFlow;
|
||||
import google.registry.flows.domain.DomainClaimsCheckFlow;
|
||||
import google.registry.flows.domain.DomainCreateFlow;
|
||||
@@ -55,7 +45,6 @@ import google.registry.flows.poll.PollRequestFlow;
|
||||
import google.registry.flows.session.HelloFlow;
|
||||
import google.registry.flows.session.LoginFlow;
|
||||
import google.registry.flows.session.LogoutFlow;
|
||||
import google.registry.model.contact.ContactCommand;
|
||||
import google.registry.model.domain.DomainCommand;
|
||||
import google.registry.model.domain.launch.LaunchCheckExtension;
|
||||
import google.registry.model.domain.launch.LaunchCheckExtension.CheckType;
|
||||
@@ -202,11 +191,6 @@ public class FlowPicker {
|
||||
private static final FlowProvider RESOURCE_CRUD_FLOW_PROVIDER = new FlowProvider() {
|
||||
private final Map<Class<?>, Class<? extends Flow>> resourceCrudFlows =
|
||||
new ImmutableMap.Builder<Class<?>, Class<? extends Flow>>()
|
||||
.put(ContactCommand.Check.class, ContactCheckFlow.class)
|
||||
.put(ContactCommand.Create.class, ContactCreateFlow.class)
|
||||
.put(ContactCommand.Delete.class, ContactDeleteFlow.class)
|
||||
.put(ContactCommand.Info.class, ContactInfoFlow.class)
|
||||
.put(ContactCommand.Update.class, ContactUpdateFlow.class)
|
||||
.put(DomainCommand.Create.class, DomainCreateFlow.class)
|
||||
.put(DomainCommand.Delete.class, DomainDeleteFlow.class)
|
||||
.put(DomainCommand.Info.class, DomainInfoFlow.class)
|
||||
@@ -230,24 +214,6 @@ public class FlowPicker {
|
||||
new FlowProvider() {
|
||||
private final Table<Class<?>, TransferOp, Class<? extends Flow>> transferFlows =
|
||||
ImmutableTable.<Class<?>, TransferOp, Class<? extends Flow>>builder()
|
||||
.put(
|
||||
ContactCommand.Transfer.class,
|
||||
TransferOp.APPROVE,
|
||||
ContactTransferApproveFlow.class)
|
||||
.put(
|
||||
ContactCommand.Transfer.class,
|
||||
TransferOp.CANCEL,
|
||||
ContactTransferCancelFlow.class)
|
||||
.put(
|
||||
ContactCommand.Transfer.class, TransferOp.QUERY, ContactTransferQueryFlow.class)
|
||||
.put(
|
||||
ContactCommand.Transfer.class,
|
||||
TransferOp.REJECT,
|
||||
ContactTransferRejectFlow.class)
|
||||
.put(
|
||||
ContactCommand.Transfer.class,
|
||||
TransferOp.REQUEST,
|
||||
ContactTransferRequestFlow.class)
|
||||
.put(
|
||||
DomainCommand.Transfer.class,
|
||||
TransferOp.APPROVE,
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
package google.registry.flows.session;
|
||||
|
||||
import static com.google.common.collect.Sets.difference;
|
||||
import static google.registry.model.common.FeatureFlag.FeatureName.PROHIBIT_CONTACT_OBJECTS_ON_LOGIN;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
|
||||
@@ -40,7 +39,6 @@ import google.registry.flows.TlsCredentials.BadRegistrarIpAddressException;
|
||||
import google.registry.flows.TlsCredentials.MissingRegistrarCertificateException;
|
||||
import google.registry.flows.TransportCredentials;
|
||||
import google.registry.flows.TransportCredentials.BadRegistrarPasswordException;
|
||||
import google.registry.model.common.FeatureFlag;
|
||||
import google.registry.model.eppcommon.ProtocolDefinition;
|
||||
import google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
@@ -120,9 +118,7 @@ public class LoginFlow implements MutatingFlow {
|
||||
Set<String> unsupportedObjectServices =
|
||||
difference(
|
||||
nullToEmpty(services.getObjectServices()),
|
||||
FeatureFlag.isActiveNow(PROHIBIT_CONTACT_OBJECTS_ON_LOGIN)
|
||||
? ProtocolDefinition.SUPPORTED_OBJECT_SERVICES
|
||||
: ProtocolDefinition.SUPPORTED_OBJECT_SERVICES_WITH_CONTACT);
|
||||
ProtocolDefinition.SUPPORTED_OBJECT_SERVICES);
|
||||
stopwatch.tick("LoginFlow difference unsupportedObjectServices");
|
||||
if (!unsupportedObjectServices.isEmpty()) {
|
||||
throw new UnimplementedObjectServiceException();
|
||||
|
||||
@@ -56,6 +56,7 @@ public final class GmailClient {
|
||||
private final InternetAddress outgoingEmailAddressWithUsername;
|
||||
private final InternetAddress replyToEmailAddress;
|
||||
|
||||
// TODO(b/510340944): drop sender info. Sender is determined by the Gmail credential owner.
|
||||
@Inject
|
||||
GmailClient(
|
||||
Lazy<Gmail> gmail,
|
||||
@@ -77,6 +78,20 @@ public final class GmailClient {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/510340944): Remove this experiment method
|
||||
public GmailClient(
|
||||
Lazy<Gmail> gmail,
|
||||
Retrier retrier,
|
||||
@Config("isEmailSendingEnabled") boolean isEmailSendingEnabled,
|
||||
@Config("replyToEmailAddress") InternetAddress replyToEmailAddress) {
|
||||
|
||||
this.gmail = gmail;
|
||||
this.retrier = retrier;
|
||||
this.isEmailSendingEnabled = isEmailSendingEnabled;
|
||||
this.replyToEmailAddress = replyToEmailAddress;
|
||||
this.outgoingEmailAddressWithUsername = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends {@code emailMessage} using {@link Gmail}.
|
||||
*/
|
||||
@@ -116,7 +131,9 @@ public final class GmailClient {
|
||||
try {
|
||||
MimeMessage msg =
|
||||
new MimeMessage(Session.getDefaultInstance(new Properties(), /* authenticator= */ null));
|
||||
msg.setFrom(this.outgoingEmailAddressWithUsername);
|
||||
if (this.outgoingEmailAddressWithUsername != null) {
|
||||
msg.setFrom(this.outgoingEmailAddressWithUsername);
|
||||
}
|
||||
msg.setReplyTo(
|
||||
new InternetAddress[] {emailMessage.replyToEmailAddress().orElse(replyToEmailAddress)});
|
||||
msg.addRecipients(
|
||||
|
||||
@@ -22,6 +22,7 @@ import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.keyring.api.Keyring;
|
||||
import google.registry.keyring.secretmanager.SecretManagerKeyring;
|
||||
import jakarta.inject.Singleton;
|
||||
import java.util.Optional;
|
||||
|
||||
/** Dagger module for {@link Keyring} */
|
||||
@Module
|
||||
@@ -55,7 +56,7 @@ public abstract class KeyringModule {
|
||||
|
||||
@Provides
|
||||
@Config("valkeyCertificateAuthority")
|
||||
public static String provideValkeyCertificateAuthority(Keyring keyring) {
|
||||
return keyring.getValkeyCertificateAuthority();
|
||||
public static Optional<String> provideValkeyCertificateAuthority(Keyring keyring) {
|
||||
return Optional.ofNullable(keyring.getValkeyCertificateAuthority());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,19 +106,24 @@ public abstract class ImmutableObject implements Cloneable {
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
/** Returns a clone of the given object. */
|
||||
@SuppressWarnings("unchecked")
|
||||
protected static <T extends ImmutableObject> T clone(T t) {
|
||||
@Override
|
||||
@SuppressWarnings("AmbiguousMethodReference")
|
||||
public ImmutableObject clone() {
|
||||
try {
|
||||
T clone = (T) t.clone();
|
||||
// Clear the hashCode since we often mutate clones before handing them out.
|
||||
ImmutableObject clone = (ImmutableObject) super.clone();
|
||||
clone.hashCode = null;
|
||||
return clone;
|
||||
} catch (CloneNotSupportedException e) { // Yes it is.
|
||||
throw new IllegalStateException();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a clone of the given object. */
|
||||
@SuppressWarnings({"unchecked", "AmbiguousMethodReference"})
|
||||
protected static <T extends ImmutableObject> T clone(T t) {
|
||||
return (T) t.clone();
|
||||
}
|
||||
|
||||
/** Returns a clone of the given object with empty fields set to null. */
|
||||
protected static <T extends ImmutableObject> T cloneEmptyToNull(T t) {
|
||||
return ModelUtils.cloneEmptyToNull(t);
|
||||
@@ -233,7 +238,7 @@ public abstract class ImmutableObject implements Cloneable {
|
||||
}
|
||||
}
|
||||
|
||||
/** Marker to indicate that this filed should be ignored by {@link #toDiffableFieldMap}. */
|
||||
/** Marker to indicate that this field should be ignored by {@link #toDiffableFieldMap}. */
|
||||
@Documented
|
||||
@Retention(RUNTIME)
|
||||
@Target(FIELD)
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.contact;
|
||||
|
||||
import google.registry.model.eppcommon.Address;
|
||||
import jakarta.persistence.Embeddable;
|
||||
|
||||
/**
|
||||
* EPP Contact Address
|
||||
*
|
||||
* <p>This class is embedded inside the {@link PostalInfo} of an EPP contact to hold its address.
|
||||
* The fields are all defined in parent class {@link Address}, but the subclass is still necessary
|
||||
* to pick up the contact namespace.
|
||||
*
|
||||
* <p>This does not implement {@code Overlayable} because it is intended to be bulk replaced on
|
||||
* update.
|
||||
*
|
||||
* @see PostalInfo
|
||||
*/
|
||||
@Embeddable
|
||||
public class ContactAddress extends Address {
|
||||
|
||||
/** Builder for {@link ContactAddress}. */
|
||||
public static class Builder extends Address.Builder<ContactAddress> {}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.contact;
|
||||
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
|
||||
/** A version of authInfo specifically for contacts. */
|
||||
@Embeddable
|
||||
@XmlType(namespace = "urn:ietf:params:xml:ns:contact-1.0")
|
||||
public class ContactAuthInfo extends AuthInfo {
|
||||
public static ContactAuthInfo create(PasswordAuth pw) {
|
||||
ContactAuthInfo instance = new ContactAuthInfo();
|
||||
instance.pw = pw;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.contact;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.contact.PostalInfo.Type;
|
||||
import google.registry.model.eppinput.ResourceCommand.AbstractSingleResourceCommand;
|
||||
import google.registry.model.eppinput.ResourceCommand.ResourceCheck;
|
||||
import google.registry.model.eppinput.ResourceCommand.ResourceCreateOrChange;
|
||||
import google.registry.model.eppinput.ResourceCommand.ResourceUpdate;
|
||||
import google.registry.model.eppinput.ResourceCommand.SingleResourceCommand;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlTransient;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import jakarta.xml.bind.annotation.adapters.CollapsedStringAdapter;
|
||||
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** A collection of (vestigial) Contact commands. */
|
||||
public class ContactCommand {
|
||||
|
||||
/** The fields on "chgType" from <a href="http://tools.ietf.org/html/rfc5733">RFC5733</a>. */
|
||||
@XmlTransient
|
||||
public static class ContactCreateOrChange extends ImmutableObject
|
||||
implements ResourceCreateOrChange<EppResource.Builder<?, ?>> {
|
||||
|
||||
/** Postal info for the contact. */
|
||||
List<PostalInfo> postalInfo;
|
||||
|
||||
/** Contact’s voice number. */
|
||||
ContactPhoneNumber voice;
|
||||
|
||||
/** Contact’s fax number. */
|
||||
ContactPhoneNumber fax;
|
||||
|
||||
/** Contact’s email address. */
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
String email;
|
||||
|
||||
/** Authorization info (aka transfer secret) of the contact. */
|
||||
ContactAuthInfo authInfo;
|
||||
|
||||
/** Disclosure policy. */
|
||||
Disclose disclose;
|
||||
|
||||
/** Helper method to move between the postal infos list and the individual getters. */
|
||||
protected Map<Type, PostalInfo> getPostalInfosAsMap() {
|
||||
// There can be no more than 2 postalInfos (enforced by the schema), and if there are 2 they
|
||||
// must be of different types (not enforced). If the type is repeated, uniqueIndex will throw.
|
||||
checkState(nullToEmpty(postalInfo).size() <= 2);
|
||||
return Maps.uniqueIndex(nullToEmpty(postalInfo), PostalInfo::getType);
|
||||
}
|
||||
|
||||
public ContactPhoneNumber getVoice() {
|
||||
return voice;
|
||||
}
|
||||
|
||||
public ContactPhoneNumber getFax() {
|
||||
return fax;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public ContactAuthInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
|
||||
public Disclose getDisclose() {
|
||||
return disclose;
|
||||
}
|
||||
|
||||
public PostalInfo getInternationalizedPostalInfo() {
|
||||
return getPostalInfosAsMap().get(Type.INTERNATIONALIZED);
|
||||
}
|
||||
|
||||
public PostalInfo getLocalizedPostalInfo() {
|
||||
return getPostalInfosAsMap().get(Type.LOCALIZED);
|
||||
}
|
||||
}
|
||||
|
||||
/** An abstract contact command that contains authorization info. */
|
||||
@XmlTransient
|
||||
public static class AbstractContactAuthCommand extends AbstractSingleResourceCommand {
|
||||
/** Authorization info used to validate if client has permissions to perform this operation. */
|
||||
ContactAuthInfo authInfo;
|
||||
|
||||
@Override
|
||||
public ContactAuthInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A create command for a (vestigial) Contact, mapping "createType" from <a
|
||||
* href="http://tools.ietf.org/html/rfc5733">RFC5733</a>}.
|
||||
*/
|
||||
@XmlType(propOrder = {"contactId", "postalInfo", "voice", "fax", "email", "authInfo", "disclose"})
|
||||
@XmlRootElement
|
||||
public static class Create extends ContactCreateOrChange
|
||||
implements SingleResourceCommand, ResourceCreateOrChange<EppResource.Builder<?, ?>> {
|
||||
/**
|
||||
* Unique identifier for this contact.
|
||||
*
|
||||
* <p>This is only unique in the sense that for any given lifetime specified as the time range
|
||||
* from (creationTime, deletionTime) there can only be one contact in the database with this id.
|
||||
* However, there can be many contacts with the same id and non-overlapping lifetimes.
|
||||
*/
|
||||
@XmlElement(name = "id")
|
||||
String contactId;
|
||||
|
||||
@Override
|
||||
public String getTargetId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactAuthInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/** A delete command for a (vestigial) Contact. */
|
||||
@XmlRootElement
|
||||
public static class Delete extends AbstractSingleResourceCommand {}
|
||||
|
||||
/** An info request for a (vestigial) Contact. */
|
||||
@XmlRootElement
|
||||
@XmlType(propOrder = {"targetId", "authInfo"})
|
||||
public static class Info extends AbstractContactAuthCommand {}
|
||||
|
||||
/** A check request for (vestigial) Contact. */
|
||||
@XmlRootElement
|
||||
public static class Check extends ResourceCheck {}
|
||||
|
||||
/** A transfer operation for a (vestigial) Contact. */
|
||||
@XmlRootElement
|
||||
@XmlType(propOrder = {"targetId", "authInfo"})
|
||||
public static class Transfer extends AbstractContactAuthCommand {}
|
||||
|
||||
/** An update to a (vestigial) Contact. */
|
||||
@XmlRootElement
|
||||
@XmlType(propOrder = {"targetId", "innerAdd", "innerRemove", "innerChange"})
|
||||
public static class Update
|
||||
extends ResourceUpdate<Update.AddRemove, EppResource.Builder<?, ?>, Update.Change> {
|
||||
|
||||
@XmlElement(name = "chg")
|
||||
protected Change innerChange;
|
||||
|
||||
@XmlElement(name = "add")
|
||||
protected AddRemove innerAdd;
|
||||
|
||||
@XmlElement(name = "rem")
|
||||
protected AddRemove innerRemove;
|
||||
|
||||
@Override
|
||||
protected Change getNullableInnerChange() {
|
||||
return innerChange;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AddRemove getNullableInnerAdd() {
|
||||
return innerAdd;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AddRemove getNullableInnerRemove() {
|
||||
return innerRemove;
|
||||
}
|
||||
|
||||
/** The inner change type on a contact update command. */
|
||||
public static class AddRemove extends ResourceUpdate.AddRemove {}
|
||||
|
||||
/** The inner change type on a contact update command. */
|
||||
@XmlType(propOrder = {"postalInfo", "voice", "fax", "email", "authInfo", "disclose"})
|
||||
public static class Change extends ContactCreateOrChange {}
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.contact;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.auto.value.AutoValue.CopyAnnotations;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppoutput.EppResponse.ResponseData;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import jakarta.xml.bind.annotation.adapters.CollapsedStringAdapter;
|
||||
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
import java.time.Instant;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** The {@link ResponseData} returned for an EPP info flow on a contact. */
|
||||
@XmlRootElement(name = "infData")
|
||||
@XmlType(
|
||||
propOrder = {
|
||||
"contactId",
|
||||
"repoId",
|
||||
"statusValues",
|
||||
"postalInfos",
|
||||
"voiceNumber",
|
||||
"faxNumber",
|
||||
"emailAddress",
|
||||
"currentSponsorRegistrarId",
|
||||
"creationRegistrarId",
|
||||
"creationTime",
|
||||
"lastEppUpdateRegistrarId",
|
||||
"lastEppUpdateTime",
|
||||
"lastTransferTime",
|
||||
"authInfo",
|
||||
"disclose"
|
||||
})
|
||||
@AutoValue
|
||||
@CopyAnnotations
|
||||
public abstract class ContactInfoData implements ResponseData {
|
||||
|
||||
@XmlElement(name = "id")
|
||||
abstract String getContactId();
|
||||
|
||||
@XmlElement(name = "roid")
|
||||
abstract String getRepoId();
|
||||
|
||||
@XmlElement(name = "status")
|
||||
abstract ImmutableSet<StatusValue> getStatusValues();
|
||||
|
||||
@XmlElement(name = "postalInfo")
|
||||
abstract ImmutableList<PostalInfo> getPostalInfos();
|
||||
|
||||
@XmlElement(name = "voice")
|
||||
@Nullable
|
||||
abstract ContactPhoneNumber getVoiceNumber();
|
||||
|
||||
@XmlElement(name = "fax")
|
||||
@Nullable
|
||||
abstract ContactPhoneNumber getFaxNumber();
|
||||
|
||||
@XmlElement(name = "email")
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
@Nullable
|
||||
abstract String getEmailAddress();
|
||||
|
||||
@XmlElement(name = "clID")
|
||||
abstract String getCurrentSponsorRegistrarId();
|
||||
|
||||
@XmlElement(name = "crID")
|
||||
abstract String getCreationRegistrarId();
|
||||
|
||||
@XmlElement(name = "crDate")
|
||||
abstract Instant getCreationTime();
|
||||
|
||||
@XmlElement(name = "upID")
|
||||
@Nullable
|
||||
abstract String getLastEppUpdateRegistrarId();
|
||||
|
||||
@XmlElement(name = "upDate")
|
||||
@Nullable
|
||||
abstract Instant getLastEppUpdateTime();
|
||||
|
||||
@XmlElement(name = "trDate")
|
||||
@Nullable
|
||||
abstract Instant getLastTransferTime();
|
||||
|
||||
@XmlElement(name = "authInfo")
|
||||
@Nullable
|
||||
abstract ContactAuthInfo getAuthInfo();
|
||||
|
||||
@XmlElement(name = "disclose")
|
||||
@Nullable
|
||||
abstract Disclose getDisclose();
|
||||
|
||||
/** Builder for {@link ContactInfoData}. */
|
||||
@AutoValue.Builder
|
||||
public abstract static class Builder {
|
||||
public abstract Builder setContactId(String contactId);
|
||||
public abstract Builder setRepoId(String repoId);
|
||||
public abstract Builder setStatusValues(ImmutableSet<StatusValue> statusValues);
|
||||
public abstract Builder setPostalInfos(ImmutableList<PostalInfo> postalInfos);
|
||||
public abstract Builder setVoiceNumber(@Nullable ContactPhoneNumber voiceNumber);
|
||||
public abstract Builder setFaxNumber(@Nullable ContactPhoneNumber faxNumber);
|
||||
public abstract Builder setEmailAddress(@Nullable String emailAddress);
|
||||
|
||||
public abstract Builder setCurrentSponsorRegistrarId(String currentSponsorRegistrarId);
|
||||
|
||||
public abstract Builder setCreationRegistrarId(String creationRegistrarId);
|
||||
|
||||
public abstract Builder setCreationTime(Instant creationTime);
|
||||
|
||||
public abstract Builder setLastEppUpdateRegistrarId(@Nullable String lastEppUpdateRegistrarId);
|
||||
|
||||
public abstract Builder setLastEppUpdateTime(@Nullable Instant lastEppUpdateTime);
|
||||
|
||||
public abstract Builder setLastTransferTime(@Nullable Instant lastTransferTime);
|
||||
|
||||
public abstract Builder setAuthInfo(@Nullable ContactAuthInfo authInfo);
|
||||
public abstract Builder setDisclose(@Nullable Disclose disclose);
|
||||
public abstract ContactInfoData build();
|
||||
}
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new AutoValue_ContactInfoData.Builder();
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.contact;
|
||||
|
||||
import google.registry.model.eppcommon.PhoneNumber;
|
||||
import jakarta.persistence.Embeddable;
|
||||
|
||||
/**
|
||||
* EPP Contact Phone Number
|
||||
*
|
||||
* <p>This class is embedded inside a (vestigial) Contact to hold the phone number of an EPP
|
||||
* contact. The fields are all defined in the parent class {@link PhoneNumber}, but the subclass is
|
||||
* still necessary to pick up the contact namespace.
|
||||
*/
|
||||
@Embeddable
|
||||
public class ContactPhoneNumber extends PhoneNumber {
|
||||
|
||||
/** Builder for {@link ContactPhoneNumber}. */
|
||||
public static class Builder extends PhoneNumber.Builder<ContactPhoneNumber> {}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.contact;
|
||||
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.UnsafeSerializable;
|
||||
import google.registry.model.eppcommon.PresenceMarker;
|
||||
import google.registry.persistence.converter.PostalInfoChoiceListUserType;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.xml.bind.annotation.XmlAttribute;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import org.hibernate.annotations.Type;
|
||||
|
||||
/** The "discloseType" from <a href="http://tools.ietf.org/html/rfc5733">RFC5733</a>. */
|
||||
@Embeddable
|
||||
@XmlType(propOrder = {"name", "org", "addr", "voice", "fax", "email"})
|
||||
public class Disclose extends ImmutableObject implements UnsafeSerializable {
|
||||
|
||||
@Type(PostalInfoChoiceListUserType.class)
|
||||
List<PostalInfoChoice> name;
|
||||
|
||||
@Type(PostalInfoChoiceListUserType.class)
|
||||
List<PostalInfoChoice> org;
|
||||
|
||||
@Type(PostalInfoChoiceListUserType.class)
|
||||
List<PostalInfoChoice> addr;
|
||||
|
||||
@Embedded PresenceMarker voice;
|
||||
|
||||
@Embedded PresenceMarker fax;
|
||||
|
||||
@Embedded PresenceMarker email;
|
||||
|
||||
@XmlAttribute
|
||||
Boolean flag;
|
||||
|
||||
public ImmutableList<PostalInfoChoice> getNames() {
|
||||
return nullToEmptyImmutableCopy(name);
|
||||
}
|
||||
|
||||
public ImmutableList<PostalInfoChoice> getOrgs() {
|
||||
return nullToEmptyImmutableCopy(org);
|
||||
}
|
||||
|
||||
public ImmutableList<PostalInfoChoice> getAddrs() {
|
||||
return nullToEmptyImmutableCopy(addr);
|
||||
}
|
||||
|
||||
public PresenceMarker getVoice() {
|
||||
return voice;
|
||||
}
|
||||
|
||||
public PresenceMarker getFax() {
|
||||
return fax;
|
||||
}
|
||||
|
||||
public PresenceMarker getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public Boolean getFlag() {
|
||||
return flag;
|
||||
}
|
||||
|
||||
/** The "intLocType" from <a href="http://tools.ietf.org/html/rfc5733">RFC5733</a>. */
|
||||
public static class PostalInfoChoice extends ImmutableObject implements Serializable {
|
||||
@XmlAttribute
|
||||
PostalInfo.Type type;
|
||||
|
||||
public PostalInfo.Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public static PostalInfoChoice create(PostalInfo.Type type) {
|
||||
PostalInfoChoice instance = new PostalInfoChoice();
|
||||
instance.type = type;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/** A builder for {@link Disclose} since it is immutable. */
|
||||
public static class Builder extends Buildable.Builder<Disclose> {
|
||||
public Builder setNames(ImmutableList<PostalInfoChoice> names) {
|
||||
getInstance().name = names;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setOrgs(ImmutableList<PostalInfoChoice> orgs) {
|
||||
getInstance().org = orgs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAddrs(ImmutableList<PostalInfoChoice> addrs) {
|
||||
getInstance().addr = addrs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setVoice(PresenceMarker voice) {
|
||||
getInstance().voice = voice;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setFax(PresenceMarker fax) {
|
||||
getInstance().fax = fax;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEmail(PresenceMarker email) {
|
||||
getInstance().email = email;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setFlag(boolean flag) {
|
||||
getInstance().flag = flag;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.contact;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.Buildable.Overlayable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.UnsafeSerializable;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.xml.bind.annotation.XmlAttribute;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlEnumValue;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import jakarta.xml.bind.annotation.adapters.NormalizedStringAdapter;
|
||||
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Implementation of both "postalInfoType" and "chgPostalInfoType" from <a href=
|
||||
* "http://tools.ietf.org/html/rfc5733">RFC5733</a>.
|
||||
*/
|
||||
@Embeddable
|
||||
@XmlType(propOrder = {"name", "org", "address", "type"})
|
||||
public class PostalInfo extends ImmutableObject
|
||||
implements Overlayable<PostalInfo>, UnsafeSerializable {
|
||||
|
||||
/** The type of the address, either localized or international. */
|
||||
public enum Type {
|
||||
@XmlEnumValue("loc")
|
||||
LOCALIZED,
|
||||
@XmlEnumValue("int")
|
||||
INTERNATIONALIZED
|
||||
}
|
||||
|
||||
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
|
||||
String name;
|
||||
|
||||
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
|
||||
String org;
|
||||
|
||||
@XmlElement(name = "addr")
|
||||
ContactAddress address;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@XmlAttribute
|
||||
Type type;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getOrg() {
|
||||
return org;
|
||||
}
|
||||
|
||||
public ContactAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PostalInfo overlay(PostalInfo source) {
|
||||
// Don't overlay the type field, as that should never change.
|
||||
checkState(source.type == null || source.type == type);
|
||||
return asBuilder()
|
||||
.setName(Optional.ofNullable(source.getName()).orElse(name))
|
||||
.setOrg(Optional.ofNullable(source.getOrg()).orElse(org))
|
||||
.setAddress(Optional.ofNullable(source.getAddress()).orElse(address))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder asBuilder() {
|
||||
return new Builder(clone(this));
|
||||
}
|
||||
|
||||
/** A builder for constructing {@link PostalInfo}, since its changes get overlayed. */
|
||||
public static class Builder extends Buildable.Builder<PostalInfo> {
|
||||
public Builder() {}
|
||||
|
||||
private Builder(PostalInfo instance) {
|
||||
super(instance);
|
||||
}
|
||||
|
||||
public Builder setName(String name) {
|
||||
getInstance().name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setOrg(String org) {
|
||||
getInstance().org = org;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAddress(ContactAddress address) {
|
||||
getInstance().address = address;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setType(Type type) {
|
||||
getInstance().type = type;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
@XmlSchema(
|
||||
namespace = "urn:ietf:params:xml:ns:contact-1.0",
|
||||
xmlns = @XmlNs(prefix = "contact", namespaceURI = "urn:ietf:params:xml:ns:contact-1.0"),
|
||||
elementFormDefault = XmlNsForm.QUALIFIED)
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlJavaTypeAdapters({@XmlJavaTypeAdapter(UtcInstantAdapter.class)})
|
||||
package google.registry.model.contact;
|
||||
|
||||
import google.registry.xml.UtcInstantAdapter;
|
||||
import jakarta.xml.bind.annotation.XmlAccessType;
|
||||
import jakarta.xml.bind.annotation.XmlAccessorType;
|
||||
import jakarta.xml.bind.annotation.XmlNs;
|
||||
import jakarta.xml.bind.annotation.XmlNsForm;
|
||||
import jakarta.xml.bind.annotation.XmlSchema;
|
||||
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
|
||||
@@ -17,7 +17,6 @@ package google.registry.model.domain;
|
||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.Sets.difference;
|
||||
import static google.registry.util.CollectionUtils.difference;
|
||||
import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
||||
import static google.registry.util.CollectionUtils.nullSafeImmutableCopy;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
@@ -28,8 +27,11 @@ import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.flows.EppException.ParameterValuePolicyErrorException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.RegistrantProhibitedException;
|
||||
import google.registry.flows.exceptions.ContactsProhibitedException;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.ForeignKeyUtils;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppinput.ResourceCommand.AbstractSingleResourceCommand;
|
||||
import google.registry.model.eppinput.ResourceCommand.ResourceCheck;
|
||||
import google.registry.model.eppinput.ResourceCommand.ResourceCreateOrChange;
|
||||
@@ -37,6 +39,8 @@ import google.registry.model.eppinput.ResourceCommand.ResourceUpdate;
|
||||
import google.registry.model.eppinput.ResourceCommand.SingleResourceCommand;
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.persistence.VKey;
|
||||
import jakarta.xml.bind.annotation.XmlAccessType;
|
||||
import jakarta.xml.bind.annotation.XmlAccessorType;
|
||||
import jakarta.xml.bind.annotation.XmlAttribute;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlElementWrapper;
|
||||
@@ -68,10 +72,10 @@ public class DomainCommand {
|
||||
throws InvalidReferencesException, ParameterValuePolicyErrorException;
|
||||
}
|
||||
|
||||
/** The fields on "chgType" from <a href="http://tools.ietf.org/html/rfc5731">RFC5731</a>. */
|
||||
/** The fields on "chgType" from <a href="https://tools.ietf.org/html/rfc5731">RFC5731</a>. */
|
||||
@XmlTransient
|
||||
public static class DomainCreateOrChange<B extends Domain.Builder> extends ImmutableObject
|
||||
implements ResourceCreateOrChange<B> {
|
||||
public abstract static class DomainCreateOrChange<B extends Domain.Builder>
|
||||
extends ImmutableObject implements ResourceCreateOrChange<B> {
|
||||
|
||||
/** The contactId of the registrant who registered this domain. */
|
||||
@XmlElement(name = "registrant")
|
||||
@@ -92,9 +96,10 @@ public class DomainCommand {
|
||||
|
||||
/**
|
||||
* A create command for a {@link Domain}, mapping "createType" from <a
|
||||
* href="http://tools.ietf.org/html/rfc5731">RFC5731</a>.
|
||||
* href="https://tools.ietf.org/html/rfc5731">RFC5731</a>.
|
||||
*/
|
||||
@XmlRootElement
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(
|
||||
propOrder = {
|
||||
"domainName",
|
||||
@@ -147,17 +152,12 @@ public class DomainCommand {
|
||||
return nullToEmptyImmutableCopy(nameservers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainAuthInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
|
||||
/** Creates a copy of this {@link Create} with hard links to hosts and contacts. */
|
||||
@Override
|
||||
public Create cloneAndLinkReferences(Instant now)
|
||||
throws InvalidReferencesException, ParameterValuePolicyErrorException {
|
||||
Create clone = clone(this);
|
||||
clone.nameservers = linkHosts(clone.nameserverHostNames, now);
|
||||
clone.nameservers = linkHosts(nullSafeImmutableCopy(clone.nameserverHostNames), now);
|
||||
if (registrantContactId != null) {
|
||||
throw new RegistrantProhibitedException();
|
||||
}
|
||||
@@ -166,14 +166,65 @@ public class DomainCommand {
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
/** Builder for {@link Create}. */
|
||||
public static class Builder extends Buildable.Builder<Create> {
|
||||
public Builder setDomainName(String domainName) {
|
||||
getInstance().domainName = domainName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPeriod(Period period) {
|
||||
getInstance().period = period;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setNameserverHostNames(ImmutableSet<String> nameserverHostNames) {
|
||||
getInstance().nameserverHostNames =
|
||||
isNullOrEmpty(nameserverHostNames) ? null : nameserverHostNames;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setForeignKeyedDesignatedContacts(
|
||||
ImmutableSet<ForeignKeyedDesignatedContact> foreignKeyedDesignatedContacts) {
|
||||
getInstance().foreignKeyedDesignatedContacts =
|
||||
isNullOrEmpty(foreignKeyedDesignatedContacts) ? null : foreignKeyedDesignatedContacts;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRegistrant(String registrant) {
|
||||
getInstance().registrantContactId = registrant;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAuthInfo(DomainAuthInfo authInfo) {
|
||||
getInstance().authInfo = authInfo;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** A delete command for a {@link Domain}. */
|
||||
@XmlRootElement
|
||||
public static class Delete extends AbstractSingleResourceCommand {}
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class Delete extends AbstractSingleResourceCommand {
|
||||
@XmlElement(name = "name")
|
||||
String name;
|
||||
|
||||
@Override
|
||||
public String getTargetId() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetId(String targetId) {
|
||||
this.name = targetId;
|
||||
}
|
||||
}
|
||||
|
||||
/** An info request for a {@link Domain}. */
|
||||
@XmlRootElement
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class Info extends ImmutableObject implements SingleResourceCommand {
|
||||
|
||||
/** The name of the domain to look up, and an attribute specifying the host lookup type. */
|
||||
@@ -226,7 +277,7 @@ public class DomainCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainAuthInfo getAuthInfo() {
|
||||
public AuthInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
}
|
||||
@@ -237,12 +288,27 @@ public class DomainCommand {
|
||||
|
||||
/** A renew command for a {@link Domain}. */
|
||||
@XmlRootElement
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = {"name", "currentExpirationDate", "period"})
|
||||
public static class Renew extends AbstractSingleResourceCommand {
|
||||
@XmlElement(name = "name")
|
||||
String name;
|
||||
|
||||
@Override
|
||||
public String getTargetId() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetId(String targetId) {
|
||||
this.name = targetId;
|
||||
}
|
||||
|
||||
@XmlElement(name = "curExpDate")
|
||||
LocalDate currentExpirationDate;
|
||||
|
||||
/** The period that this domain's state was set to last for. */
|
||||
Period period;
|
||||
@XmlElement Period period;
|
||||
|
||||
public LocalDate getCurrentExpirationDate() {
|
||||
return currentExpirationDate;
|
||||
@@ -251,13 +317,46 @@ public class DomainCommand {
|
||||
public Period getPeriod() {
|
||||
return firstNonNull(period, DEFAULT_PERIOD);
|
||||
}
|
||||
|
||||
/** Builder for {@link Renew}. */
|
||||
public static class Builder extends Buildable.Builder<Renew> {
|
||||
public Builder setTargetId(String targetId) {
|
||||
getInstance().setTargetId(targetId);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCurrentExpirationDate(LocalDate currentExpirationDate) {
|
||||
getInstance().currentExpirationDate = currentExpirationDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPeriod(Period period) {
|
||||
getInstance().period = period;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** A transfer operation for a {@link Domain}. */
|
||||
@XmlRootElement
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = {"name", "period", "authInfo"})
|
||||
public static class Transfer extends AbstractSingleResourceCommand {
|
||||
@XmlElement(name = "name")
|
||||
String name;
|
||||
|
||||
@Override
|
||||
public String getTargetId() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetId(String targetId) {
|
||||
this.name = targetId;
|
||||
}
|
||||
|
||||
/** The period to extend this domain's registration upon completion of the transfer. */
|
||||
Period period;
|
||||
@XmlElement Period period;
|
||||
|
||||
/** Authorization info used to validate if client has permissions to perform this operation. */
|
||||
DomainAuthInfo authInfo;
|
||||
@@ -267,25 +366,40 @@ public class DomainCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainAuthInfo getAuthInfo() {
|
||||
public AuthInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/** An update to a {@link Domain}. */
|
||||
@XmlRootElement
|
||||
@XmlType(propOrder = {"targetId", "innerAdd", "innerRemove", "innerChange"})
|
||||
public static class Update extends ResourceUpdate<Update.AddRemove, Domain.Builder, Update.Change>
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = {"name", "innerAdd", "innerRemove", "innerChange"})
|
||||
public static class Update
|
||||
extends ResourceUpdate<Update.DomainAddRemove, Domain.Builder, Update.Change>
|
||||
implements CreateOrUpdate<Update> {
|
||||
|
||||
@XmlElement(name = "name")
|
||||
String name;
|
||||
|
||||
@Override
|
||||
public String getTargetId() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetId(String targetId) {
|
||||
this.name = targetId;
|
||||
}
|
||||
|
||||
@XmlElement(name = "chg")
|
||||
protected Change innerChange;
|
||||
|
||||
@XmlElement(name = "add")
|
||||
protected AddRemove innerAdd;
|
||||
protected DomainAddRemove innerAdd;
|
||||
|
||||
@XmlElement(name = "rem")
|
||||
protected AddRemove innerRemove;
|
||||
protected DomainAddRemove innerRemove;
|
||||
|
||||
@Override
|
||||
protected Change getNullableInnerChange() {
|
||||
@@ -293,25 +407,49 @@ public class DomainCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AddRemove getNullableInnerAdd() {
|
||||
protected DomainAddRemove getNullableInnerAdd() {
|
||||
return innerAdd;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AddRemove getNullableInnerRemove() {
|
||||
protected DomainAddRemove getNullableInnerRemove() {
|
||||
return innerRemove;
|
||||
}
|
||||
|
||||
public boolean noChangesPresent() {
|
||||
AddRemove emptyAddRemove = new AddRemove();
|
||||
DomainAddRemove emptyAddRemove = new DomainAddRemove();
|
||||
return emptyAddRemove.equals(getInnerAdd())
|
||||
&& emptyAddRemove.equals(getInnerRemove())
|
||||
&& new Change().equals(getInnerChange());
|
||||
}
|
||||
|
||||
/** Builder for {@link Update}. */
|
||||
public static class Builder extends Buildable.Builder<Update> {
|
||||
public Builder setTargetId(String targetId) {
|
||||
getInstance().setTargetId(targetId);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setInnerAdd(DomainAddRemove innerAdd) {
|
||||
getInstance().innerAdd = innerAdd;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setInnerRemove(DomainAddRemove innerRemove) {
|
||||
getInstance().innerRemove = innerRemove;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setInnerChange(Change innerChange) {
|
||||
getInstance().innerChange = innerChange;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/** The inner change type on a domain update command. */
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = {"nameserverHostNames", "foreignKeyedDesignatedContacts", "statusValues"})
|
||||
public static class AddRemove extends ResourceUpdate.AddRemove {
|
||||
public static class DomainAddRemove extends ResourceUpdate.AddRemove {
|
||||
/** Fully qualified host names of the hosts that are the nameservers for the domain. */
|
||||
@XmlElementWrapper(name = "ns")
|
||||
@XmlElement(name = "hostObj")
|
||||
@@ -324,6 +462,25 @@ public class DomainCommand {
|
||||
@XmlElement(name = "contact")
|
||||
Set<ForeignKeyedDesignatedContact> foreignKeyedDesignatedContacts;
|
||||
|
||||
@XmlElement(name = "status")
|
||||
Set<StatusValue> statusValues;
|
||||
|
||||
public boolean isEmpty() {
|
||||
return isNullOrEmpty(nameserverHostNames)
|
||||
&& isNullOrEmpty(foreignKeyedDesignatedContacts)
|
||||
&& isNullOrEmpty(statusValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatusValues(ImmutableSet<StatusValue> statusValues) {
|
||||
this.statusValues = statusValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSet<StatusValue> getStatusValues() {
|
||||
return nullToEmptyImmutableCopy(statusValues);
|
||||
}
|
||||
|
||||
public ImmutableSet<String> getNameserverHostNames() {
|
||||
return nullSafeImmutableCopy(nameserverHostNames);
|
||||
}
|
||||
@@ -332,11 +489,25 @@ public class DomainCommand {
|
||||
return nullToEmptyImmutableCopy(nameservers);
|
||||
}
|
||||
|
||||
/** Creates a copy of this {@link AddRemove} with hard links to hosts and contacts. */
|
||||
private AddRemove cloneAndLinkReferences(Instant now)
|
||||
/** Builder for {@link DomainAddRemove}. */
|
||||
public static class Builder extends Buildable.Builder<DomainAddRemove> {
|
||||
public Builder setNameserverHostNames(ImmutableSet<String> nameserverHostNames) {
|
||||
getInstance().nameserverHostNames =
|
||||
isNullOrEmpty(nameserverHostNames) ? null : nameserverHostNames;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setStatusValues(ImmutableSet<StatusValue> statusValues) {
|
||||
getInstance().statusValues = isNullOrEmpty(statusValues) ? null : statusValues;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates a copy of this {@link DomainAddRemove} with hard links to hosts and contacts. */
|
||||
private DomainAddRemove cloneAndLinkReferences(Instant now)
|
||||
throws InvalidReferencesException, ContactsProhibitedException {
|
||||
AddRemove clone = clone(this);
|
||||
clone.nameservers = linkHosts(clone.nameserverHostNames, now);
|
||||
DomainAddRemove clone = clone(this);
|
||||
clone.nameservers = linkHosts(nullSafeImmutableCopy(clone.nameserverHostNames), now);
|
||||
if (!isNullOrEmpty(foreignKeyedDesignatedContacts)) {
|
||||
throw new ContactsProhibitedException();
|
||||
}
|
||||
@@ -345,8 +516,17 @@ public class DomainCommand {
|
||||
}
|
||||
|
||||
/** The inner change type on a domain update command. */
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = {"registrantContactId", "authInfo"})
|
||||
public static class Change extends DomainCreateOrChange<Domain.Builder> {
|
||||
/** Builder for {@link Change}. */
|
||||
public static class Builder extends Buildable.Builder<Change> {
|
||||
public Builder setAuthInfo(DomainAuthInfo authInfo) {
|
||||
getInstance().authInfo = authInfo;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
Change cloneAndLinkReferences() throws RegistrantProhibitedException {
|
||||
Change clone = clone(this);
|
||||
if (clone.registrantContactId != null) {
|
||||
@@ -373,7 +553,7 @@ public class DomainCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<VKey<Host>> linkHosts(Set<String> hostNames, Instant now)
|
||||
private static ImmutableSet<VKey<Host>> linkHosts(ImmutableSet<String> hostNames, Instant now)
|
||||
throws InvalidReferencesException {
|
||||
if (hostNames == null) {
|
||||
return null;
|
||||
@@ -383,7 +563,7 @@ public class DomainCommand {
|
||||
|
||||
/** Loads host keys to cached EPP resources by their foreign keys. */
|
||||
private static ImmutableMap<String, VKey<Host>> loadByForeignKeysCached(
|
||||
Set<String> foreignKeys, Instant now) throws InvalidReferencesException {
|
||||
ImmutableSet<String> foreignKeys, Instant now) throws InvalidReferencesException {
|
||||
ImmutableMap<String, VKey<Host>> fks =
|
||||
ForeignKeyUtils.loadKeysByCacheIfEnabled(Host.class, foreignKeys, now);
|
||||
if (!fks.keySet().equals(foreignKeys)) {
|
||||
@@ -394,14 +574,14 @@ public class DomainCommand {
|
||||
}
|
||||
|
||||
/** Exception to throw when referenced objects don't exist. */
|
||||
public static class InvalidReferencesException extends Exception {
|
||||
public static class InvalidReferencesException extends ParameterValuePolicyErrorException {
|
||||
private final ImmutableSet<String> foreignKeys;
|
||||
private final Class<?> type;
|
||||
|
||||
InvalidReferencesException(Class<?> type, ImmutableSet<String> foreignKeys) {
|
||||
public InvalidReferencesException(Class<?> type, Set<String> foreignKeys) {
|
||||
super(String.format("Invalid %s reference IDs: %s", type.getSimpleName(), foreignKeys));
|
||||
this.type = checkNotNull(type);
|
||||
this.foreignKeys = foreignKeys;
|
||||
this.foreignKeys = nullToEmptyImmutableCopy(foreignKeys);
|
||||
}
|
||||
|
||||
public ImmutableSet<String> getForeignKeys() {
|
||||
|
||||
@@ -15,21 +15,33 @@
|
||||
package google.registry.model.domain.fee;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Range;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.time.Period;
|
||||
|
||||
/**
|
||||
* A fee, in currency units specified elsewhere in the xml, with type of the fee an optional fee
|
||||
* description.
|
||||
* A fee, in currency units specified elsewhere in the XML, with a type and an optional description.
|
||||
*/
|
||||
public class Fee extends BaseFee {
|
||||
|
||||
public static final ImmutableSet<String> FEE_EXTENSION_URIS =
|
||||
ImmutableSet.of(
|
||||
ServiceExtension.FEE_1_00.getUri(),
|
||||
ServiceExtension.FEE_0_12.getUri(),
|
||||
ServiceExtension.FEE_0_11.getUri(),
|
||||
ServiceExtension.FEE_0_6.getUri());
|
||||
|
||||
@Override
|
||||
public Fee clone() {
|
||||
return (Fee) super.clone();
|
||||
}
|
||||
|
||||
/** Creates a Fee for the given cost and type with the default description. */
|
||||
public static Fee create(
|
||||
BigDecimal cost, FeeType type, boolean isPremium, Object... descriptionArgs) {
|
||||
@@ -54,18 +66,46 @@ public class Fee extends BaseFee {
|
||||
private static Fee createWithCustomDescription(
|
||||
BigDecimal cost, FeeType type, boolean isPremium, String description) {
|
||||
Fee instance = new Fee();
|
||||
instance.cost = checkNotNull(cost);
|
||||
checkArgument(instance.cost.signum() >= 0, "Cost must be a positive number");
|
||||
instance.type = checkNotNull(type);
|
||||
checkArgumentNotNull(cost, "Cost cannot be null");
|
||||
checkArgument(cost.signum() >= 0, "Cost must be a non-negative number");
|
||||
instance.cost = cost;
|
||||
instance.type = type;
|
||||
instance.isPremium = isPremium;
|
||||
instance.description = description;
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static final ImmutableSet<String> FEE_EXTENSION_URIS =
|
||||
ImmutableSet.of(
|
||||
ServiceExtension.FEE_1_00.getUri(),
|
||||
ServiceExtension.FEE_0_12.getUri(),
|
||||
ServiceExtension.FEE_0_11.getUri(),
|
||||
ServiceExtension.FEE_0_6.getUri());
|
||||
/** Builder for {@link Fee}. */
|
||||
public static class Builder extends Buildable.Builder<Fee> {
|
||||
|
||||
/** Sets the cost of the fee. */
|
||||
public Builder setCost(BigDecimal cost) {
|
||||
getInstance().cost = cost;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the description of the fee. */
|
||||
public Builder setDescription(String description) {
|
||||
getInstance().description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets whether the fee is refundable. */
|
||||
public Builder setRefundable(Boolean refundable) {
|
||||
getInstance().refundable = refundable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the grace period of the fee. */
|
||||
public Builder setGracePeriod(Period gracePeriod) {
|
||||
getInstance().gracePeriod = gracePeriod;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets when the fee is applied. */
|
||||
public Builder setApplied(AppliedType applied) {
|
||||
getInstance().applied = applied;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,10 @@ public abstract class FeeQueryCommandExtensionItem extends ImmutableObject {
|
||||
/** The period for the command being checked. */
|
||||
Period period;
|
||||
|
||||
public void setPeriod(Period period) {
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
/**
|
||||
* Three-character ISO4217 currency code.
|
||||
*
|
||||
|
||||
@@ -30,7 +30,7 @@ public abstract class FeeTransformCommandExtension
|
||||
extends ImmutableObject implements CommandExtension {
|
||||
|
||||
/** The currency of the fee. */
|
||||
CurrencyUnit currency;
|
||||
@XmlElement public CurrencyUnit currency;
|
||||
|
||||
/**
|
||||
* The magnitude of the fee, in the specified units, with an optional description.
|
||||
@@ -38,7 +38,7 @@ public abstract class FeeTransformCommandExtension
|
||||
* <p>This is a list because a single operation can involve multiple fees.
|
||||
*/
|
||||
@XmlElement(name = "fee")
|
||||
List<Fee> fees;
|
||||
public List<Fee> fees;
|
||||
|
||||
public CurrencyUnit getCurrency() {
|
||||
return currency;
|
||||
|
||||
@@ -31,7 +31,7 @@ import org.joda.money.CurrencyUnit;
|
||||
public class FeeTransformResponseExtension extends ImmutableObject implements ResponseExtension {
|
||||
|
||||
/** The currency of the fee. */
|
||||
CurrencyUnit currency;
|
||||
@XmlElement CurrencyUnit currency;
|
||||
|
||||
/**
|
||||
* The magnitude of the fee, in the specified units, with an optional description.
|
||||
@@ -63,12 +63,12 @@ public class FeeTransformResponseExtension extends ImmutableObject implements Re
|
||||
}
|
||||
|
||||
public Builder setFees(List<Fee> fees) {
|
||||
getInstance().fees = fees;
|
||||
getInstance().fees = forceEmptyToNull(nullToEmptyImmutableCopy(fees));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCredits(List<Credit> credits) {
|
||||
getInstance().credits = forceEmptyToNull(credits);
|
||||
getInstance().credits = forceEmptyToNull(nullToEmptyImmutableCopy(credits));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package google.registry.model.domain.fee06;
|
||||
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.fee.FeeCheckCommandExtensionItem;
|
||||
import google.registry.model.domain.fee.FeeExtensionCommandDescriptor;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
@@ -33,6 +34,16 @@ public class FeeCheckCommandExtensionItemV06 extends FeeCheckCommandExtensionIte
|
||||
/** The command being checked. */
|
||||
FeeExtensionCommandDescriptor command;
|
||||
|
||||
public static FeeCheckCommandExtensionItemV06 create(
|
||||
String name, CurrencyUnit currency, FeeExtensionCommandDescriptor command, Period period) {
|
||||
FeeCheckCommandExtensionItemV06 instance = new FeeCheckCommandExtensionItemV06();
|
||||
instance.name = name;
|
||||
instance.currency = currency;
|
||||
instance.command = command;
|
||||
instance.setPeriod(period);
|
||||
return instance;
|
||||
}
|
||||
|
||||
/** The name of the command being checked. */
|
||||
@Override
|
||||
public CommandName getCommandName() {
|
||||
|
||||
@@ -25,16 +25,22 @@ import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import java.util.List;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
|
||||
/** Version 0.6 of the fee extension that may be present on domain check commands. */
|
||||
/**
|
||||
* An XML data object that represents version 0.6 of the fee extension that may be present on EPP
|
||||
* domain check commands.
|
||||
*/
|
||||
@XmlRootElement(name = "check")
|
||||
public class FeeCheckCommandExtensionV06 extends ImmutableObject
|
||||
implements FeeCheckCommandExtension<
|
||||
FeeCheckCommandExtensionItemV06,
|
||||
FeeCheckResponseExtensionV06> {
|
||||
FeeCheckCommandExtensionItemV06, FeeCheckResponseExtensionV06> {
|
||||
|
||||
@XmlElement(name = "domain")
|
||||
List<FeeCheckCommandExtensionItemV06> items;
|
||||
|
||||
public void setItems(ImmutableList<FeeCheckCommandExtensionItemV06> items) {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CurrencyUnit getCurrency() {
|
||||
return null; // This version of the fee extension doesn't specify a top-level currency.
|
||||
|
||||
@@ -15,13 +15,20 @@
|
||||
package google.registry.model.domain.fee06;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.domain.fee.Credit;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.domain.fee.FeeCreateCommandExtension;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlTransient;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
|
||||
/** A fee extension that may be present on domain create commands. */
|
||||
/**
|
||||
* An XML data object that represents a fee extension that may be present on EPP domain create
|
||||
* commands.
|
||||
*/
|
||||
@XmlRootElement(name = "create")
|
||||
@XmlType(propOrder = {"currency", "fees"})
|
||||
public class FeeCreateCommandExtensionV06 extends FeeCreateCommandExtension {
|
||||
@@ -31,12 +38,23 @@ public class FeeCreateCommandExtensionV06 extends FeeCreateCommandExtension {
|
||||
return new FeeTransformResponseExtension.Builder(new FeeCreateResponseExtensionV06());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is overridden and not annotated for JAXB because this version of the extension
|
||||
* doesn't support the "credit" field.
|
||||
*/
|
||||
/** This version of the extension doesn't support the "credit" field. */
|
||||
@Override
|
||||
@XmlTransient
|
||||
public ImmutableList<Credit> getCredits() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
/** Builder for {@link FeeCreateCommandExtensionV06}. */
|
||||
public static class Builder extends Buildable.Builder<FeeCreateCommandExtensionV06> {
|
||||
public Builder setCurrency(CurrencyUnit currency) {
|
||||
getInstance().currency = currency;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setFees(ImmutableList<Fee> fees) {
|
||||
getInstance().fees = fees;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
package google.registry.model.domain.fee06;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.domain.fee.Credit;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
@@ -25,12 +23,5 @@ import jakarta.xml.bind.annotation.XmlType;
|
||||
* domain create commands.
|
||||
*/
|
||||
@XmlRootElement(name = "creData")
|
||||
@XmlType(propOrder = {"currency", "fees"})
|
||||
public class FeeCreateResponseExtensionV06 extends FeeTransformResponseExtension {
|
||||
|
||||
/** This version of the extension doesn't support the "credit" field. */
|
||||
@Override
|
||||
public ImmutableList<Credit> getCredits() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
}
|
||||
@XmlType(propOrder = {"currency", "fees", "credits"})
|
||||
public class FeeCreateResponseExtensionV06 extends FeeTransformResponseExtension {}
|
||||
|
||||
@@ -20,7 +20,7 @@ import jakarta.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* An XML data object that represents a fee extension that may be present on the response to EPP
|
||||
* domain create commands.
|
||||
* domain delete commands.
|
||||
*/
|
||||
@XmlRootElement(name = "delData")
|
||||
@XmlType(propOrder = {"currency", "fees", "credits"})
|
||||
|
||||
@@ -19,9 +19,13 @@ import google.registry.model.domain.fee.Credit;
|
||||
import google.registry.model.domain.fee.FeeRenewCommandExtension;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlTransient;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
|
||||
/** A fee extension that may be present on domain renew commands. */
|
||||
/**
|
||||
* An XML data object that represents a fee extension that may be present on EPP domain renew
|
||||
* commands.
|
||||
*/
|
||||
@XmlRootElement(name = "renew")
|
||||
@XmlType(propOrder = {"currency", "fees"})
|
||||
public class FeeRenewCommandExtensionV06 extends FeeRenewCommandExtension {
|
||||
@@ -33,6 +37,7 @@ public class FeeRenewCommandExtensionV06 extends FeeRenewCommandExtension {
|
||||
|
||||
/** This version of the extension doesn't support the "credit" field. */
|
||||
@Override
|
||||
@XmlTransient
|
||||
public ImmutableList<Credit> getCredits() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
package google.registry.model.domain.fee06;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.domain.fee.Credit;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
@@ -25,12 +23,5 @@ import jakarta.xml.bind.annotation.XmlType;
|
||||
* domain renew commands.
|
||||
*/
|
||||
@XmlRootElement(name = "renData")
|
||||
@XmlType(propOrder = {"currency", "fees"})
|
||||
public class FeeRenewResponseExtensionV06 extends FeeTransformResponseExtension {
|
||||
|
||||
/** This version of the extension doesn't support the "credit" field. */
|
||||
@Override
|
||||
public ImmutableList<Credit> getCredits() {
|
||||
return super.getCredits();
|
||||
}
|
||||
}
|
||||
@XmlType(propOrder = {"currency", "fees", "credits"})
|
||||
public class FeeRenewResponseExtensionV06 extends FeeTransformResponseExtension {}
|
||||
|
||||
@@ -19,9 +19,13 @@ import google.registry.model.domain.fee.Credit;
|
||||
import google.registry.model.domain.fee.FeeTransferCommandExtension;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlTransient;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
|
||||
/** A fee extension that may be present on domain transfer requests. */
|
||||
/**
|
||||
* An XML data object that represents a fee extension that may be present on EPP domain transfer
|
||||
* commands.
|
||||
*/
|
||||
@XmlRootElement(name = "transfer")
|
||||
@XmlType(propOrder = {"currency", "fees"})
|
||||
public class FeeTransferCommandExtensionV06 extends FeeTransferCommandExtension {
|
||||
@@ -33,6 +37,7 @@ public class FeeTransferCommandExtensionV06 extends FeeTransferCommandExtension
|
||||
|
||||
/** This version of the extension doesn't support the "credit" field. */
|
||||
@Override
|
||||
@XmlTransient
|
||||
public ImmutableList<Credit> getCredits() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@@ -14,23 +14,14 @@
|
||||
|
||||
package google.registry.model.domain.fee06;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.domain.fee.Credit;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* An XML data object that represents a fee extension that may be present on the response to EPP
|
||||
* domain transfer requests.
|
||||
* domain transfer commands.
|
||||
*/
|
||||
@XmlRootElement(name = "trnData")
|
||||
@XmlType(propOrder = {"currency", "fees"})
|
||||
public class FeeTransferResponseExtensionV06 extends FeeTransformResponseExtension {
|
||||
|
||||
/** This version of the extension doesn't support the "credit" field. */
|
||||
@Override
|
||||
public ImmutableList<Credit> getCredits() {
|
||||
return super.getCredits();
|
||||
}
|
||||
}
|
||||
@XmlType(propOrder = {"currency", "fees", "credits"})
|
||||
public class FeeTransferResponseExtensionV06 extends FeeTransformResponseExtension {}
|
||||
|
||||
@@ -19,9 +19,13 @@ import google.registry.model.domain.fee.Credit;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import google.registry.model.domain.fee.FeeUpdateCommandExtension;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlTransient;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
|
||||
/** A fee extension that may be present on domain update commands. */
|
||||
/**
|
||||
* An XML data object that represents a fee extension that may be present on EPP domain update
|
||||
* commands.
|
||||
*/
|
||||
@XmlRootElement(name = "update")
|
||||
@XmlType(propOrder = {"currency", "fees"})
|
||||
public class FeeUpdateCommandExtensionV06 extends FeeUpdateCommandExtension {
|
||||
@@ -33,6 +37,7 @@ public class FeeUpdateCommandExtensionV06 extends FeeUpdateCommandExtension {
|
||||
|
||||
/** This version of the extension doesn't support the "credit" field. */
|
||||
@Override
|
||||
@XmlTransient
|
||||
public ImmutableList<Credit> getCredits() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
package google.registry.model.domain.fee06;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.domain.fee.Credit;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
@@ -25,12 +23,5 @@ import jakarta.xml.bind.annotation.XmlType;
|
||||
* domain update commands.
|
||||
*/
|
||||
@XmlRootElement(name = "updData")
|
||||
@XmlType(propOrder = {"currency", "fees"})
|
||||
public class FeeUpdateResponseExtensionV06 extends FeeTransformResponseExtension {
|
||||
|
||||
/** This version of the extension doesn't support the "credit" field. */
|
||||
@Override
|
||||
public ImmutableList<Credit> getCredits() {
|
||||
return super.getCredits();
|
||||
}
|
||||
}
|
||||
@XmlType(propOrder = {"currency", "fees", "credits"})
|
||||
public class FeeUpdateResponseExtensionV06 extends FeeTransformResponseExtension {}
|
||||
|
||||
@@ -17,13 +17,16 @@ package google.registry.model.domain.fee12;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.domain.fee.Credit;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.domain.fee.FeeCreateCommandExtension;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import java.util.List;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
|
||||
/** A fee extension that may be present on domain create commands. */
|
||||
@XmlRootElement(name = "create")
|
||||
@@ -42,4 +45,22 @@ public class FeeCreateCommandExtensionV12 extends FeeCreateCommandExtension {
|
||||
public FeeTransformResponseExtension.Builder createResponseBuilder() {
|
||||
return new FeeTransformResponseExtension.Builder(new FeeCreateResponseExtensionV12());
|
||||
}
|
||||
|
||||
/** Builder for {@link FeeCreateCommandExtensionV12}. */
|
||||
public static class Builder extends Buildable.Builder<FeeCreateCommandExtensionV12> {
|
||||
public Builder setCurrency(CurrencyUnit currency) {
|
||||
getInstance().currency = currency;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setFees(ImmutableList<Fee> fees) {
|
||||
getInstance().fees = fees;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCredits(ImmutableList<Credit> credits) {
|
||||
getInstance().credits = credits;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,18 +17,21 @@ package google.registry.model.domain.fee12;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.domain.fee.Credit;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.domain.fee.FeeRenewCommandExtension;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import java.util.List;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
|
||||
/** A fee extension that may be present on domain renew commands. */
|
||||
@XmlRootElement(name = "renew")
|
||||
@XmlType(propOrder = {"currency", "fees", "credits"})
|
||||
public class FeeRenewCommandExtensionV12 extends FeeRenewCommandExtension {
|
||||
public class FeeRenewCommandExtensionV12 extends FeeRenewCommandExtension {
|
||||
|
||||
@XmlElement(name = "credit")
|
||||
List<Credit> credits;
|
||||
@@ -42,4 +45,22 @@ public class FeeRenewCommandExtensionV12 extends FeeRenewCommandExtension {
|
||||
public FeeTransformResponseExtension.Builder createResponseBuilder() {
|
||||
return new FeeTransformResponseExtension.Builder(new FeeRenewResponseExtensionV12());
|
||||
}
|
||||
|
||||
/** Builder for {@link FeeRenewCommandExtensionV12}. */
|
||||
public static class Builder extends Buildable.Builder<FeeRenewCommandExtensionV12> {
|
||||
public Builder setCurrency(CurrencyUnit currency) {
|
||||
getInstance().currency = currency;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setFees(ImmutableList<Fee> fees) {
|
||||
getInstance().fees = fees;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCredits(ImmutableList<Credit> credits) {
|
||||
getInstance().credits = credits;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,16 @@ package google.registry.model.domain.fee12;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.domain.fee.Credit;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.domain.fee.FeeTransferCommandExtension;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import java.util.List;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
|
||||
/** A fee extension that may be present on domain transfer requests. */
|
||||
@XmlRootElement(name = "transfer")
|
||||
@@ -42,4 +45,22 @@ public class FeeTransferCommandExtensionV12 extends FeeTransferCommandExtension
|
||||
public FeeTransformResponseExtension.Builder createResponseBuilder() {
|
||||
return new FeeTransformResponseExtension.Builder(new FeeTransferResponseExtensionV12());
|
||||
}
|
||||
|
||||
/** Builder for {@link FeeTransferCommandExtensionV12}. */
|
||||
public static class Builder extends Buildable.Builder<FeeTransferCommandExtensionV12> {
|
||||
public Builder setCurrency(CurrencyUnit currency) {
|
||||
getInstance().currency = currency;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setFees(ImmutableList<Fee> fees) {
|
||||
getInstance().fees = fees;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCredits(ImmutableList<Credit> credits) {
|
||||
getInstance().credits = credits;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,16 @@ package google.registry.model.domain.fee12;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.domain.fee.Credit;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import google.registry.model.domain.fee.FeeUpdateCommandExtension;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import java.util.List;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
|
||||
/** A fee extension that may be present on domain update commands. */
|
||||
@XmlRootElement(name = "update")
|
||||
@@ -42,4 +45,22 @@ public class FeeUpdateCommandExtensionV12 extends FeeUpdateCommandExtension {
|
||||
public FeeTransformResponseExtension.Builder createResponseBuilder() {
|
||||
return new FeeTransformResponseExtension.Builder(new FeeUpdateResponseExtensionV12());
|
||||
}
|
||||
|
||||
/** Builder for {@link FeeUpdateCommandExtensionV12}. */
|
||||
public static class Builder extends Buildable.Builder<FeeUpdateCommandExtensionV12> {
|
||||
public Builder setCurrency(CurrencyUnit currency) {
|
||||
getInstance().currency = currency;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setFees(ImmutableList<Fee> fees) {
|
||||
getInstance().fees = fees;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCredits(ImmutableList<Credit> credits) {
|
||||
getInstance().credits = credits;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,13 +14,12 @@
|
||||
|
||||
package google.registry.model.domain.feestdv1;
|
||||
|
||||
import static google.registry.util.CollectionUtils.forceEmptyToNull;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.domain.fee.FeeCheckResponseExtensionItem;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import jakarta.xml.bind.annotation.XmlTransient;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
|
||||
/** The version 1.0 response for a domain check on a single resource. */
|
||||
@@ -38,6 +37,7 @@ public class FeeCheckResponseExtensionItemStdV1 extends FeeCheckResponseExtensio
|
||||
* doesn't support "period".
|
||||
*/
|
||||
@Override
|
||||
@XmlTransient
|
||||
public Period getPeriod() {
|
||||
return super.getPeriod();
|
||||
}
|
||||
@@ -47,6 +47,7 @@ public class FeeCheckResponseExtensionItemStdV1 extends FeeCheckResponseExtensio
|
||||
* doesn't support "fee".
|
||||
*/
|
||||
@Override
|
||||
@XmlTransient
|
||||
public ImmutableList<Fee> getFees() {
|
||||
return super.getFees();
|
||||
}
|
||||
@@ -74,7 +75,7 @@ public class FeeCheckResponseExtensionItemStdV1 extends FeeCheckResponseExtensio
|
||||
|
||||
@Override
|
||||
public Builder setFees(ImmutableList<Fee> fees) {
|
||||
commandBuilder.setFee(forceEmptyToNull(ImmutableList.copyOf(fees)));
|
||||
commandBuilder.setFee(fees);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,34 +19,37 @@ import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.eppinput.EppInput.CommandExtension;
|
||||
import jakarta.xml.bind.annotation.XmlAttribute;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlEnumValue;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* An XML data object that represents a launch extension that may be present on EPP domain check
|
||||
* commands.
|
||||
*
|
||||
* <p>This object holds XML data which JAXB will unmarshal from an EPP domain check command
|
||||
* extension. The XML will have the following enclosing structure:
|
||||
* extension. The XML will have the following enclosing structure:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <epp>
|
||||
* <command>
|
||||
* <create>
|
||||
* <!-- domain check XML data -->
|
||||
* </create>
|
||||
* <extension>
|
||||
* <launch:check>
|
||||
* <!-- launch check XML payload data -->
|
||||
* </launch:check>
|
||||
* </extension>
|
||||
* </command>
|
||||
* </epp>
|
||||
* } </pre>
|
||||
* <pre>{@code
|
||||
* <epp>
|
||||
* <command>
|
||||
* <create>
|
||||
* <!-- domain check XML data -->
|
||||
* </create>
|
||||
* <extension>
|
||||
* <launch:check>
|
||||
* <!-- launch check XML payload data -->
|
||||
* </launch:check>
|
||||
* </extension>
|
||||
* </command>
|
||||
* </epp>
|
||||
* }</pre>
|
||||
*
|
||||
* @see CommandExtension
|
||||
*/
|
||||
@XmlRootElement(name = "check")
|
||||
@XmlType(propOrder = "phase")
|
||||
public class LaunchCheckExtension extends ImmutableObject implements CommandExtension {
|
||||
|
||||
/** The default check type is "claims" if not specified. */
|
||||
@@ -67,11 +70,18 @@ public class LaunchCheckExtension extends ImmutableObject implements CommandExte
|
||||
* The launch phase this command is intended to run against. If it does not match the server's
|
||||
* current launch phase, the command will be rejected.
|
||||
*/
|
||||
LaunchPhase phase;
|
||||
@XmlElement LaunchPhase phase;
|
||||
|
||||
@XmlAttribute
|
||||
CheckType type;
|
||||
|
||||
public static LaunchCheckExtension create(CheckType type, LaunchPhase phase) {
|
||||
LaunchCheckExtension instance = new LaunchCheckExtension();
|
||||
instance.type = type;
|
||||
instance.phase = phase;
|
||||
return instance;
|
||||
}
|
||||
|
||||
public CheckType getCheckType() {
|
||||
return firstNonNull(type, DEFAULT_CHECK_TYPE);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import google.registry.model.ImmutableObject;
|
||||
import jakarta.xml.bind.annotation.XmlAttribute;
|
||||
import jakarta.xml.bind.annotation.XmlValue;
|
||||
import java.util.Objects;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The launch phase of the TLD being addressed by this command.
|
||||
@@ -46,7 +47,7 @@ import java.util.Objects;
|
||||
* sets it is the one that needs to make sure the domain isn't a trademark and that the fields are
|
||||
* correct.
|
||||
*/
|
||||
public class LaunchPhase extends ImmutableObject {
|
||||
public final class LaunchPhase extends ImmutableObject {
|
||||
|
||||
/**
|
||||
* The phase during which trademark holders can submit domain registrations with trademark
|
||||
@@ -70,6 +71,9 @@ public class LaunchPhase extends ImmutableObject {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/** Private no-arg constructor required for JAXB and to enforce immutability elsewhere. */
|
||||
private LaunchPhase() {}
|
||||
|
||||
@XmlValue String phase;
|
||||
|
||||
/**
|
||||
@@ -79,6 +83,7 @@ public class LaunchPhase extends ImmutableObject {
|
||||
* <p>This is currently unused, but is retained so that incoming XMLs that include a subphase can
|
||||
* have it be reflected back.
|
||||
*/
|
||||
@Nullable
|
||||
@XmlAttribute(name = "name")
|
||||
String subphase;
|
||||
|
||||
|
||||
@@ -14,39 +14,62 @@
|
||||
|
||||
package google.registry.model.domain.metadata;
|
||||
|
||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.eppinput.EppInput.CommandExtension;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** A metadata extension that may be present on EPP create/mutate commands. */
|
||||
/**
|
||||
* Extension for EPP commands that provides metadata.
|
||||
*
|
||||
* @see <a href="https://www.google.com/search?q=EPP+metadata+extension">EPP Metadata Extension</a>
|
||||
*/
|
||||
@XmlRootElement(name = "metadata")
|
||||
@XmlType(propOrder = {"reason", "requestedByRegistrar", "isAnchorTenant"})
|
||||
public class MetadataExtension extends ImmutableObject implements CommandExtension {
|
||||
|
||||
/** The reason for the change. */
|
||||
@XmlElement(name = "reason")
|
||||
String reason;
|
||||
/** Reason for the command. */
|
||||
@XmlElement @Nullable String reason;
|
||||
|
||||
/** Whether a change was requested by a registrar. */
|
||||
@XmlElement(name = "requestedByRegistrar")
|
||||
boolean requestedByRegistrar;
|
||||
/** Whether the command was requested by a registrar. */
|
||||
@XmlElement Boolean requestedByRegistrar;
|
||||
|
||||
/**
|
||||
* Whether a domain is being created for an anchor tenant. This field is only
|
||||
* relevant for domain creates, and should be omitted for all other operations.
|
||||
*/
|
||||
/** Whether this is an anchor tenant. */
|
||||
@XmlElement(name = "anchorTenant")
|
||||
boolean isAnchorTenant;
|
||||
Boolean isAnchorTenant;
|
||||
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public boolean getRequestedByRegistrar() {
|
||||
public Boolean getRequestedByRegistrar() {
|
||||
return requestedByRegistrar;
|
||||
}
|
||||
|
||||
public boolean getIsAnchorTenant() {
|
||||
return isAnchorTenant;
|
||||
public Boolean getIsAnchorTenant() {
|
||||
return firstNonNull(isAnchorTenant, false);
|
||||
}
|
||||
|
||||
/** Builder for {@link MetadataExtension}. */
|
||||
public static class Builder extends Buildable.Builder<MetadataExtension> {
|
||||
public Builder setReason(String reason) {
|
||||
getInstance().reason = reason;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRequestedByRegistrar(Boolean requestedByRegistrar) {
|
||||
getInstance().requestedByRegistrar = requestedByRegistrar;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAnchorTenant(Boolean isAnchorTenant) {
|
||||
getInstance().isAnchorTenant = isAnchorTenant;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,12 +23,14 @@ import jakarta.persistence.Transient;
|
||||
import jakarta.xml.bind.DatatypeConverter;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlTransient;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import jakarta.xml.bind.annotation.adapters.HexBinaryAdapter;
|
||||
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
/** Base class for {@link DomainDsData} and {@link DomainDsDataHistory}. */
|
||||
@MappedSuperclass
|
||||
@Access(AccessType.FIELD)
|
||||
@XmlType(propOrder = {"keyTag", "algorithm", "digestType", "digest"})
|
||||
public abstract class DomainDsDataBase extends ImmutableObject implements UnsafeSerializable {
|
||||
|
||||
@XmlTransient @Transient @Insignificant String domainRepoId;
|
||||
|
||||
@@ -14,11 +14,13 @@
|
||||
|
||||
package google.registry.model.domain.secdns;
|
||||
|
||||
import static google.registry.util.CollectionUtils.nullSafeImmutableCopy;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.eppinput.EppInput.CommandExtension;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import java.util.Set;
|
||||
@@ -33,9 +35,10 @@ public class SecDnsCreateExtension extends ImmutableObject implements CommandExt
|
||||
* <p>We do not support expirations, but we need this field to be able to return appropriate
|
||||
* errors.
|
||||
*/
|
||||
Long maxSigLife;
|
||||
@XmlElement Long maxSigLife;
|
||||
|
||||
/** Signatures for this domain. */
|
||||
@XmlElement(name = "dsData")
|
||||
Set<DomainDsData> dsData;
|
||||
|
||||
public Long getMaxSigLife() {
|
||||
@@ -43,6 +46,19 @@ public class SecDnsCreateExtension extends ImmutableObject implements CommandExt
|
||||
}
|
||||
|
||||
public ImmutableSet<DomainDsData> getDsData() {
|
||||
return nullSafeImmutableCopy(dsData);
|
||||
return nullToEmptyImmutableCopy(dsData);
|
||||
}
|
||||
|
||||
/** Builder for {@link SecDnsCreateExtension}. */
|
||||
public static class Builder extends Buildable.Builder<SecDnsCreateExtension> {
|
||||
public Builder setDsData(ImmutableSet<DomainDsData> dsData) {
|
||||
getInstance().dsData = dsData;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMaxSigLife(Long maxSigLife) {
|
||||
getInstance().maxSigLife = maxSigLife;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package google.registry.model.domain.secdns;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.eppinput.EppInput.CommandExtension;
|
||||
import jakarta.xml.bind.annotation.XmlAttribute;
|
||||
@@ -46,7 +47,7 @@ public class SecDnsUpdateExtension extends ImmutableObject implements CommandExt
|
||||
Remove remove;
|
||||
|
||||
/** Allows adding new delegations. */
|
||||
Add add;
|
||||
@XmlElement Add add;
|
||||
|
||||
/** Would allow changing maxSigLife except that we don't support it. */
|
||||
@XmlElement(name = "chg")
|
||||
@@ -68,31 +69,88 @@ public class SecDnsUpdateExtension extends ImmutableObject implements CommandExt
|
||||
return Optional.ofNullable(change);
|
||||
}
|
||||
|
||||
/** Builder for {@link SecDnsUpdateExtension}. */
|
||||
public static class Builder extends Buildable.Builder<SecDnsUpdateExtension> {
|
||||
public Builder setUrgent(Boolean urgent) {
|
||||
getInstance().urgent = urgent;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRemove(Remove remove) {
|
||||
getInstance().remove = remove;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAdd(Add add) {
|
||||
getInstance().add = add;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@XmlTransient
|
||||
abstract static class AddRemoveBase extends ImmutableObject {
|
||||
/** Delegations to add or remove. */
|
||||
abstract static class Builder<T extends AddRemoveBase, B extends Builder<T, B>>
|
||||
extends Buildable.Builder<T> {
|
||||
public abstract B setDsData(ImmutableSet<DomainDsData> dsData);
|
||||
}
|
||||
}
|
||||
|
||||
/** The inner add type on the update extension. */
|
||||
@XmlType(propOrder = "dsData")
|
||||
public static class Add extends AddRemoveBase {
|
||||
/** Delegations to add. */
|
||||
@XmlElement(name = "dsData")
|
||||
Set<DomainDsData> dsData;
|
||||
|
||||
public ImmutableSet<DomainDsData> getDsData() {
|
||||
return nullToEmptyImmutableCopy(dsData);
|
||||
}
|
||||
}
|
||||
|
||||
/** The inner add type on the update extension. */
|
||||
public static class Add extends AddRemoveBase {}
|
||||
/** Builder for {@link Add}. */
|
||||
public static class Builder extends AddRemoveBase.Builder<Add, Builder> {
|
||||
@Override
|
||||
public Builder setDsData(ImmutableSet<DomainDsData> dsData) {
|
||||
getInstance().dsData = dsData;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The inner remove type on the update extension. */
|
||||
@XmlType(propOrder = {"all", "dsData"})
|
||||
public static class Remove extends AddRemoveBase {
|
||||
/** Whether to remove all delegations. */
|
||||
Boolean all;
|
||||
@XmlElement Boolean all;
|
||||
|
||||
/** Delegations to remove. */
|
||||
@XmlElement(name = "dsData")
|
||||
Set<DomainDsData> dsData;
|
||||
|
||||
public Boolean getAll() {
|
||||
return all;
|
||||
}
|
||||
|
||||
public ImmutableSet<DomainDsData> getDsData() {
|
||||
return nullToEmptyImmutableCopy(dsData);
|
||||
}
|
||||
|
||||
/** Builder for {@link Remove}. */
|
||||
public static class Builder extends AddRemoveBase.Builder<Remove, Builder> {
|
||||
public Builder setAll(Boolean all) {
|
||||
getInstance().all = all;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setDsData(ImmutableSet<DomainDsData> dsData) {
|
||||
getInstance().dsData = dsData;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The inner change type on the update extension, though we don't actually support changes. */
|
||||
@XmlType(propOrder = "maxSigLife")
|
||||
public static class Change extends ImmutableObject {
|
||||
/**
|
||||
* Time in seconds until the signature should expire.
|
||||
@@ -100,6 +158,7 @@ public class SecDnsUpdateExtension extends ImmutableObject implements CommandExt
|
||||
* <p>We do not support expirations, but we need this field to be able to return appropriate
|
||||
* errors.
|
||||
*/
|
||||
@XmlElement(name = "maxSigLife")
|
||||
Long maxSigLife;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,11 @@ package google.registry.model.domain.superuser;
|
||||
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
|
||||
/** A superuser extension that may be present on domain delete commands. */
|
||||
@XmlRootElement(name = "domainDelete")
|
||||
@XmlType(propOrder = {"redemptionGracePeriodDays", "pendingDeleteDays"})
|
||||
public class DomainDeleteSuperuserExtension extends SuperuserExtension {
|
||||
|
||||
@XmlElement(name = "redemptionGracePeriodDays")
|
||||
@@ -27,6 +29,14 @@ public class DomainDeleteSuperuserExtension extends SuperuserExtension {
|
||||
@XmlElement(name = "pendingDeleteDays")
|
||||
int pendingDeleteDays;
|
||||
|
||||
public static DomainDeleteSuperuserExtension create(
|
||||
int redemptionGracePeriodDays, int pendingDeleteDays) {
|
||||
DomainDeleteSuperuserExtension instance = new DomainDeleteSuperuserExtension();
|
||||
instance.redemptionGracePeriodDays = redemptionGracePeriodDays;
|
||||
instance.pendingDeleteDays = pendingDeleteDays;
|
||||
return instance;
|
||||
}
|
||||
|
||||
public int getRedemptionGracePeriodDays() {
|
||||
return redemptionGracePeriodDays;
|
||||
}
|
||||
|
||||
@@ -14,22 +14,28 @@
|
||||
|
||||
package google.registry.model.domain.superuser;
|
||||
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** A superuser extension that may be present on domain update commands. */
|
||||
@XmlRootElement(name = "domainUpdate")
|
||||
@XmlType(propOrder = "autorenews")
|
||||
public class DomainUpdateSuperuserExtension extends SuperuserExtension {
|
||||
|
||||
@XmlElement(name = "autorenews")
|
||||
@Nullable
|
||||
String autorenews;
|
||||
Boolean autorenews;
|
||||
|
||||
public static DomainUpdateSuperuserExtension create(@Nullable Boolean autorenews) {
|
||||
DomainUpdateSuperuserExtension instance = new DomainUpdateSuperuserExtension();
|
||||
instance.autorenews = autorenews;
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Optional<Boolean> getAutorenews() {
|
||||
return Optional.ofNullable(isNullOrEmpty(autorenews) ? null : Boolean.valueOf(autorenews));
|
||||
return Optional.ofNullable(autorenews);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,12 @@ public class AllocationTokenExtension extends ImmutableObject implements Command
|
||||
@XmlJavaTypeAdapter(TrimWhitespaceAdapter.class)
|
||||
String allocationToken;
|
||||
|
||||
public static AllocationTokenExtension create(String allocationToken) {
|
||||
AllocationTokenExtension instance = new AllocationTokenExtension();
|
||||
instance.allocationToken = allocationToken;
|
||||
return instance;
|
||||
}
|
||||
|
||||
public String getAllocationToken() {
|
||||
return allocationToken;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ import java.util.stream.Stream;
|
||||
* also matches the "addrType" type from <a
|
||||
* href="http://tools.ietf.org/html/draft-lozano-tmch-smd">Mark and Signed Mark Objects Mapping</a>.
|
||||
*
|
||||
* @see google.registry.model.contact.ContactAddress
|
||||
* @see google.registry.model.mark.MarkAddress
|
||||
* @see google.registry.model.registrar.RegistrarAddress
|
||||
*/
|
||||
|
||||
@@ -40,7 +40,6 @@ public class EppXmlTransformer {
|
||||
ImmutableList.of(
|
||||
"eppcom.xsd",
|
||||
"epp.xsd",
|
||||
"contact.xsd",
|
||||
"host.xsd",
|
||||
"domain.xsd",
|
||||
"rgp.xsd",
|
||||
|
||||
@@ -44,7 +44,6 @@ import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
*
|
||||
* </blockquote>
|
||||
*
|
||||
* @see google.registry.model.contact.ContactPhoneNumber
|
||||
* @see google.registry.model.mark.MarkPhoneNumber
|
||||
*/
|
||||
@XmlTransient
|
||||
|
||||
@@ -52,12 +52,6 @@ public class ProtocolDefinition {
|
||||
public static final ImmutableSet<String> SUPPORTED_OBJECT_SERVICES =
|
||||
ImmutableSet.of("urn:ietf:params:xml:ns:host-1.0", "urn:ietf:params:xml:ns:domain-1.0");
|
||||
|
||||
public static final ImmutableSet<String> SUPPORTED_OBJECT_SERVICES_WITH_CONTACT =
|
||||
new ImmutableSet.Builder<String>()
|
||||
.addAll(SUPPORTED_OBJECT_SERVICES)
|
||||
.add("urn:ietf:params:xml:ns:contact-1.0")
|
||||
.build();
|
||||
|
||||
/** Enum representing which environments should have which service extensions enabled. */
|
||||
private enum ServiceExtensionVisibility {
|
||||
ALL,
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
// Copyright 2026 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.eppinput;
|
||||
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName.CREATE;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.domain.fee.FeeExtensionCommandDescriptor;
|
||||
import google.registry.model.domain.fee06.FeeCheckCommandExtensionItemV06;
|
||||
import google.registry.model.domain.fee06.FeeCheckCommandExtensionV06;
|
||||
import google.registry.model.domain.fee06.FeeCreateCommandExtensionV06;
|
||||
import google.registry.model.domain.fee12.FeeCreateCommandExtensionV12;
|
||||
import google.registry.model.domain.launch.LaunchCheckExtension;
|
||||
import google.registry.model.domain.launch.LaunchCheckExtension.CheckType;
|
||||
import google.registry.model.domain.launch.LaunchPhase;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.domain.secdns.DomainDsData;
|
||||
import google.registry.model.domain.secdns.SecDnsCreateExtension;
|
||||
import google.registry.model.domain.secdns.SecDnsUpdateExtension;
|
||||
import google.registry.model.domain.secdns.SecDnsUpdateExtension.Add;
|
||||
import google.registry.model.domain.secdns.SecDnsUpdateExtension.Remove;
|
||||
import google.registry.model.domain.superuser.DomainDeleteSuperuserExtension;
|
||||
import google.registry.model.domain.superuser.DomainUpdateSuperuserExtension;
|
||||
import google.registry.model.domain.token.AllocationTokenExtension;
|
||||
import java.math.BigDecimal;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.money.Money;
|
||||
|
||||
/** Static helpers for creating common EPP extensions. */
|
||||
public class EppExtensions {
|
||||
|
||||
/**
|
||||
* Returns a metadata extension with the specified reason and flags.
|
||||
*
|
||||
* @param reason the reason for the change, recorded in history entries
|
||||
* @param requestedByRegistrar whether the change was requested by a registrar
|
||||
* @param isAnchorTenant whether the domain is an anchor tenant
|
||||
*/
|
||||
@Nullable
|
||||
public static MetadataExtension metadata(
|
||||
@Nullable String reason,
|
||||
@Nullable Boolean requestedByRegistrar,
|
||||
@Nullable Boolean isAnchorTenant) {
|
||||
if (isNullOrEmpty(reason) && requestedByRegistrar == null && isAnchorTenant == null) {
|
||||
return null;
|
||||
}
|
||||
return new MetadataExtension.Builder()
|
||||
.setReason(reason)
|
||||
.setRequestedByRegistrar(requestedByRegistrar)
|
||||
.setAnchorTenant(isAnchorTenant)
|
||||
.build();
|
||||
}
|
||||
|
||||
/** Returns a metadata extension for standard tool commands. */
|
||||
@Nullable
|
||||
public static MetadataExtension toolMetadata(
|
||||
@Nullable String reason, @Nullable Boolean requestedByRegistrar) {
|
||||
return metadata(reason, requestedByRegistrar, null);
|
||||
}
|
||||
|
||||
/** Returns an allocation token extension for the specified token string. */
|
||||
@Nullable
|
||||
public static AllocationTokenExtension allocationToken(@Nullable String token) {
|
||||
return isNullOrEmpty(token) ? null : AllocationTokenExtension.create(token);
|
||||
}
|
||||
|
||||
/** Returns a domain update superuser extension with the specified autorenew flag. */
|
||||
@Nullable
|
||||
public static DomainUpdateSuperuserExtension updateSuperuser(@Nullable Boolean autorenews) {
|
||||
return autorenews == null ? null : DomainUpdateSuperuserExtension.create(autorenews);
|
||||
}
|
||||
|
||||
/** Returns a domain delete superuser extension for immediate deletion if requested. */
|
||||
@Nullable
|
||||
public static DomainDeleteSuperuserExtension deleteSuperuser(boolean immediately) {
|
||||
return immediately ? DomainDeleteSuperuserExtension.create(0, 0) : null;
|
||||
}
|
||||
|
||||
/** Returns a fee create extension (V12) for a single fee. */
|
||||
@Nullable
|
||||
public static FeeCreateCommandExtensionV12 feeCreate(@Nullable Money cost) {
|
||||
return cost == null ? null : feeCreate(cost.getCurrencyUnit(), cost.getAmount());
|
||||
}
|
||||
|
||||
/** Returns a fee create extension (V12) for a single fee with a simple currency and cost. */
|
||||
@Nullable
|
||||
public static FeeCreateCommandExtensionV12 feeCreate(
|
||||
@Nullable CurrencyUnit currency, @Nullable BigDecimal cost) {
|
||||
if (currency == null || cost == null) {
|
||||
return null;
|
||||
}
|
||||
return new FeeCreateCommandExtensionV12.Builder()
|
||||
.setCurrency(currency)
|
||||
.setFees(ImmutableList.of(new Fee.Builder().setCost(cost).build()))
|
||||
.build();
|
||||
}
|
||||
|
||||
/** Returns a fee create extension (V06) for a single fee. */
|
||||
@Nullable
|
||||
public static FeeCreateCommandExtensionV06 feeCreateV06(@Nullable Money cost) {
|
||||
if (cost == null) {
|
||||
return null;
|
||||
}
|
||||
return new FeeCreateCommandExtensionV06.Builder()
|
||||
.setCurrency(cost.getCurrencyUnit())
|
||||
.setFees(ImmutableList.of(new Fee.Builder().setCost(cost.getAmount()).build()))
|
||||
.build();
|
||||
}
|
||||
|
||||
/** Returns a secDNS create extension with the specified DS records. */
|
||||
@Nullable
|
||||
public static SecDnsCreateExtension secDnsCreate(ImmutableSet<DomainDsData> dsData) {
|
||||
if (dsData.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return new SecDnsCreateExtension.Builder().setDsData(dsData).build();
|
||||
}
|
||||
|
||||
/** Returns a secDNS update extension to replace or modify DS records. */
|
||||
@Nullable
|
||||
public static SecDnsUpdateExtension secDnsUpdate(
|
||||
ImmutableSet<DomainDsData> add, ImmutableSet<DomainDsData> remove, boolean removeAll) {
|
||||
if (add.isEmpty() && remove.isEmpty() && !removeAll) {
|
||||
return null;
|
||||
}
|
||||
SecDnsUpdateExtension.Builder builder = new SecDnsUpdateExtension.Builder();
|
||||
if (removeAll) {
|
||||
builder.setRemove(new Remove.Builder().setAll(true).build());
|
||||
} else if (!remove.isEmpty()) {
|
||||
builder.setRemove(new Remove.Builder().setDsData(remove).build());
|
||||
}
|
||||
if (!add.isEmpty()) {
|
||||
builder.setAdd(new Add.Builder().setDsData(add).build());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/** Returns a fee check extension for domain creations (V06). */
|
||||
public static FeeCheckCommandExtensionV06 feeCheckCreateV06(ImmutableList<String> domainNames) {
|
||||
return feeCheckCreateV06(domainNames, 1);
|
||||
}
|
||||
|
||||
/** Returns a fee check extension for domain creations (V06) with a specific period. */
|
||||
public static FeeCheckCommandExtensionV06 feeCheckCreateV06(
|
||||
ImmutableList<String> domainNames, int years) {
|
||||
FeeCheckCommandExtensionV06 feeCheck = new FeeCheckCommandExtensionV06();
|
||||
ImmutableList.Builder<FeeCheckCommandExtensionItemV06> items = new ImmutableList.Builder<>();
|
||||
for (String domainName : domainNames) {
|
||||
items.add(
|
||||
FeeCheckCommandExtensionItemV06.create(
|
||||
domainName,
|
||||
null,
|
||||
FeeExtensionCommandDescriptor.create(CREATE, null, null),
|
||||
Period.create(years, Period.Unit.YEARS)));
|
||||
}
|
||||
feeCheck.setItems(items.build());
|
||||
return feeCheck;
|
||||
}
|
||||
|
||||
/** Returns a launch check extension for claims. */
|
||||
public static LaunchCheckExtension launchCheckClaims() {
|
||||
return LaunchCheckExtension.create(CheckType.CLAIMS, LaunchPhase.CLAIMS);
|
||||
}
|
||||
}
|
||||
@@ -14,14 +14,15 @@
|
||||
|
||||
package google.registry.model.eppinput;
|
||||
|
||||
import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
||||
import static google.registry.util.CollectionUtils.nullSafeImmutableCopy;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.contact.ContactCommand;
|
||||
import google.registry.model.domain.DomainCommand;
|
||||
import google.registry.model.domain.bulktoken.BulkTokenExtension;
|
||||
import google.registry.model.domain.fee06.FeeCheckCommandExtensionV06;
|
||||
@@ -61,6 +62,8 @@ import google.registry.model.domain.token.AllocationTokenExtension;
|
||||
import google.registry.model.eppinput.ResourceCommand.ResourceCheck;
|
||||
import google.registry.model.eppinput.ResourceCommand.SingleResourceCommand;
|
||||
import google.registry.model.host.HostCommand;
|
||||
import jakarta.xml.bind.annotation.XmlAccessType;
|
||||
import jakarta.xml.bind.annotation.XmlAccessorType;
|
||||
import jakarta.xml.bind.annotation.XmlAttribute;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlElementRef;
|
||||
@@ -70,21 +73,26 @@ import jakarta.xml.bind.annotation.XmlElements;
|
||||
import jakarta.xml.bind.annotation.XmlEnumValue;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlSchema;
|
||||
import jakarta.xml.bind.annotation.XmlTransient;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import jakarta.xml.bind.annotation.adapters.XmlAdapter;
|
||||
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** This class represents the root EPP XML element for input. */
|
||||
@XmlRootElement(name = "epp")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class EppInput extends ImmutableObject {
|
||||
|
||||
@XmlElements({
|
||||
@XmlElement(name = "command", type = CommandWrapper.class),
|
||||
@XmlElement(name = "hello", type = Hello.class) })
|
||||
@XmlElement(name = "command", type = CommandWrapper.class),
|
||||
@XmlElement(name = "hello", type = Hello.class)
|
||||
})
|
||||
CommandWrapper commandWrapper;
|
||||
|
||||
public CommandWrapper getCommandWrapper() {
|
||||
@@ -108,11 +116,11 @@ public class EppInput extends ImmutableObject {
|
||||
public Optional<String> getResourceType() {
|
||||
ResourceCommand resourceCommand = getResourceCommand();
|
||||
if (resourceCommand != null) {
|
||||
XmlSchema xmlSchemaAnnotation =
|
||||
resourceCommand.getClass().getPackage().getAnnotation(XmlSchema.class);
|
||||
if (xmlSchemaAnnotation != null && xmlSchemaAnnotation.xmlns().length > 0) {
|
||||
return Optional.of(xmlSchemaAnnotation.xmlns()[0].prefix());
|
||||
}
|
||||
XmlSchema xmlSchemaAnnotation =
|
||||
resourceCommand.getClass().getPackage().getAnnotation(XmlSchema.class);
|
||||
if (xmlSchemaAnnotation != null && xmlSchemaAnnotation.xmlns().length > 0) {
|
||||
return Optional.of(xmlSchemaAnnotation.xmlns()[0].prefix());
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
@@ -124,6 +132,9 @@ public class EppInput extends ImmutableObject {
|
||||
|
||||
@Nullable
|
||||
private ResourceCommand getResourceCommand() {
|
||||
if (commandWrapper == null) {
|
||||
return null;
|
||||
}
|
||||
InnerCommand innerCommand = commandWrapper.getCommand();
|
||||
return innerCommand instanceof ResourceCommandWrapper resourceCommandWrapper
|
||||
? resourceCommandWrapper.getResourceCommand()
|
||||
@@ -137,7 +148,7 @@ public class EppInput extends ImmutableObject {
|
||||
public Optional<String> getSingleTargetId() {
|
||||
ResourceCommand resourceCommand = getResourceCommand();
|
||||
return resourceCommand instanceof SingleResourceCommand singleResourceCommand
|
||||
? Optional.of(singleResourceCommand.getTargetId())
|
||||
? Optional.ofNullable(singleResourceCommand.getTargetId())
|
||||
: Optional.empty();
|
||||
}
|
||||
|
||||
@@ -148,7 +159,8 @@ public class EppInput extends ImmutableObject {
|
||||
public ImmutableList<String> getTargetIds() {
|
||||
ResourceCommand resourceCommand = getResourceCommand();
|
||||
if (resourceCommand instanceof SingleResourceCommand singleResourceCommand) {
|
||||
return ImmutableList.of(singleResourceCommand.getTargetId());
|
||||
String targetId = singleResourceCommand.getTargetId();
|
||||
return targetId == null ? ImmutableList.of() : ImmutableList.of(targetId);
|
||||
} else if (resourceCommand instanceof ResourceCheck resourceCheck) {
|
||||
return resourceCheck.getTargetIds();
|
||||
} else {
|
||||
@@ -158,24 +170,54 @@ public class EppInput extends ImmutableObject {
|
||||
|
||||
/** Get the extension based on type, or null. If there are multiple, it chooses the first. */
|
||||
public <E extends CommandExtension> Optional<E> getSingleExtension(Class<E> clazz) {
|
||||
return getCommandWrapper().getExtensions().stream()
|
||||
if (commandWrapper == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return commandWrapper.getExtensions().stream()
|
||||
.filter(clazz::isInstance)
|
||||
.map(clazz::cast)
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Static factory method to create an {@link EppInput} from an {@link InnerCommand} and
|
||||
* extensions.
|
||||
*/
|
||||
public static EppInput create(InnerCommand command, CommandExtension... extensions) {
|
||||
EppInput instance = new EppInput();
|
||||
instance.commandWrapper = new CommandWrapper();
|
||||
instance.commandWrapper.command = command;
|
||||
ImmutableList<CommandExtension> validExtensions =
|
||||
Arrays.stream(extensions).filter(Objects::nonNull).collect(ImmutableList.toImmutableList());
|
||||
if (!validExtensions.isEmpty()) {
|
||||
instance.commandWrapper.extension = validExtensions;
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public EppInput withClTrid(String clTrid) {
|
||||
this.commandWrapper.clTrid = clTrid;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builder for {@link EppInput}. */
|
||||
public static class Builder extends Buildable.Builder<EppInput> {
|
||||
public Builder setCommandWrapper(CommandWrapper commandWrapper) {
|
||||
getInstance().commandWrapper = commandWrapper;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/** A tag that goes inside an EPP {@literal <command>}. */
|
||||
public static class InnerCommand extends ImmutableObject {}
|
||||
@XmlTransient
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public abstract static class InnerCommand extends ImmutableObject {}
|
||||
|
||||
/** A command that has an extension inside of it. */
|
||||
public static class ResourceCommandWrapper extends InnerCommand {
|
||||
@XmlTransient
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public abstract static class ResourceCommandWrapper extends InnerCommand {
|
||||
@XmlElementRefs({
|
||||
@XmlElementRef(type = ContactCommand.Check.class),
|
||||
@XmlElementRef(type = ContactCommand.Create.class),
|
||||
@XmlElementRef(type = ContactCommand.Delete.class),
|
||||
@XmlElementRef(type = ContactCommand.Info.class),
|
||||
@XmlElementRef(type = ContactCommand.Transfer.class),
|
||||
@XmlElementRef(type = ContactCommand.Update.class),
|
||||
@XmlElementRef(type = DomainCommand.Check.class),
|
||||
@XmlElementRef(type = DomainCommand.Create.class),
|
||||
@XmlElementRef(type = DomainCommand.Delete.class),
|
||||
@@ -196,21 +238,65 @@ public class EppInput extends ImmutableObject {
|
||||
}
|
||||
|
||||
/** Epp envelope wrapper for check on some objects. */
|
||||
public static class Check extends ResourceCommandWrapper {}
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class Check extends ResourceCommandWrapper {
|
||||
public static Check create(ResourceCommand resourceCommand) {
|
||||
Check instance = new Check();
|
||||
instance.resourceCommand = resourceCommand;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/** Epp envelope wrapper for create of some object. */
|
||||
public static class Create extends ResourceCommandWrapper {}
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class Create extends ResourceCommandWrapper {
|
||||
public static Create create(ResourceCommand resourceCommand) {
|
||||
Create instance = new Create();
|
||||
instance.resourceCommand = resourceCommand;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/** Builder for {@link Create}. */
|
||||
public static class Builder extends Buildable.Builder<Create> {
|
||||
public Builder setResourceCommand(ResourceCommand resourceCommand) {
|
||||
getInstance().resourceCommand = resourceCommand;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Epp envelope wrapper for delete of some object. */
|
||||
public static class Delete extends ResourceCommandWrapper {}
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class Delete extends ResourceCommandWrapper {
|
||||
public static Delete create(ResourceCommand resourceCommand) {
|
||||
Delete instance = new Delete();
|
||||
instance.resourceCommand = resourceCommand;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/** Epp envelope wrapper for info on some object. */
|
||||
public static class Info extends ResourceCommandWrapper {}
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class Info extends ResourceCommandWrapper {
|
||||
public static Info create(ResourceCommand resourceCommand) {
|
||||
Info instance = new Info();
|
||||
instance.resourceCommand = resourceCommand;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/** Epp envelope wrapper for renewing some object. */
|
||||
public static class Renew extends ResourceCommandWrapper {}
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class Renew extends ResourceCommandWrapper {
|
||||
public static Renew create(ResourceCommand resourceCommand) {
|
||||
Renew instance = new Renew();
|
||||
instance.resourceCommand = resourceCommand;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/** Epp envelope wrapper for transferring some object. */
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class Transfer extends ResourceCommandWrapper {
|
||||
|
||||
/** Enum of the possible values for the "op" attribute in transfer flows. */
|
||||
@@ -237,12 +323,35 @@ public class EppInput extends ImmutableObject {
|
||||
public TransferOp getTransferOp() {
|
||||
return transferOp;
|
||||
}
|
||||
|
||||
public static Transfer create(TransferOp transferOp, ResourceCommand resourceCommand) {
|
||||
Transfer instance = new Transfer();
|
||||
instance.transferOp = transferOp;
|
||||
instance.resourceCommand = resourceCommand;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/** Epp envelope wrapper for update of some object. */
|
||||
public static class Update extends ResourceCommandWrapper {}
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class Update extends ResourceCommandWrapper {
|
||||
public static Update create(ResourceCommand resourceCommand) {
|
||||
Update instance = new Update();
|
||||
instance.resourceCommand = resourceCommand;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/** Builder for {@link Update}. */
|
||||
public static class Builder extends Buildable.Builder<Update> {
|
||||
public Builder setResourceCommand(ResourceCommand resourceCommand) {
|
||||
getInstance().resourceCommand = resourceCommand;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Poll command. */
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class Poll extends InnerCommand {
|
||||
|
||||
/** Enum of the possible values for the "op" attribute in poll commands. */
|
||||
@@ -260,19 +369,28 @@ public class EppInput extends ImmutableObject {
|
||||
@XmlAttribute
|
||||
PollOp op;
|
||||
|
||||
@XmlAttribute
|
||||
String msgID;
|
||||
@XmlAttribute(name = "msgID")
|
||||
String msgId;
|
||||
|
||||
public PollOp getPollOp() {
|
||||
return op;
|
||||
}
|
||||
|
||||
public String getMessageId() {
|
||||
return msgID;
|
||||
return msgId;
|
||||
}
|
||||
|
||||
public static Poll create(PollOp op, @Nullable String msgId) {
|
||||
Poll instance = new Poll();
|
||||
instance.op = op;
|
||||
instance.msgId = msgId;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/** Login command. */
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = {"clientId", "password", "newPassword", "options", "services"})
|
||||
public static class Login extends InnerCommand {
|
||||
@XmlElement(name = "clID")
|
||||
String clientId;
|
||||
@@ -310,10 +428,12 @@ public class EppInput extends ImmutableObject {
|
||||
}
|
||||
|
||||
/** Logout command. */
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class Logout extends InnerCommand {}
|
||||
|
||||
/** The "command" element that holds an actual command inside of it. */
|
||||
@XmlType(propOrder = {"command", "extension", "clTRID"})
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = {"command", "extension", "clTrid"})
|
||||
public static class CommandWrapper extends ImmutableObject {
|
||||
@XmlElements({
|
||||
@XmlElement(name = "check", type = Check.class),
|
||||
@@ -383,7 +503,9 @@ public class EppInput extends ImmutableObject {
|
||||
@XmlElementWrapper
|
||||
List<CommandExtension> extension;
|
||||
|
||||
@Nullable String clTRID;
|
||||
@XmlElement(name = "clTRID")
|
||||
@Nullable
|
||||
String clTrid;
|
||||
|
||||
/**
|
||||
* Returns the client transaction ID.
|
||||
@@ -391,7 +513,7 @@ public class EppInput extends ImmutableObject {
|
||||
* <p>This is optional (i.e. it may not be specified) per RFC 5730.
|
||||
*/
|
||||
public Optional<String> getClTrid() {
|
||||
return Optional.ofNullable(clTRID);
|
||||
return Optional.ofNullable(clTrid);
|
||||
}
|
||||
|
||||
public InnerCommand getCommand() {
|
||||
@@ -401,12 +523,34 @@ public class EppInput extends ImmutableObject {
|
||||
public ImmutableList<CommandExtension> getExtensions() {
|
||||
return nullToEmptyImmutableCopy(extension);
|
||||
}
|
||||
|
||||
/** Builder for {@link CommandWrapper}. */
|
||||
public static class Builder extends Buildable.Builder<CommandWrapper> {
|
||||
|
||||
public Builder setCommand(InnerCommand command) {
|
||||
getInstance().command = command;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setExtensions(ImmutableList<CommandExtension> extension) {
|
||||
getInstance().extension = isNullOrEmpty(extension) ? null : extension;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setClTrid(String clTrid) {
|
||||
getInstance().clTrid = clTrid;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Empty type to represent the empty "hello" command. */
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class Hello extends CommandWrapper {}
|
||||
|
||||
/** An options object inside of {@link Login}. */
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = {"version", "language"})
|
||||
public static class Options extends ImmutableObject {
|
||||
@XmlJavaTypeAdapter(VersionAdapter.class)
|
||||
String version;
|
||||
@@ -420,6 +564,8 @@ public class EppInput extends ImmutableObject {
|
||||
}
|
||||
|
||||
/** A services object inside of {@link Login}. */
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = {"objectServices", "serviceExtensions"})
|
||||
public static class Services extends ImmutableObject {
|
||||
@XmlElement(name = "objURI")
|
||||
Set<String> objectServices;
|
||||
@@ -438,15 +584,15 @@ public class EppInput extends ImmutableObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* RFC 5730 says we should check the version and return special error code 2100 if it isn't
|
||||
* what we support, but it also specifies a schema that only allows 1.0 in the version field, so
|
||||
* any other version doesn't validate. As a result, if we didn't do this here it would throw a
|
||||
* {@code SyntaxErrorException} when it failed to validate.
|
||||
* RFC 5730 says we should check the version and return special error code 2100 if it isn't what
|
||||
* we support, but it also specifies a schema that only allows 1.0 in the version field, so any
|
||||
* other version doesn't validate. As a result, if we didn't do this here it would throw a {@code
|
||||
* SyntaxErrorException} when it failed to validate.
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc5730#page-41">
|
||||
* RFC 5730 - EPP - Command error responses</a>
|
||||
* @see <a href="http://tools.ietf.org/html/rfc5730#page-41">RFC 5730 - EPP - Command error
|
||||
* responses</a>
|
||||
*/
|
||||
public static class VersionAdapter extends XmlAdapter<String, String> {
|
||||
public static class VersionAdapter extends XmlAdapter<String, String> {
|
||||
@Override
|
||||
public String unmarshal(String version) throws Exception {
|
||||
if (!"1.0".equals(version)) {
|
||||
@@ -456,8 +602,8 @@ public class EppInput extends ImmutableObject {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String marshal(String ignored) {
|
||||
throw new UnsupportedOperationException();
|
||||
public String marshal(String version) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
package google.registry.model.eppinput;
|
||||
|
||||
import static google.registry.util.CollectionUtils.nullSafeImmutableCopy;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -24,41 +23,50 @@ import google.registry.model.EppResource;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppinput.ResourceCommand.ResourceUpdate.AddRemove;
|
||||
import google.registry.util.TypeUtils.TypeInstantiator;
|
||||
import jakarta.xml.bind.annotation.XmlAccessType;
|
||||
import jakarta.xml.bind.annotation.XmlAccessorType;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlElements;
|
||||
import jakarta.xml.bind.annotation.XmlTransient;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/** Commands for EPP resources. */
|
||||
public interface ResourceCommand {
|
||||
|
||||
/**
|
||||
* A command for a single {@link EppResource}.
|
||||
*
|
||||
* <p>In general commands should extend {@link AbstractSingleResourceCommand} instead of
|
||||
* implementing this directly, but "Create" commands can't do that since they need to inherit from
|
||||
* a base class that gives them all of the resource's fields. The domain "Info" command also can't
|
||||
* do that since it's "name" field is overloaded with a "hosts" attribute.
|
||||
*/
|
||||
/** Interface for EPP commands that operate on a single resource. */
|
||||
interface SingleResourceCommand extends ResourceCommand {
|
||||
@Override
|
||||
String getTargetId();
|
||||
|
||||
@Override
|
||||
AuthInfo getAuthInfo();
|
||||
}
|
||||
|
||||
/** Returns the target ID for single-resource commands, or null otherwise. */
|
||||
default String getTargetId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Returns the auth info for single-resource commands, or null otherwise. */
|
||||
default AuthInfo getAuthInfo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Abstract implementation of {@link ResourceCommand}. */
|
||||
@XmlTransient
|
||||
abstract class AbstractSingleResourceCommand extends ImmutableObject
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public abstract class AbstractSingleResourceCommand extends ImmutableObject
|
||||
implements SingleResourceCommand {
|
||||
@XmlElements({
|
||||
@XmlElement(name = "id"),
|
||||
@XmlElement(name = "name") })
|
||||
String targetId;
|
||||
|
||||
@XmlTransient public String targetId;
|
||||
|
||||
public void setTargetId(String targetId) {
|
||||
this.targetId = targetId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@XmlTransient
|
||||
public String getTargetId() {
|
||||
return targetId;
|
||||
}
|
||||
@@ -71,11 +79,14 @@ public interface ResourceCommand {
|
||||
|
||||
/** A check command for an {@link EppResource}. */
|
||||
@XmlTransient
|
||||
class ResourceCheck extends ImmutableObject implements ResourceCommand {
|
||||
@XmlElements({
|
||||
@XmlElement(name = "id"),
|
||||
@XmlElement(name = "name") })
|
||||
List<String> targetUniqueIds;
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class ResourceCheck extends ImmutableObject implements ResourceCommand {
|
||||
@XmlElements({@XmlElement(name = "id"), @XmlElement(name = "name")})
|
||||
public List<String> targetUniqueIds;
|
||||
|
||||
public void setTargetIds(ImmutableList<String> targetUniqueIds) {
|
||||
this.targetUniqueIds = targetUniqueIds;
|
||||
}
|
||||
|
||||
public ImmutableList<String> getTargetIds() {
|
||||
return nullSafeImmutableCopy(targetUniqueIds);
|
||||
@@ -83,7 +94,7 @@ public interface ResourceCommand {
|
||||
}
|
||||
|
||||
/** A create command, or the inner change (as opposed to add or remove) part of an update. */
|
||||
interface ResourceCreateOrChange<B extends Buildable.Builder<?>> {}
|
||||
public interface ResourceCreateOrChange<B extends Buildable.Builder<?>> {}
|
||||
|
||||
/**
|
||||
* An update command for an {@link EppResource}.
|
||||
@@ -92,21 +103,19 @@ public interface ResourceCommand {
|
||||
* @param <C> the change type
|
||||
*/
|
||||
@XmlTransient
|
||||
abstract class ResourceUpdate<
|
||||
A extends AddRemove,
|
||||
public abstract class ResourceUpdate<
|
||||
A extends ResourceUpdate.AddRemove,
|
||||
B extends EppResource.Builder<?, ?>,
|
||||
C extends ResourceCreateOrChange<B>>
|
||||
extends AbstractSingleResourceCommand {
|
||||
|
||||
/** Part of an update command that specifies set values to add or remove. */
|
||||
@XmlTransient
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public abstract static class AddRemove extends ImmutableObject {
|
||||
@XmlElement(name = "status")
|
||||
Set<StatusValue> statusValues;
|
||||
public abstract void setStatusValues(ImmutableSet<StatusValue> statusValues);
|
||||
|
||||
public ImmutableSet<StatusValue> getStatusValues() {
|
||||
return nullToEmptyImmutableCopy(statusValues);
|
||||
}
|
||||
public abstract ImmutableSet<StatusValue> getStatusValues();
|
||||
}
|
||||
|
||||
protected abstract C getNullableInnerChange();
|
||||
|
||||
@@ -32,8 +32,6 @@ public abstract class CheckData extends ImmutableObject implements ResponseData
|
||||
|
||||
/** The check responses. We must explicitly list the namespaced versions of {@link Check}. */
|
||||
@XmlElements({
|
||||
@XmlElement(
|
||||
name = "cd", namespace = "urn:ietf:params:xml:ns:contact-1.0", type = ContactCheck.class),
|
||||
@XmlElement(
|
||||
name = "cd", namespace = "urn:ietf:params:xml:ns:domain-1.0", type = DomainCheck.class),
|
||||
@XmlElement(
|
||||
@@ -114,14 +112,6 @@ public abstract class CheckData extends ImmutableObject implements ResponseData
|
||||
}
|
||||
}
|
||||
|
||||
/** A version with contact namespacing. */
|
||||
@XmlType(namespace = "urn:ietf:params:xml:ns:contact-1.0")
|
||||
public static class ContactCheck extends Check {
|
||||
public static ContactCheck create(boolean avail, String id, String reason) {
|
||||
return init(new ContactCheck(), CheckID.create(avail, id), reason);
|
||||
}
|
||||
}
|
||||
|
||||
/** A version with domain namespacing. */
|
||||
@XmlType(namespace = "urn:ietf:params:xml:ns:domain-1.0")
|
||||
public static class DomainCheck extends Check {
|
||||
@@ -146,14 +136,6 @@ public abstract class CheckData extends ImmutableObject implements ResponseData
|
||||
}
|
||||
}
|
||||
|
||||
/** A version with contact namespacing. */
|
||||
@XmlRootElement(name = "chkData", namespace = "urn:ietf:params:xml:ns:contact-1.0")
|
||||
public static class ContactCheckData extends CheckData {
|
||||
public static ContactCheckData create(ImmutableList<ContactCheck> checks) {
|
||||
return init(new ContactCheckData(), checks);
|
||||
}
|
||||
}
|
||||
|
||||
/** A version with domain namespacing. */
|
||||
@XmlRootElement(name = "chkData", namespace = "urn:ietf:params:xml:ns:domain-1.0")
|
||||
public static class DomainCheckData extends CheckData {
|
||||
|
||||
@@ -28,21 +28,6 @@ public abstract class CreateData implements ResponseData {
|
||||
@XmlElement(name = "crDate")
|
||||
protected Instant creationDate;
|
||||
|
||||
/** An acknowledgment message indicating that a contact was created. */
|
||||
@XmlRootElement(name = "creData", namespace = "urn:ietf:params:xml:ns:contact-1.0")
|
||||
@XmlType(propOrder = {"id", "creationDate"}, namespace = "urn:ietf:params:xml:ns:contact-1.0")
|
||||
public static class ContactCreateData extends CreateData {
|
||||
|
||||
String id;
|
||||
|
||||
public static ContactCreateData create(String id, Instant creationDate) {
|
||||
ContactCreateData instance = new ContactCreateData();
|
||||
instance.id = id;
|
||||
instance.creationDate = creationDate;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/** An acknowledgment message indicating that a domain was created. */
|
||||
@XmlRootElement(name = "creData", namespace = "urn:ietf:params:xml:ns:domain-1.0")
|
||||
@XmlType(
|
||||
|
||||
@@ -20,7 +20,6 @@ import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.contact.ContactInfoData;
|
||||
import google.registry.model.domain.DomainInfoData;
|
||||
import google.registry.model.domain.DomainRenewData;
|
||||
import google.registry.model.domain.bulktoken.BulkTokenResponseExtension;
|
||||
@@ -53,19 +52,15 @@ import google.registry.model.domain.launch.LaunchCheckResponseExtension;
|
||||
import google.registry.model.domain.rgp.RgpInfoExtension;
|
||||
import google.registry.model.domain.secdns.SecDnsInfoExtension;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.eppoutput.CheckData.ContactCheckData;
|
||||
import google.registry.model.eppoutput.CheckData.DomainCheckData;
|
||||
import google.registry.model.eppoutput.CheckData.HostCheckData;
|
||||
import google.registry.model.eppoutput.CreateData.ContactCreateData;
|
||||
import google.registry.model.eppoutput.CreateData.DomainCreateData;
|
||||
import google.registry.model.eppoutput.CreateData.HostCreateData;
|
||||
import google.registry.model.eppoutput.EppOutput.ResponseOrGreeting;
|
||||
import google.registry.model.host.HostInfoData;
|
||||
import google.registry.model.poll.MessageQueueInfo;
|
||||
import google.registry.model.poll.PendingActionNotificationResponse.ContactPendingActionNotificationResponse;
|
||||
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
|
||||
import google.registry.model.poll.PendingActionNotificationResponse.HostPendingActionNotificationResponse;
|
||||
import google.registry.model.transfer.TransferResponse.ContactTransferResponse;
|
||||
import google.registry.model.transfer.TransferResponse.DomainTransferResponse;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlElementRef;
|
||||
@@ -107,11 +102,6 @@ public class EppResponse extends ImmutableObject implements ResponseOrGreeting {
|
||||
|
||||
/** Zero or more response "resData" results. */
|
||||
@XmlElementRefs({
|
||||
@XmlElementRef(type = ContactCheckData.class),
|
||||
@XmlElementRef(type = ContactCreateData.class),
|
||||
@XmlElementRef(type = ContactInfoData.class),
|
||||
@XmlElementRef(type = ContactPendingActionNotificationResponse.class),
|
||||
@XmlElementRef(type = ContactTransferResponse.class),
|
||||
@XmlElementRef(type = DomainCheckData.class),
|
||||
@XmlElementRef(type = DomainCreateData.class),
|
||||
@XmlElementRef(type = DomainInfoData.class),
|
||||
|
||||
@@ -14,14 +14,18 @@
|
||||
|
||||
package google.registry.model.host;
|
||||
|
||||
import static google.registry.util.CollectionUtils.nullSafeImmutableCopy;
|
||||
import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppinput.ResourceCommand.AbstractSingleResourceCommand;
|
||||
import google.registry.model.eppinput.ResourceCommand.ResourceCheck;
|
||||
import google.registry.model.eppinput.ResourceCommand.ResourceCreateOrChange;
|
||||
import google.registry.model.eppinput.ResourceCommand.ResourceUpdate;
|
||||
import jakarta.xml.bind.annotation.XmlAccessType;
|
||||
import jakarta.xml.bind.annotation.XmlAccessorType;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlTransient;
|
||||
@@ -32,39 +36,95 @@ import java.util.Set;
|
||||
/** A collection of {@link Host} commands. */
|
||||
public class HostCommand {
|
||||
|
||||
/** The fields on "chgType" from <a href="http://tools.ietf.org/html/rfc5732">RFC5732</a>. */
|
||||
/** The fields on "chgType" from <a href="https://tools.ietf.org/html/rfc5732">RFC5732</a>. */
|
||||
@XmlTransient
|
||||
abstract static class HostCreateOrChange extends AbstractSingleResourceCommand
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public abstract static class HostCreateOrChange extends AbstractSingleResourceCommand
|
||||
implements ResourceCreateOrChange<Host.Builder> {
|
||||
|
||||
@XmlElement(name = "name")
|
||||
String name;
|
||||
|
||||
@Override
|
||||
public String getTargetId() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetId(String targetId) {
|
||||
this.name = targetId;
|
||||
}
|
||||
|
||||
public String getHostName() {
|
||||
return getTargetId();
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A create command for a {@link Host}, mapping "createType" from <a
|
||||
* href="http://tools.ietf.org/html/rfc5732">RFC5732</a>.
|
||||
* href="https://tools.ietf.org/html/rfc5732">RFC5732</a>.
|
||||
*/
|
||||
@XmlType(propOrder = {"targetId", "inetAddresses"})
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = {"name", "inetAddresses"})
|
||||
@XmlRootElement
|
||||
public static class Create extends HostCreateOrChange
|
||||
implements ResourceCreateOrChange<Host.Builder> {
|
||||
public static class Create extends HostCreateOrChange {
|
||||
/** IP Addresses for this host. Can be null if this is an external host. */
|
||||
@XmlElement(name = "addr")
|
||||
Set<InetAddress> inetAddresses;
|
||||
|
||||
public ImmutableSet<InetAddress> getInetAddresses() {
|
||||
return nullSafeImmutableCopy(inetAddresses);
|
||||
return nullToEmptyImmutableCopy(inetAddresses);
|
||||
}
|
||||
|
||||
/** Builder for {@link Create}. */
|
||||
public static class Builder extends Buildable.Builder<Create> {
|
||||
public Builder setTargetId(String targetId) {
|
||||
getInstance().setTargetId(targetId);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setInetAddresses(ImmutableSet<InetAddress> inetAddresses) {
|
||||
getInstance().inetAddresses = inetAddresses;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** A delete command for a {@link Host}. */
|
||||
@XmlRootElement
|
||||
public static class Delete extends AbstractSingleResourceCommand {}
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class Delete extends AbstractSingleResourceCommand {
|
||||
@XmlElement(name = "name")
|
||||
String name;
|
||||
|
||||
@Override
|
||||
public String getTargetId() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetId(String targetId) {
|
||||
this.name = targetId;
|
||||
}
|
||||
}
|
||||
|
||||
/** An info request for a {@link Host}. */
|
||||
@XmlRootElement
|
||||
public static class Info extends AbstractSingleResourceCommand {}
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class Info extends AbstractSingleResourceCommand {
|
||||
@XmlElement(name = "name")
|
||||
String name;
|
||||
|
||||
@Override
|
||||
public String getTargetId() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetId(String targetId) {
|
||||
this.name = targetId;
|
||||
}
|
||||
}
|
||||
|
||||
/** A check request for {@link Host}. */
|
||||
@XmlRootElement
|
||||
@@ -72,17 +132,32 @@ public class HostCommand {
|
||||
|
||||
/** An update to a {@link Host}. */
|
||||
@XmlRootElement
|
||||
@XmlType(propOrder = {"targetId", "innerAdd", "innerRemove", "innerChange"})
|
||||
public static class Update extends ResourceUpdate<Update.AddRemove, Host.Builder, Update.Change> {
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = {"name", "innerAdd", "innerRemove", "innerChange"})
|
||||
public static class Update
|
||||
extends ResourceUpdate<Update.HostAddRemove, Host.Builder, Update.Change> {
|
||||
|
||||
@XmlElement(name = "name")
|
||||
String name;
|
||||
|
||||
@Override
|
||||
public String getTargetId() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetId(String targetId) {
|
||||
this.name = targetId;
|
||||
}
|
||||
|
||||
@XmlElement(name = "chg")
|
||||
protected Change innerChange;
|
||||
|
||||
@XmlElement(name = "add")
|
||||
protected AddRemove innerAdd;
|
||||
protected HostAddRemove innerAdd;
|
||||
|
||||
@XmlElement(name = "rem")
|
||||
protected AddRemove innerRemove;
|
||||
protected HostAddRemove innerRemove;
|
||||
|
||||
@Override
|
||||
protected Change getNullableInnerChange() {
|
||||
@@ -90,28 +165,55 @@ public class HostCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AddRemove getNullableInnerAdd() {
|
||||
protected HostAddRemove getNullableInnerAdd() {
|
||||
return innerAdd;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AddRemove getNullableInnerRemove() {
|
||||
protected HostAddRemove getNullableInnerRemove() {
|
||||
return innerRemove;
|
||||
}
|
||||
|
||||
/** The add/remove type on a host update command. */
|
||||
@XmlType(propOrder = { "inetAddresses", "statusValues" })
|
||||
public static class AddRemove extends ResourceUpdate.AddRemove {
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = {"inetAddresses", "statusValues"})
|
||||
public static class HostAddRemove extends ResourceUpdate.AddRemove {
|
||||
/** IP Addresses for this host. Can be null if this is an external host. */
|
||||
@XmlElement(name = "addr")
|
||||
Set<InetAddress> inetAddresses;
|
||||
|
||||
@XmlElement(name = "status")
|
||||
Set<StatusValue> statusValues;
|
||||
|
||||
@Override
|
||||
public void setStatusValues(ImmutableSet<StatusValue> statusValues) {
|
||||
this.statusValues = statusValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSet<StatusValue> getStatusValues() {
|
||||
return nullToEmptyImmutableCopy(statusValues);
|
||||
}
|
||||
|
||||
public ImmutableSet<InetAddress> getInetAddresses() {
|
||||
return nullToEmptyImmutableCopy(inetAddresses);
|
||||
}
|
||||
|
||||
/** Builder for {@link HostAddRemove}. */
|
||||
public static class Builder extends Buildable.Builder<HostAddRemove> {
|
||||
public Builder setInetAddresses(ImmutableSet<InetAddress> inetAddresses) {
|
||||
getInstance().inetAddresses = isNullOrEmpty(inetAddresses) ? null : inetAddresses;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setStatusValues(ImmutableSet<StatusValue> statusValues) {
|
||||
getInstance().statusValues = isNullOrEmpty(statusValues) ? null : statusValues;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The inner change type on a host update command. */
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class Change extends HostCreateOrChange {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,15 +39,13 @@ public class PendingActionNotificationResponse extends ImmutableObject
|
||||
/** The inner name type that contains a name and the result boolean. */
|
||||
@Embeddable
|
||||
static class NameOrId extends ImmutableObject implements UnsafeSerializable {
|
||||
@XmlValue
|
||||
String value;
|
||||
@XmlValue String value;
|
||||
|
||||
@XmlAttribute(name = "paResult")
|
||||
boolean actionResult;
|
||||
}
|
||||
|
||||
@XmlTransient
|
||||
NameOrId nameOrId;
|
||||
@XmlTransient NameOrId nameOrId;
|
||||
|
||||
@XmlElement(name = "paTRID")
|
||||
Trid trid;
|
||||
@@ -104,36 +102,11 @@ public class PendingActionNotificationResponse extends ImmutableObject
|
||||
}
|
||||
}
|
||||
|
||||
/** An adapter to output the XML in response to resolving a pending command on a contact. */
|
||||
@XmlRootElement(name = "panData", namespace = "urn:ietf:params:xml:ns:contact-1.0")
|
||||
@XmlType(
|
||||
propOrder = {"id", "trid", "processedDate"},
|
||||
namespace = "urn:ietf:params:xml:ns:contact-1.0")
|
||||
public static class ContactPendingActionNotificationResponse
|
||||
extends PendingActionNotificationResponse {
|
||||
|
||||
@XmlElement
|
||||
NameOrId getId() {
|
||||
return nameOrId;
|
||||
}
|
||||
|
||||
public static ContactPendingActionNotificationResponse create(
|
||||
String contactId, boolean actionResult, Trid trid, Instant processedDate) {
|
||||
return init(
|
||||
new ContactPendingActionNotificationResponse(),
|
||||
contactId,
|
||||
actionResult,
|
||||
trid,
|
||||
processedDate);
|
||||
}
|
||||
}
|
||||
|
||||
/** An adapter to output the XML in response to resolving a pending command on a host. */
|
||||
@XmlRootElement(name = "panData", namespace = "urn:ietf:params:xml:ns:domain-1.0")
|
||||
@XmlType(
|
||||
propOrder = {"name", "trid", "processedDate"},
|
||||
namespace = "urn:ietf:params:xml:ns:domain-1.0"
|
||||
)
|
||||
propOrder = {"name", "trid", "processedDate"},
|
||||
namespace = "urn:ietf:params:xml:ns:domain-1.0")
|
||||
public static class HostPendingActionNotificationResponse
|
||||
extends PendingActionNotificationResponse {
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
|
||||
DISABLED
|
||||
}
|
||||
|
||||
/** Regex for E.164 phone number format specified by {@code contact.xsd}. */
|
||||
/** Regex for E.164 phone number format. */
|
||||
private static final Pattern E164_PATTERN = Pattern.compile("\\+[0-9]{1,3}\\.[0-9]{1,14}");
|
||||
|
||||
/** Regex for telephone support passcode (5 digit string). */
|
||||
|
||||
@@ -43,17 +43,7 @@ public final class IcannReportingTypes {
|
||||
HOST_CREATE("srs-host-create"),
|
||||
HOST_DELETE("srs-host-delete"),
|
||||
HOST_INFO("srs-host-info"),
|
||||
HOST_UPDATE("srs-host-update"),
|
||||
CONTACT_CHECK("srs-cont-check"),
|
||||
CONTACT_CREATE("srs-cont-create"),
|
||||
CONTACT_DELETE("srs-cont-delete"),
|
||||
CONTACT_INFO("srs-cont-info"),
|
||||
CONTACT_TRANSFER_APPROVE("srs-cont-transfer-approve"),
|
||||
CONTACT_TRANSFER_CANCEL("srs-cont-transfer-cancel"),
|
||||
CONTACT_TRANSFER_QUERY("srs-cont-transfer-query"),
|
||||
CONTACT_TRANSFER_REJECT("srs-cont-transfer-reject"),
|
||||
CONTACT_TRANSFER_REQUEST("srs-cont-transfer-request"),
|
||||
CONTACT_UPDATE("srs-cont-update");
|
||||
HOST_UPDATE("srs-host-update");
|
||||
|
||||
/** Returns the actual field name from the specification. */
|
||||
private final String fieldName;
|
||||
|
||||
@@ -83,33 +83,4 @@ public class TransferResponse extends BaseTransferObject implements ResponseData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** An adapter to output the XML in response to a transfer command on a contact. */
|
||||
@XmlRootElement(name = "trnData", namespace = "urn:ietf:params:xml:ns:contact-1.0")
|
||||
@XmlType(propOrder = {
|
||||
"contactId",
|
||||
"transferStatus",
|
||||
"gainingClientId",
|
||||
"transferRequestTime",
|
||||
"losingClientId",
|
||||
"pendingTransferExpirationTime"},
|
||||
namespace = "urn:ietf:params:xml:ns:contact-1.0")
|
||||
public static class ContactTransferResponse extends TransferResponse {
|
||||
|
||||
@XmlElement(name = "id")
|
||||
String contactId;
|
||||
|
||||
public String getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
/** Builder for {@link ContactTransferResponse}. */
|
||||
public static class Builder
|
||||
extends BaseTransferObject.Builder<ContactTransferResponse, Builder> {
|
||||
public Builder setContactId(String contactId) {
|
||||
getInstance().contactId = contactId;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
// Copyright 2024 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.persistence.converter;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
|
||||
import google.registry.model.contact.Disclose.PostalInfoChoice;
|
||||
import google.registry.model.contact.PostalInfo;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/** Hibernate custom type for {@link List} of {@link PostalInfoChoice}. */
|
||||
public class PostalInfoChoiceListUserType
|
||||
extends StringCollectionUserType<PostalInfoChoice, List<PostalInfoChoice>> {
|
||||
|
||||
@Override
|
||||
String[] toJdbcObject(List<PostalInfoChoice> collection) {
|
||||
return collection.stream()
|
||||
.map(PostalInfoChoice::getType)
|
||||
.map(Enum::name)
|
||||
.toList()
|
||||
.toArray(new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
List<PostalInfoChoice> toEntity(String[] data) {
|
||||
return Stream.of(data)
|
||||
.map(PostalInfo.Type::valueOf)
|
||||
.map(PostalInfoChoice::create)
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Class<List<PostalInfoChoice>> returnedClass() {
|
||||
return (Class<List<PostalInfoChoice>>) ((Object) List.class);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.Registrar.State;
|
||||
import google.registry.model.registrar.RegistrarAddress;
|
||||
import google.registry.xjc.contact.XjcContactE164Type;
|
||||
import google.registry.xjc.eppcom.XjcEppcomE164Type;
|
||||
import google.registry.xjc.rderegistrar.XjcRdeRegistrar;
|
||||
import google.registry.xjc.rderegistrar.XjcRdeRegistrarAddrType;
|
||||
import google.registry.xjc.rderegistrar.XjcRdeRegistrarElement;
|
||||
@@ -103,7 +103,7 @@ final class RegistrarToXjcConverter {
|
||||
// telephone number.
|
||||
// XXX: Make Registrar use PhoneNumber.
|
||||
if (model.getPhoneNumber() != null) {
|
||||
XjcContactE164Type phone = new XjcContactE164Type();
|
||||
XjcEppcomE164Type phone = new XjcEppcomE164Type();
|
||||
phone.setValue(model.getPhoneNumber());
|
||||
bean.setVoice(phone);
|
||||
}
|
||||
@@ -111,7 +111,7 @@ final class RegistrarToXjcConverter {
|
||||
// o An OPTIONAL <fax> element that contains the registrar's facsimile
|
||||
// telephone number.
|
||||
if (model.getFaxNumber() != null) {
|
||||
XjcContactE164Type fax = new XjcContactE164Type();
|
||||
XjcEppcomE164Type fax = new XjcEppcomE164Type();
|
||||
fax.setValue(model.getFaxNumber());
|
||||
bean.setFax(fax);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import static jakarta.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
|
||||
|
||||
import com.google.api.services.dataflow.Dataflow;
|
||||
import com.google.api.services.dataflow.model.Job;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Maps;
|
||||
@@ -32,11 +31,10 @@ import com.google.common.collect.Multimaps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import com.google.template.soy.parseinfo.SoyTemplateInfo;
|
||||
import google.registry.beam.spec11.ThreatMatch;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.reporting.ReportingModule;
|
||||
import google.registry.reporting.spec11.soy.Spec11EmailSoyInfo;
|
||||
import google.registry.reporting.spec11.Spec11EmailUtils.Spec11EmailTemplate;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
@@ -45,14 +43,13 @@ import jakarta.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.json.JSONException;
|
||||
|
||||
/**
|
||||
* Retries until a {@code Dataflow} job with a given {@code jobId} completes, continuing the Spec11
|
||||
* pipeline accordingly.
|
||||
*
|
||||
* <p>This calls {@link Spec11EmailUtils#emailSpec11Reports(LocalDate, SoyTemplateInfo, String,
|
||||
* <p>This calls {@link Spec11EmailUtils#emailSpec11Reports(LocalDate, Spec11EmailTemplate, String,
|
||||
* ImmutableSet)} on success or {@link Spec11EmailUtils#sendAlertEmail(String, String)} on failure.
|
||||
*/
|
||||
@Action(
|
||||
@@ -134,7 +131,7 @@ public class PublishSpec11ReportAction implements Runnable {
|
||||
String.format("Spec11 %s job %s ended in status failure.", date, jobId));
|
||||
}
|
||||
default -> {
|
||||
logger.atInfo().log("Job in non-terminal state %s, retrying:", state);
|
||||
logger.atInfo().log("Job in non-terminal state %s, retrying.", state);
|
||||
response.setStatus(SC_SERVICE_UNAVAILABLE);
|
||||
}
|
||||
}
|
||||
@@ -153,8 +150,7 @@ public class PublishSpec11ReportAction implements Runnable {
|
||||
ImmutableSet<RegistrarThreatMatches> monthlyMatchesSet =
|
||||
spec11RegistrarThreatMatchesParser.getRegistrarThreatMatches(date);
|
||||
String subject = String.format("%s Monthly Threat Detector [%s]", registryName, date);
|
||||
emailUtils.emailSpec11Reports(
|
||||
date, Spec11EmailSoyInfo.MONTHLY_SPEC_11_EMAIL, subject, monthlyMatchesSet);
|
||||
emailUtils.emailSpec11Reports(date, Spec11EmailTemplate.MONTHLY, subject, monthlyMatchesSet);
|
||||
}
|
||||
|
||||
private void processDailyDiff(LocalDate previousDate) throws IOException, JSONException {
|
||||
@@ -165,7 +161,7 @@ public class PublishSpec11ReportAction implements Runnable {
|
||||
String dailySubject = String.format("%s Daily Threat Detector [%s]", registryName, date);
|
||||
emailUtils.emailSpec11Reports(
|
||||
date,
|
||||
Spec11EmailSoyInfo.DAILY_SPEC_11_EMAIL,
|
||||
Spec11EmailTemplate.DAILY,
|
||||
dailySubject,
|
||||
getNewMatches(previousMatches, currentMatches));
|
||||
}
|
||||
@@ -173,19 +169,20 @@ public class PublishSpec11ReportAction implements Runnable {
|
||||
private ImmutableSet<RegistrarThreatMatches> getNewMatches(
|
||||
ImmutableSet<RegistrarThreatMatches> previousMatchesSet,
|
||||
ImmutableSet<RegistrarThreatMatches> currentMatchesSet) {
|
||||
ImmutableMap<String, ImmutableSet<ThreatMatch>> previousMatchesByEmail =
|
||||
ImmutableMap<String, ImmutableSet<ThreatMatch>> previousMatchesByRegistrarId =
|
||||
groupByKeyAndFlatMap(previousMatchesSet);
|
||||
ImmutableMap<String, ImmutableSet<ThreatMatch>> currentMatchesByEmail =
|
||||
ImmutableMap<String, ImmutableSet<ThreatMatch>> currentMatchesByRegistrarId =
|
||||
groupByKeyAndFlatMap(currentMatchesSet);
|
||||
ImmutableSet.Builder<RegistrarThreatMatches> resultsBuilder = ImmutableSet.builder();
|
||||
for (String email : currentMatchesByEmail.keySet()) {
|
||||
for (String registrarId : currentMatchesByRegistrarId.keySet()) {
|
||||
// Only include matches in the result if they're non-empty
|
||||
Set<ThreatMatch> difference =
|
||||
Sets.difference(
|
||||
currentMatchesByEmail.get(email),
|
||||
previousMatchesByEmail.getOrDefault(email, ImmutableSet.of()));
|
||||
ImmutableSet<ThreatMatch> difference =
|
||||
ImmutableSet.copyOf(
|
||||
Sets.difference(
|
||||
currentMatchesByRegistrarId.get(registrarId),
|
||||
previousMatchesByRegistrarId.getOrDefault(registrarId, ImmutableSet.of())));
|
||||
if (!difference.isEmpty()) {
|
||||
resultsBuilder.add(RegistrarThreatMatches.create(email, ImmutableList.copyOf(difference)));
|
||||
resultsBuilder.add(RegistrarThreatMatches.create(registrarId, difference.asList()));
|
||||
}
|
||||
}
|
||||
return resultsBuilder.build();
|
||||
@@ -193,13 +190,13 @@ public class PublishSpec11ReportAction implements Runnable {
|
||||
|
||||
private ImmutableMap<String, ImmutableSet<ThreatMatch>> groupByKeyAndFlatMap(
|
||||
ImmutableSet<RegistrarThreatMatches> registrarThreatMatches) {
|
||||
// Group by email address then flat-map all of the ThreatMatch objects together
|
||||
// Group by registrarId then flat-map all of the ThreatMatch objects together
|
||||
return ImmutableMap.copyOf(
|
||||
Maps.transformValues(
|
||||
Multimaps.index(registrarThreatMatches, RegistrarThreatMatches::clientId).asMap(),
|
||||
Multimaps.index(registrarThreatMatches, RegistrarThreatMatches::registrarId).asMap(),
|
||||
registrarThreatMatchesCollection ->
|
||||
registrarThreatMatchesCollection.stream()
|
||||
.flatMap(matches -> matches.threatMatches().stream())
|
||||
.flatMap(rtm -> rtm.threatMatches().stream())
|
||||
.collect(toImmutableSet())));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,17 @@ package google.registry.reporting.spec11;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.beam.spec11.ThreatMatch;
|
||||
import java.util.List;
|
||||
|
||||
/** Value record representing the registrar and list-of-threat-matches pair stored in GCS. */
|
||||
public record RegistrarThreatMatches(String clientId, ImmutableList<ThreatMatch> threatMatches) {
|
||||
|
||||
static RegistrarThreatMatches create(String clientId, List<ThreatMatch> threatMatches) {
|
||||
return new RegistrarThreatMatches(clientId, ImmutableList.copyOf(threatMatches));
|
||||
/**
|
||||
* A value record representing a registrar and its associated list of threat matches.
|
||||
*
|
||||
* @param registrarId the ID of the registrar
|
||||
* @param threatMatches the list of {@link ThreatMatch} objects associated with the registrar
|
||||
*/
|
||||
public record RegistrarThreatMatches(String registrarId, ImmutableList<ThreatMatch> threatMatches) {
|
||||
/** Creates a new {@link RegistrarThreatMatches} instance. */
|
||||
static RegistrarThreatMatches create(
|
||||
String registrarId, ImmutableList<ThreatMatch> threatMatches) {
|
||||
return new RegistrarThreatMatches(registrarId, threatMatches);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user