diff --git a/java/google/registry/flows/EppController.java b/java/google/registry/flows/EppController.java index 7a43e3ff8..44f2ae054 100644 --- a/java/google/registry/flows/EppController.java +++ b/java/google/registry/flows/EppController.java @@ -17,8 +17,8 @@ package google.registry.flows; import static com.google.common.base.Strings.nullToEmpty; import static com.google.common.flogger.LazyArgs.lazy; import static com.google.common.io.BaseEncoding.base64; -import static google.registry.flows.EppXmlTransformer.unmarshal; import static google.registry.flows.FlowReporter.extractTlds; +import static google.registry.flows.FlowUtils.unmarshalEpp; import static java.nio.charset.StandardCharsets.UTF_8; import com.google.common.annotations.VisibleForTesting; @@ -65,7 +65,7 @@ public final class EppController { try { EppInput eppInput; try { - eppInput = unmarshal(EppInput.class, inputXmlBytes); + eppInput = unmarshalEpp(EppInput.class, inputXmlBytes); } catch (EppException e) { // Log the unmarshalling error, with the raw bytes (in base64) to help with debugging. logger.atInfo().withCause(e).log( diff --git a/java/google/registry/flows/EppRequestHandler.java b/java/google/registry/flows/EppRequestHandler.java index 2d1f568fa..5b2785581 100644 --- a/java/google/registry/flows/EppRequestHandler.java +++ b/java/google/registry/flows/EppRequestHandler.java @@ -14,7 +14,7 @@ package google.registry.flows; -import static google.registry.flows.EppXmlTransformer.marshalWithLenientRetry; +import static google.registry.flows.FlowUtils.marshalWithLenientRetry; import static google.registry.model.eppoutput.Result.Code.SUCCESS_AND_CLOSE; import static google.registry.xml.XmlTransformer.prettyPrint; import static java.nio.charset.StandardCharsets.UTF_8; diff --git a/java/google/registry/flows/EppXmlTransformer.java b/java/google/registry/flows/EppXmlTransformer.java deleted file mode 100644 index 71838b3c8..000000000 --- a/java/google/registry/flows/EppXmlTransformer.java +++ /dev/null @@ -1,179 +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; - -import static com.google.common.base.Preconditions.checkState; -import static google.registry.xml.ValidationMode.LENIENT; -import static google.registry.xml.ValidationMode.STRICT; -import static java.nio.charset.StandardCharsets.UTF_8; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Throwables; -import com.google.common.collect.ImmutableList; -import com.google.common.flogger.FluentLogger; -import google.registry.flows.EppException.ParameterValueRangeErrorException; -import google.registry.flows.EppException.ParameterValueSyntaxErrorException; -import google.registry.flows.EppException.SyntaxErrorException; -import google.registry.flows.EppException.UnimplementedProtocolVersionException; -import google.registry.model.EppResourceUtils.InvalidRepoIdException; -import google.registry.model.ImmutableObject; -import google.registry.model.eppinput.EppInput; -import google.registry.model.eppinput.EppInput.WrongProtocolVersionException; -import google.registry.model.eppoutput.EppOutput; -import google.registry.model.host.InetAddressAdapter.IpVersionMismatchException; -import google.registry.model.translators.CurrencyUnitAdapter.UnknownCurrencyException; -import google.registry.xml.ValidationMode; -import google.registry.xml.XmlException; -import google.registry.xml.XmlTransformer; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.util.List; - -/** {@link XmlTransformer} for marshalling to and from the Epp model classes. */ -public class EppXmlTransformer { - - private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - - // Hardcoded XML schemas, ordered with respect to dependency. - private static final ImmutableList SCHEMAS = ImmutableList.of( - "eppcom.xsd", - "epp.xsd", - "contact.xsd", - "host.xsd", - "domain.xsd", - "rgp.xsd", - "secdns.xsd", - "fee06.xsd", - "fee11.xsd", - "fee12.xsd", - "metadata.xsd", - "mark.xsd", - "dsig.xsd", - "smd.xsd", - "launch.xsd", - "allocate.xsd", - "superuser.xsd", - "allocationToken-1.0.xsd"); - - private static final XmlTransformer INPUT_TRANSFORMER = - new XmlTransformer(SCHEMAS, EppInput.class); - - private static final XmlTransformer OUTPUT_TRANSFORMER = - new XmlTransformer(SCHEMAS, EppOutput.class); - - public static void validateOutput(String xml) throws XmlException { - OUTPUT_TRANSFORMER.validate(xml); - } - - /** - * Unmarshal bytes into Epp classes. - * - * @param clazz type to return, specified as a param to enforce typesafe generics - * @see TypeParameterUnusedInFormals - */ - public static T unmarshal(Class clazz, byte[] bytes) throws EppException { - try { - return INPUT_TRANSFORMER.unmarshal(clazz, new ByteArrayInputStream(bytes)); - } catch (XmlException e) { - // If this XmlException is wrapping a known type find it. If not, it's a syntax error. - List causalChain = Throwables.getCausalChain(e); - if (causalChain.stream().anyMatch(IpVersionMismatchException.class::isInstance)) { - throw new IpAddressVersionMismatchException(); - } - if (causalChain.stream().anyMatch(WrongProtocolVersionException.class::isInstance)) { - throw new UnimplementedProtocolVersionException(); - } - if (causalChain.stream().anyMatch(InvalidRepoIdException.class::isInstance)) { - throw new InvalidRepoIdEppException(); - } - if (causalChain.stream().anyMatch(UnknownCurrencyException.class::isInstance)) { - throw new UnknownCurrencyEppException(); - } - throw new GenericSyntaxErrorException(e.getMessage()); - } - } - - private static byte[] marshal( - XmlTransformer transformer, - ImmutableObject root, - ValidationMode validation) throws XmlException { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - transformer.marshal(root, byteArrayOutputStream, UTF_8, validation); - return byteArrayOutputStream.toByteArray(); - } - - public static byte[] marshal(EppOutput root, ValidationMode validation) throws XmlException { - return marshal(OUTPUT_TRANSFORMER, root, validation); - } - - public static byte[] marshalWithLenientRetry(EppOutput eppOutput) { - checkState(eppOutput != null); - // We need to marshal to a string instead of writing the response directly to the servlet's - // response writer, so that partial results don't get written on failure. - try { - return EppXmlTransformer.marshal(eppOutput, STRICT); - } catch (XmlException e) { - // We failed to marshal with validation. This is very bad, but we can potentially still send - // back slightly invalid xml, so try again without validation. - try { - byte[] lenient = EppXmlTransformer.marshal(eppOutput, LENIENT); - // Marshaling worked even though the results didn't validate against the schema. - logger.atSevere().withCause(e).log( - "Result marshaled but did not validate: %s", new String(lenient, UTF_8)); - return lenient; - } catch (XmlException e2) { - throw new RuntimeException(e2); // Failing to marshal at all is not recoverable. - } - } - } - - @VisibleForTesting - public static byte[] marshalInput(EppInput root, ValidationMode validation) throws XmlException { - return marshal(INPUT_TRANSFORMER, root, validation); - } - - @VisibleForTesting - public static void validateInput(String xml) throws XmlException { - INPUT_TRANSFORMER.validate(xml); - } - - /** IP address version mismatch. */ - public static class IpAddressVersionMismatchException extends ParameterValueRangeErrorException { - public IpAddressVersionMismatchException() { - super("IP adddress version mismatch"); - } - } - - /** Invalid format for repository id. */ - public static class InvalidRepoIdEppException extends ParameterValueSyntaxErrorException { - public InvalidRepoIdEppException() { - super("Invalid format for repository id"); - } - } - - /** Unknown currency. */ - static class UnknownCurrencyEppException extends ParameterValueRangeErrorException { - public UnknownCurrencyEppException() { - super("Unknown currency."); - } - } - - /** Generic syntax error that can be thrown by any flow. */ - static class GenericSyntaxErrorException extends SyntaxErrorException { - public GenericSyntaxErrorException(String message) { - super(message); - } - } -} diff --git a/java/google/registry/flows/FlowUtils.java b/java/google/registry/flows/FlowUtils.java index 238ef3951..767688e08 100644 --- a/java/google/registry/flows/FlowUtils.java +++ b/java/google/registry/flows/FlowUtils.java @@ -14,14 +14,32 @@ package google.registry.flows; +import static com.google.common.base.Preconditions.checkState; import static google.registry.model.ofy.ObjectifyService.ofy; +import static google.registry.xml.ValidationMode.LENIENT; +import static google.registry.xml.ValidationMode.STRICT; +import static java.nio.charset.StandardCharsets.UTF_8; +import com.google.common.base.Throwables; +import com.google.common.flogger.FluentLogger; import google.registry.flows.EppException.CommandUseErrorException; +import google.registry.flows.EppException.ParameterValueRangeErrorException; +import google.registry.flows.EppException.SyntaxErrorException; +import google.registry.flows.EppException.UnimplementedProtocolVersionException; import google.registry.flows.custom.EntityChanges; +import google.registry.model.eppcommon.EppXmlTransformer; +import google.registry.model.eppinput.EppInput.WrongProtocolVersionException; +import google.registry.model.eppoutput.EppOutput; +import google.registry.model.host.InetAddressAdapter.IpVersionMismatchException; +import google.registry.model.translators.CurrencyUnitAdapter.UnknownCurrencyException; +import google.registry.xml.XmlException; +import java.util.List; /** Static utility functions for flows. */ public final class FlowUtils { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); + private FlowUtils() {} /** Validate that there is a logged in client. */ @@ -37,10 +55,75 @@ public final class FlowUtils { ofy().delete().keys(entityChanges.getDeletes()); } + /** + * Unmarshal bytes into Epp classes. Does the same as {@link EppXmlTransformer#unmarshal(Class, + * byte[])} but with exception-handling logic to throw {@link EppException} instead. + */ + public static T unmarshalEpp(Class clazz, byte[] bytes) throws EppException { + try { + return EppXmlTransformer.unmarshal(clazz, bytes); + } catch (XmlException e) { + // If this XmlException is wrapping a known type find it. If not, it's a syntax error. + List causalChain = Throwables.getCausalChain(e); + if (causalChain.stream().anyMatch(IpVersionMismatchException.class::isInstance)) { + throw new IpAddressVersionMismatchException(); + } + if (causalChain.stream().anyMatch(WrongProtocolVersionException.class::isInstance)) { + throw new UnimplementedProtocolVersionException(); + } + if (causalChain.stream().anyMatch(UnknownCurrencyException.class::isInstance)) { + throw new UnknownCurrencyEppException(); + } + throw new GenericXmlSyntaxErrorException(e.getMessage()); + } + } + + public static byte[] marshalWithLenientRetry(EppOutput eppOutput) { + checkState(eppOutput != null); + // We need to marshal to a string instead of writing the response directly to the servlet's + // response writer, so that partial results don't get written on failure. + try { + return EppXmlTransformer.marshal(eppOutput, STRICT); + } catch (XmlException e) { + // We failed to marshal with validation. This is very bad, but we can potentially still send + // back slightly invalid xml, so try again without validation. + try { + byte[] lenient = EppXmlTransformer.marshal(eppOutput, LENIENT); + // Marshaling worked even though the results didn't validate against the schema. + logger.atSevere().withCause(e).log( + "Result marshaled but did not validate: %s", new String(lenient, UTF_8)); + return lenient; + } catch (XmlException e2) { + throw new RuntimeException(e2); // Failing to marshal at all is not recoverable. + } + } + } + /** Registrar is not logged in. */ public static class NotLoggedInException extends CommandUseErrorException { public NotLoggedInException() { super("Registrar is not logged in."); } } + + /** IP address version mismatch. */ + public static class IpAddressVersionMismatchException extends ParameterValueRangeErrorException { + public IpAddressVersionMismatchException() { + super("IP adddress version mismatch"); + } + } + + /** Unknown currency. */ + static class UnknownCurrencyEppException extends ParameterValueRangeErrorException { + public UnknownCurrencyEppException() { + super("Unknown currency."); + } + } + + /** Generic XML syntax error that can be thrown by any flow. */ + public static class GenericXmlSyntaxErrorException extends SyntaxErrorException { + public GenericXmlSyntaxErrorException(String message) { + super(message); + } + } } diff --git a/java/google/registry/flows/domain/DomainApplicationInfoFlow.java b/java/google/registry/flows/domain/DomainApplicationInfoFlow.java index 841a0156e..8224ce739 100644 --- a/java/google/registry/flows/domain/DomainApplicationInfoFlow.java +++ b/java/google/registry/flows/domain/DomainApplicationInfoFlow.java @@ -15,7 +15,7 @@ package google.registry.flows.domain; import static com.google.common.collect.Sets.union; -import static google.registry.flows.EppXmlTransformer.unmarshal; +import static google.registry.flows.FlowUtils.unmarshalEpp; import static google.registry.flows.FlowUtils.validateClientIsLoggedIn; import static google.registry.flows.ResourceFlowUtils.verifyExistence; import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo; @@ -136,7 +136,7 @@ public final class DomainApplicationInfoFlow implements Flow { if (Boolean.TRUE.equals(launchInfo.getIncludeMark())) { // Default to false. for (EncodedSignedMark encodedMark : application.getEncodedSignedMarks()) { try { - marksBuilder.add(unmarshal(SignedMark.class, encodedMark.getBytes()).getMark()); + marksBuilder.add(unmarshalEpp(SignedMark.class, encodedMark.getBytes()).getMark()); } catch (EppException e) { // This is a serious error; don't let the benign EppException propagate. throw new IllegalStateException("Could not decode a stored encoded signed mark", e); diff --git a/java/google/registry/flows/domain/DomainFlowTmchUtils.java b/java/google/registry/flows/domain/DomainFlowTmchUtils.java index 4ba9e8e4f..765e363fa 100644 --- a/java/google/registry/flows/domain/DomainFlowTmchUtils.java +++ b/java/google/registry/flows/domain/DomainFlowTmchUtils.java @@ -15,7 +15,7 @@ package google.registry.flows.domain; import static com.google.common.collect.Iterables.concat; -import static google.registry.flows.EppXmlTransformer.unmarshal; +import static google.registry.flows.FlowUtils.unmarshalEpp; import com.google.common.collect.ImmutableList; import google.registry.flows.EppException; @@ -90,7 +90,7 @@ public final class DomainFlowTmchUtils { SignedMark signedMark; try { - signedMark = unmarshal(SignedMark.class, signedMarkData); + signedMark = unmarshalEpp(SignedMark.class, signedMarkData); } catch (EppException e) { throw new SignedMarkParsingErrorException(); } diff --git a/java/google/registry/flows/host/HostCreateFlow.java b/java/google/registry/flows/host/HostCreateFlow.java index 2ffbe8ccf..63aa8c0a0 100644 --- a/java/google/registry/flows/host/HostCreateFlow.java +++ b/java/google/registry/flows/host/HostCreateFlow.java @@ -64,7 +64,7 @@ import org.joda.time.DateTime; * hosts cannot have any. This flow allows creating a host name, and if necessary enqueues tasks to * update DNS. * - * @error {@link google.registry.flows.EppXmlTransformer.IpAddressVersionMismatchException} + * @error {@link google.registry.flows.FlowUtils.IpAddressVersionMismatchException} * @error {@link google.registry.flows.exceptions.ResourceAlreadyExistsException} * @error {@link HostFlowUtils.HostNameTooLongException} * @error {@link HostFlowUtils.HostNameTooShallowException} @@ -87,8 +87,13 @@ public final class HostCreateFlow implements TransactionalFlow { @Inject HistoryEntry.Builder historyBuilder; @Inject DnsQueue dnsQueue; @Inject EppResponse.Builder responseBuilder; - @Inject @Config("contactAndHostRoidSuffix") String roidSuffix; - @Inject HostCreateFlow() {} + + @Inject + @Config("contactAndHostRoidSuffix") + String roidSuffix; + + @Inject + HostCreateFlow() {} @Override public final EppResponse run() throws EppException { @@ -126,17 +131,21 @@ public final class HostCreateFlow implements TransactionalFlow { .setType(HistoryEntry.Type.HOST_CREATE) .setModificationTime(now) .setParent(Key.create(newHost)); - ImmutableSet entitiesToSave = ImmutableSet.of( - newHost, - historyBuilder.build(), - ForeignKeyIndex.create(newHost, newHost.getDeletionTime()), - EppResourceIndex.create(Key.create(newHost))); + ImmutableSet entitiesToSave = + ImmutableSet.of( + newHost, + historyBuilder.build(), + ForeignKeyIndex.create(newHost, newHost.getDeletionTime()), + EppResourceIndex.create(Key.create(newHost))); if (superordinateDomain.isPresent()) { - entitiesToSave = union( - entitiesToSave, - superordinateDomain.get().asBuilder() - .addSubordinateHost(command.getFullyQualifiedHostName()) - .build()); + entitiesToSave = + union( + entitiesToSave, + superordinateDomain + .get() + .asBuilder() + .addSubordinateHost(command.getFullyQualifiedHostName()) + .build()); // Only update DNS if this is a subordinate host. External hosts have no glue to write, so // they are only written as NS records from the referencing domain. dnsQueue.addHostRefreshTask(targetId); diff --git a/java/google/registry/model/EppResourceUtils.java b/java/google/registry/model/EppResourceUtils.java index dba9b9b4c..b013917cc 100644 --- a/java/google/registry/model/EppResourceUtils.java +++ b/java/google/registry/model/EppResourceUtils.java @@ -402,13 +402,5 @@ public final class EppResourceUtils { return queryForLinkedDomains(key, now).limit(1).count() > 0; } - /** Exception to throw when failing to parse a repo id. */ - public static class InvalidRepoIdException extends Exception { - - public InvalidRepoIdException(String message) { - super(message); - } - } - private EppResourceUtils() {} } diff --git a/java/google/registry/model/eppcommon/EppXmlTransformer.java b/java/google/registry/model/eppcommon/EppXmlTransformer.java new file mode 100644 index 000000000..b4a3a0c2a --- /dev/null +++ b/java/google/registry/model/eppcommon/EppXmlTransformer.java @@ -0,0 +1,95 @@ +// 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.eppcommon; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; +import google.registry.model.ImmutableObject; +import google.registry.model.eppinput.EppInput; +import google.registry.model.eppoutput.EppOutput; +import google.registry.xml.ValidationMode; +import google.registry.xml.XmlException; +import google.registry.xml.XmlTransformer; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +/** {@link XmlTransformer} for marshalling to and from the Epp model classes. */ +public class EppXmlTransformer { + + // Hardcoded XML schemas, ordered with respect to dependency. + private static final ImmutableList SCHEMAS = ImmutableList.of( + "eppcom.xsd", + "epp.xsd", + "contact.xsd", + "host.xsd", + "domain.xsd", + "rgp.xsd", + "secdns.xsd", + "fee06.xsd", + "fee11.xsd", + "fee12.xsd", + "metadata.xsd", + "mark.xsd", + "dsig.xsd", + "smd.xsd", + "launch.xsd", + "allocate.xsd", + "superuser.xsd", + "allocationToken-1.0.xsd"); + + private static final XmlTransformer INPUT_TRANSFORMER = + new XmlTransformer(SCHEMAS, EppInput.class); + + private static final XmlTransformer OUTPUT_TRANSFORMER = + new XmlTransformer(SCHEMAS, EppOutput.class); + + public static void validateOutput(String xml) throws XmlException { + OUTPUT_TRANSFORMER.validate(xml); + } + + /** + * Unmarshal bytes into Epp classes. + * + * @param clazz type to return, specified as a param to enforce typesafe generics + */ + public static T unmarshal(Class clazz, byte[] bytes) throws XmlException { + return INPUT_TRANSFORMER.unmarshal(clazz, new ByteArrayInputStream(bytes)); + } + + private static byte[] marshal( + XmlTransformer transformer, + ImmutableObject root, + ValidationMode validation) throws XmlException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + transformer.marshal(root, byteArrayOutputStream, UTF_8, validation); + return byteArrayOutputStream.toByteArray(); + } + + public static byte[] marshal(EppOutput root, ValidationMode validation) throws XmlException { + return marshal(OUTPUT_TRANSFORMER, root, validation); + } + + @VisibleForTesting + public static byte[] marshalInput(EppInput root, ValidationMode validation) throws XmlException { + return marshal(INPUT_TRANSFORMER, root, validation); + } + + @VisibleForTesting + public static void validateInput(String xml) throws XmlException { + INPUT_TRANSFORMER.validate(xml); + } +} diff --git a/java/google/registry/tools/AllocateDomainCommand.java b/java/google/registry/tools/AllocateDomainCommand.java index 7edc31a7d..c39997d0f 100644 --- a/java/google/registry/tools/AllocateDomainCommand.java +++ b/java/google/registry/tools/AllocateDomainCommand.java @@ -21,7 +21,7 @@ import static com.google.common.base.Strings.emptyToNull; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.Iterables.transform; import static com.google.common.io.BaseEncoding.base16; -import static google.registry.flows.EppXmlTransformer.unmarshal; +import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal; import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.tools.CommandUtilities.addHeader; import static java.util.stream.Collectors.joining; @@ -34,7 +34,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.template.soy.data.SoyMapData; import com.googlecode.objectify.Key; -import google.registry.flows.EppException; import google.registry.model.domain.DesignatedContact; import google.registry.model.domain.DomainApplication; import google.registry.model.domain.DomainCommand; @@ -46,6 +45,7 @@ import google.registry.model.eppinput.EppInput.ResourceCommandWrapper; import google.registry.model.reporting.HistoryEntry; import google.registry.model.smd.SignedMark; import google.registry.tools.soy.DomainAllocateSoyInfo; +import google.registry.xml.XmlException; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -88,7 +88,7 @@ final class AllocateDomainCommand extends MutatingEppToolCommand { } /** Extract the registration period from the XML used to create the domain application. */ - private static Period extractPeriodFromXml(byte[] xmlBytes) throws EppException { + private static Period extractPeriodFromXml(byte[] xmlBytes) throws XmlException { EppInput eppInput = unmarshal(EppInput.class, xmlBytes); return ((DomainCommand.Create) ((ResourceCommandWrapper) eppInput.getCommandWrapper().getCommand()) @@ -182,7 +182,7 @@ final class AllocateDomainCommand extends MutatingEppToolCommand { "dsRecords", dsRecords, "clTrid", clientTransactionId)); applicationKeys.add(Key.create(application)); - } catch (EppException e) { + } catch (XmlException e) { throw new RuntimeException(e); } } diff --git a/java/google/registry/tools/GenerateApplicationsReportCommand.java b/java/google/registry/tools/GenerateApplicationsReportCommand.java index 5dc4b300c..afe831b36 100644 --- a/java/google/registry/tools/GenerateApplicationsReportCommand.java +++ b/java/google/registry/tools/GenerateApplicationsReportCommand.java @@ -15,7 +15,7 @@ package google.registry.tools; import static com.google.common.base.Strings.isNullOrEmpty; -import static google.registry.flows.EppXmlTransformer.unmarshal; +import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal; import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.registry.Registries.assertTldExists; import static google.registry.util.DateTimeUtils.isBeforeOrAt; @@ -29,7 +29,6 @@ import com.google.common.base.Joiner; import com.google.common.net.InternetDomainName; import com.googlecode.objectify.cmd.LoadType; import com.googlecode.objectify.cmd.Query; -import google.registry.flows.EppException; import google.registry.model.domain.DomainApplication; import google.registry.model.smd.EncodedSignedMark; import google.registry.model.smd.SignedMark; @@ -39,6 +38,7 @@ import google.registry.tmch.TmchXmlSignature; import google.registry.tools.params.PathParameter; import google.registry.util.Clock; import google.registry.util.Idn; +import google.registry.xml.XmlException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -132,7 +132,7 @@ final class GenerateApplicationsReportCommand implements CommandWithRemoteApi { SignedMark signedMark; try { signedMark = unmarshal(SignedMark.class, signedMarkData); - } catch (EppException e) { + } catch (XmlException e) { return Optional.of(makeLine(domainApplication, "Unparseable SMD")); } diff --git a/java/google/registry/tools/server/BUILD b/java/google/registry/tools/server/BUILD index 0c2fa9cda..9687c3cab 100644 --- a/java/google/registry/tools/server/BUILD +++ b/java/google/registry/tools/server/BUILD @@ -11,7 +11,6 @@ java_library( "//java/google/registry/config", "//java/google/registry/dns", "//java/google/registry/export", - "//java/google/registry/flows", "//java/google/registry/gcs", "//java/google/registry/groups", "//java/google/registry/mapreduce", @@ -20,6 +19,7 @@ java_library( "//java/google/registry/request", "//java/google/registry/request/auth", "//java/google/registry/util", + "//java/google/registry/xml", "//third_party/objectify:objectify-v4_1", "@com_google_appengine_api_1_0_sdk", "@com_google_appengine_tools_appengine_gcs_client", diff --git a/java/google/registry/tools/server/VerifyOteAction.java b/java/google/registry/tools/server/VerifyOteAction.java index 4654b4e9e..814b1903b 100644 --- a/java/google/registry/tools/server/VerifyOteAction.java +++ b/java/google/registry/tools/server/VerifyOteAction.java @@ -17,7 +17,7 @@ package google.registry.tools.server; import static com.google.common.base.Predicates.equalTo; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.Maps.toMap; -import static google.registry.flows.EppXmlTransformer.unmarshal; +import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal; import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.util.CollectionUtils.isNullOrEmpty; import static google.registry.util.DomainNameUtils.ACE_PREFIX; @@ -30,7 +30,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Multiset; import com.googlecode.objectify.Key; import com.googlecode.objectify.cmd.Query; -import google.registry.flows.EppException; import google.registry.model.domain.DomainCommand; import google.registry.model.domain.fee.FeeCreateCommandExtension; import google.registry.model.domain.launch.LaunchCreateExtension; @@ -45,6 +44,7 @@ import google.registry.request.Action; import google.registry.request.JsonActionRunner; import google.registry.request.JsonActionRunner.JsonAction; import google.registry.request.auth.Auth; +import google.registry.xml.XmlException; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; @@ -264,7 +264,7 @@ public class VerifyOteAction implements Runnable, JsonAction { for (HistoryEntry historyEntry : query) { try { record(historyEntry); - } catch (EppException e) { + } catch (XmlException e) { throw new RuntimeException("Couldn't parse history entry " + Key.create(historyEntry), e); } // Break out early if all tests were passed. @@ -276,7 +276,7 @@ public class VerifyOteAction implements Runnable, JsonAction { } /** Interprets the data in the provided HistoryEntry and increments counters. */ - void record(final HistoryEntry historyEntry) throws EppException { + void record(final HistoryEntry historyEntry) throws XmlException { byte[] xmlBytes = historyEntry.getXmlBytes(); // xmlBytes can be null on contact create and update for safe-harbor compliance. final Optional eppInput = diff --git a/javatests/google/registry/flows/EppControllerTest.java b/javatests/google/registry/flows/EppControllerTest.java index 1e882aca6..ba1648309 100644 --- a/javatests/google/registry/flows/EppControllerTest.java +++ b/javatests/google/registry/flows/EppControllerTest.java @@ -16,7 +16,7 @@ package google.registry.flows; import static com.google.common.io.BaseEncoding.base64; import static com.google.common.truth.Truth.assertThat; -import static google.registry.flows.EppXmlTransformer.marshal; +import static google.registry.model.eppcommon.EppXmlTransformer.marshal; import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.LogsSubject.assertAboutLogs; import static google.registry.testing.TestDataHelper.loadFile; diff --git a/javatests/google/registry/flows/EppTestCase.java b/javatests/google/registry/flows/EppTestCase.java index cc78dad27..fdd95d154 100644 --- a/javatests/google/registry/flows/EppTestCase.java +++ b/javatests/google/registry/flows/EppTestCase.java @@ -35,6 +35,7 @@ import google.registry.model.billing.BillingEvent.Flag; import google.registry.model.billing.BillingEvent.OneTime; import google.registry.model.billing.BillingEvent.Reason; import google.registry.model.domain.DomainResource; +import google.registry.model.eppcommon.EppXmlTransformer; import google.registry.model.ofy.Ofy; import google.registry.model.registry.Registry; import google.registry.model.reporting.HistoryEntry; diff --git a/javatests/google/registry/flows/FlowTestCase.java b/javatests/google/registry/flows/FlowTestCase.java index 80e25ec28..7ca158b4f 100644 --- a/javatests/google/registry/flows/FlowTestCase.java +++ b/javatests/google/registry/flows/FlowTestCase.java @@ -19,7 +19,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.Sets.difference; import static com.google.common.truth.Truth.assertThat; -import static google.registry.flows.EppXmlTransformer.marshal; +import static google.registry.model.eppcommon.EppXmlTransformer.marshal; import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.testing.DatastoreHelper.POLL_MESSAGE_ID_STRIPPER; import static google.registry.testing.DatastoreHelper.getPollMessages; diff --git a/javatests/google/registry/flows/host/HostCreateFlowTest.java b/javatests/google/registry/flows/host/HostCreateFlowTest.java index 046ad78e2..8810482bc 100644 --- a/javatests/google/registry/flows/host/HostCreateFlowTest.java +++ b/javatests/google/registry/flows/host/HostCreateFlowTest.java @@ -35,7 +35,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.googlecode.objectify.Key; import google.registry.flows.EppException; -import google.registry.flows.EppXmlTransformer.IpAddressVersionMismatchException; +import google.registry.flows.FlowUtils.IpAddressVersionMismatchException; import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.exceptions.ResourceAlreadyExistsException; import google.registry.flows.host.HostCreateFlow.SubordinateHostMustHaveIpException; diff --git a/javatests/google/registry/flows/session/LoginFlowTestCase.java b/javatests/google/registry/flows/session/LoginFlowTestCase.java index d678704b7..4df2e99b1 100644 --- a/javatests/google/registry/flows/session/LoginFlowTestCase.java +++ b/javatests/google/registry/flows/session/LoginFlowTestCase.java @@ -45,7 +45,7 @@ public abstract class LoginFlowTestCase extends FlowTestCase { @Before public void initRegistrar() { - sessionMetadata.setClientId(null); // Don't implicitly log in (all other flows need to). + sessionMetadata.setClientId(null); // Don't implicitly log in (all other flows need to). registrar = loadRegistrar("NewRegistrar"); registrarBuilder = registrar.asBuilder(); } diff --git a/javatests/google/registry/model/ResourceCommandTestCase.java b/javatests/google/registry/model/ResourceCommandTestCase.java index 83ccdaa21..066430f30 100644 --- a/javatests/google/registry/model/ResourceCommandTestCase.java +++ b/javatests/google/registry/model/ResourceCommandTestCase.java @@ -14,7 +14,7 @@ package google.registry.model; -import static google.registry.flows.EppXmlTransformer.marshalInput; +import static google.registry.model.eppcommon.EppXmlTransformer.marshalInput; import static google.registry.xml.ValidationMode.STRICT; import static google.registry.xml.XmlTestUtils.assertXmlEquals; import static java.nio.charset.StandardCharsets.UTF_8; diff --git a/javatests/google/registry/model/contact/ContactCommandTest.java b/javatests/google/registry/model/contact/ContactCommandTest.java index d7a4942d2..302b8adcf 100644 --- a/javatests/google/registry/model/contact/ContactCommandTest.java +++ b/javatests/google/registry/model/contact/ContactCommandTest.java @@ -14,8 +14,8 @@ package google.registry.model.contact; -import static google.registry.flows.EppXmlTransformer.marshalInput; -import static google.registry.flows.EppXmlTransformer.validateInput; +import static google.registry.model.eppcommon.EppXmlTransformer.marshalInput; +import static google.registry.model.eppcommon.EppXmlTransformer.validateInput; import static google.registry.xml.ValidationMode.LENIENT; import static google.registry.xml.XmlTestUtils.assertXmlEquals; import static java.nio.charset.StandardCharsets.UTF_8; diff --git a/javatests/google/registry/flows/EppXmlTransformerTest.java b/javatests/google/registry/model/eppcommon/EppXmlTransformerTest.java similarity index 86% rename from javatests/google/registry/flows/EppXmlTransformerTest.java rename to javatests/google/registry/model/eppcommon/EppXmlTransformerTest.java index 87d0428ea..062c1e7db 100644 --- a/javatests/google/registry/flows/EppXmlTransformerTest.java +++ b/javatests/google/registry/model/eppcommon/EppXmlTransformerTest.java @@ -12,11 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. - -package google.registry.flows; +package google.registry.model.eppcommon; import static com.google.common.truth.Truth.assertThat; -import static google.registry.flows.EppXmlTransformer.unmarshal; +import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal; import static google.registry.testing.JUnitBackports.assertThrows; import static google.registry.testing.TestDataHelper.loadBytes; @@ -41,8 +40,6 @@ public class EppXmlTransformerTest extends ShardableTestCase { public void testUnmarshalingWrongClassThrows() { assertThrows( ClassCastException.class, - () -> - EppXmlTransformer.unmarshal( - EppOutput.class, loadBytes(getClass(), "contact_info.xml").read())); + () -> unmarshal(EppOutput.class, loadBytes(getClass(), "contact_info.xml").read())); } } diff --git a/javatests/google/registry/model/eppcommon/testdata/contact_info.xml b/javatests/google/registry/model/eppcommon/testdata/contact_info.xml new file mode 100644 index 000000000..6c9de20ad --- /dev/null +++ b/javatests/google/registry/model/eppcommon/testdata/contact_info.xml @@ -0,0 +1,14 @@ + + + + + sh8013 + + 2fooBAR + + + + ABC-12345 + + diff --git a/javatests/google/registry/model/eppinput/EppInputTest.java b/javatests/google/registry/model/eppinput/EppInputTest.java index e6168dddc..4c9e0071a 100644 --- a/javatests/google/registry/model/eppinput/EppInputTest.java +++ b/javatests/google/registry/model/eppinput/EppInputTest.java @@ -16,15 +16,15 @@ package google.registry.model.eppinput; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth8.assertThat; -import static google.registry.flows.EppXmlTransformer.unmarshal; +import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal; import static google.registry.testing.JUnitBackports.assertThrows; import static google.registry.testing.TestDataHelper.loadBytes; -import google.registry.flows.EppException.SyntaxErrorException; import google.registry.model.contact.ContactResourceTest; import google.registry.model.domain.DomainResourceTest; import google.registry.model.eppinput.EppInput.InnerCommand; import google.registry.model.eppinput.EppInput.Login; +import google.registry.xml.XmlException; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -83,7 +83,7 @@ public class EppInputTest { @Test public void testUnmarshalling_loginTagInWrongCase_throws() { assertThrows( - SyntaxErrorException.class, + XmlException.class, () -> unmarshal(EppInput.class, loadBytes(getClass(), "login_wrong_case.xml").read())); } } diff --git a/javatests/google/registry/model/translators/StatusValueAdapterTest.java b/javatests/google/registry/model/translators/StatusValueAdapterTest.java index 598655ad9..6eefaddf9 100644 --- a/javatests/google/registry/model/translators/StatusValueAdapterTest.java +++ b/javatests/google/registry/model/translators/StatusValueAdapterTest.java @@ -20,7 +20,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import google.registry.flows.EppXmlTransformer; +import google.registry.model.eppcommon.EppXmlTransformer; import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppinput.EppInput; import google.registry.model.eppinput.EppInput.ResourceCommandWrapper; diff --git a/javatests/google/registry/testing/EppExceptionSubject.java b/javatests/google/registry/testing/EppExceptionSubject.java index ecbb1df17..ab047b9a2 100644 --- a/javatests/google/registry/testing/EppExceptionSubject.java +++ b/javatests/google/registry/testing/EppExceptionSubject.java @@ -16,7 +16,7 @@ package google.registry.testing; import static com.google.common.truth.Truth.assertAbout; import static com.google.common.truth.Truth.assertThat; -import static google.registry.flows.EppXmlTransformer.marshal; +import static google.registry.model.eppcommon.EppXmlTransformer.marshal; import com.google.common.truth.FailureMetadata; import com.google.common.truth.SimpleSubjectBuilder; diff --git a/javatests/google/registry/testing/EppLoader.java b/javatests/google/registry/testing/EppLoader.java index 0dd9e8811..02cc6ac16 100644 --- a/javatests/google/registry/testing/EppLoader.java +++ b/javatests/google/registry/testing/EppLoader.java @@ -14,7 +14,7 @@ package google.registry.testing; -import static google.registry.flows.EppXmlTransformer.unmarshal; +import static google.registry.flows.FlowUtils.unmarshalEpp; import static google.registry.testing.TestDataHelper.loadFile; import static java.nio.charset.StandardCharsets.UTF_8; @@ -37,7 +37,12 @@ public class EppLoader { } public EppInput getEpp() throws EppException { - return unmarshal(EppInput.class, eppXml.getBytes(UTF_8)); + /* + * TODO(b/120837374): we shouldn't use EppException in non-Flow tests. Find a way to use {@link + * google.registry.model.eppcommon.EppXmlTransformer#unmarshal(Class, byte[])} in those tests + * instead of {@link google.registry.flows.FlowUtils#unmarshalEpp(Class, byte[])} + */ + return unmarshalEpp(EppInput.class, eppXml.getBytes(UTF_8)); } public String getEppXml() { diff --git a/javatests/google/registry/tools/AllocateDomainCommandTest.java b/javatests/google/registry/tools/AllocateDomainCommandTest.java index 0e2638f7b..351076561 100644 --- a/javatests/google/registry/tools/AllocateDomainCommandTest.java +++ b/javatests/google/registry/tools/AllocateDomainCommandTest.java @@ -16,12 +16,12 @@ package google.registry.tools; import static com.google.common.io.BaseEncoding.base16; import static com.google.common.truth.Truth.assertThat; -import static google.registry.flows.EppXmlTransformer.unmarshal; import static google.registry.flows.picker.FlowPicker.getFlowClass; import static google.registry.model.domain.DesignatedContact.Type.ADMIN; import static google.registry.model.domain.DesignatedContact.Type.BILLING; import static google.registry.model.domain.DesignatedContact.Type.TECH; import static google.registry.model.domain.launch.ApplicationStatus.VALIDATED; +import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal; import static google.registry.model.registry.Registry.TldState.QUIET_PERIOD; import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.newDomainApplication;