Add RdeParser

RdeParser can parse an escrow deposit file from a stream without
loading the entire file into memory, but offers the convenience
of parsing RDE elements into their jaxb object representation.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=124142087
This commit is contained in:
Wolfgang Meyers 2016-06-06 09:01:09 -07:00 committed by Ben McIlwain
parent 6f4e983813
commit 81dc55ceab
4 changed files with 1315 additions and 0 deletions

View file

@ -0,0 +1,568 @@
// Copyright 2016 The Domain Registry 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.rde;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
import google.registry.xjc.XjcXmlTransformer;
import google.registry.xjc.rdecontact.XjcRdeContact;
import google.registry.xjc.rdecontact.XjcRdeContactElement;
import google.registry.xjc.rdedomain.XjcRdeDomain;
import google.registry.xjc.rdedomain.XjcRdeDomainElement;
import google.registry.xjc.rdeeppparams.XjcRdeEppParams;
import google.registry.xjc.rdeeppparams.XjcRdeEppParamsElement;
import google.registry.xjc.rdeheader.XjcRdeHeader;
import google.registry.xjc.rdeheader.XjcRdeHeaderCount;
import google.registry.xjc.rdeheader.XjcRdeHeaderElement;
import google.registry.xjc.rdehost.XjcRdeHost;
import google.registry.xjc.rdehost.XjcRdeHostElement;
import google.registry.xjc.rdeidn.XjcRdeIdn;
import google.registry.xjc.rdeidn.XjcRdeIdnElement;
import google.registry.xjc.rdenndn.XjcRdeNndn;
import google.registry.xjc.rdenndn.XjcRdeNndnElement;
import google.registry.xjc.rderegistrar.XjcRdeRegistrar;
import google.registry.xjc.rderegistrar.XjcRdeRegistrarElement;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import javax.annotation.concurrent.NotThreadSafe;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;
/**
* RDE escrow deposit file parser
*
* <p>{@link RdeParser} parses escrow deposit files as a sequence of elements. The parser will first
* parse and cache the RDE header before any other elements, so all calls to {@link #getHeader} will
* return the header even if the parser has advanced beyond it.
*
* <p>{@link RdeParser} currently supports parsing the following rde elements as jaxb objects:
* <ul>
* <li>Contact</li>
* <li>Host</li>
* <li>Domain</li>
* <li>Registrar</li>
* <li>Tld</li>
* <li>IDN table reference</li>
* <li>EPP Params</li>
* <li>NNDN</li>
* </ul>
*
* <p>Any calls to {@link #nextDomain}, {@link #nextHost}, etc. will advance the parser to the next
* element in the file, if any additional elements of that type exist. Since the order of these
* elements is not known at the time the file is read, client code should only try to parse one type
* of element at a time. Parsing of additional element types should be performed by creating a new
* parser.
*/
@NotThreadSafe
public class RdeParser {
private static final String RDE_DOMAIN_URI = "urn:ietf:params:xml:ns:rdeDomain-1.0";
private static final String RDE_HOST_URI = "urn:ietf:params:xml:ns:rdeHost-1.0";
private static final String RDE_CONTACT_URI = "urn:ietf:params:xml:ns:rdeContact-1.0";
private static final String RDE_REGISTRAR_URI = "urn:ietf:params:xml:ns:rdeRegistrar-1.0";
private static final String RDE_IDN_URI = "urn:ietf:params:xml:ns:rdeIDN-1.0";
private static final String RDE_NNDN_URI = "urn:ietf:params:xml:ns:rdeNNDN-1.0";
private static final String RDE_EPP_PARAMS_URI = "urn:ietf:params:xml:ns:rdeEppParams-1.0";
private static final String RDE_HEADER_URI = "urn:ietf:params:xml:ns:rdeHeader-1.0";
/**
* Convenient immutable java representation of an RDE header
*/
public static class RdeHeader {
private final ImmutableMap<String, Long> counts;
private final String tld;
public String getTld() {
return tld;
}
public Long getDomainCount() {
return Optional.fromNullable(counts.get(RDE_DOMAIN_URI)).or(0L);
}
public Long getHostCount() {
return Optional.fromNullable(counts.get(RDE_HOST_URI)).or(0L);
}
public Long getContactCount() {
return Optional.fromNullable(counts.get(RDE_CONTACT_URI)).or(0L);
}
public Long getRegistrarCount() {
return Optional.fromNullable(counts.get(RDE_REGISTRAR_URI)).or(0L);
}
public Long getIdnCount() {
return Optional.fromNullable(counts.get(RDE_IDN_URI)).or(0L);
}
public Long getNndnCount() {
return Optional.fromNullable(counts.get(RDE_NNDN_URI)).or(0L);
}
public Long getEppParamsCount() {
return Optional.fromNullable(counts.get(RDE_EPP_PARAMS_URI)).or(0L);
}
private RdeHeader(XjcRdeHeader header) {
this.tld = header.getTld();
ImmutableMap.Builder<String, Long> builder = new ImmutableMap.Builder<>();
for (XjcRdeHeaderCount count : header.getCounts()) {
builder = builder.put(count.getUri(), count.getValue());
}
counts = builder.build();
}
}
private final XMLStreamReader reader;
private RdeHeader header;
/**
* Creates a new instance of {@link RdeParser}
*
* @param xmlInput Contents of the escrow deposit file
*/
public RdeParser(InputStream xmlInput) throws XMLStreamException {
XMLInputFactory factory = XMLInputFactory.newInstance();
reader = factory.createXMLStreamReader(xmlInput);
header = new RdeHeader(readHeader());
}
/**
* Attempts to read the RDE header as a jaxb object.
*
* @throws IllegalStateException if no RDE header is found in the file
*/
private XjcRdeHeader readHeader() {
if (!nextElement(RDE_HEADER_URI, "header")) {
throw new IllegalStateException("No RDE Header found");
}
XjcRdeHeaderElement element = (XjcRdeHeaderElement) unmarshalElement(RDE_HEADER_URI, "header");
return element.getValue();
}
/**
* Unmarshals the current element into a Jaxb element.
*
* @param uri Element URI
* @param name Element Name
* @return Jaxb Element
* @throws IllegalStateException if the parser is not at the specified element
*/
private Object unmarshalElement(String uri, String name) {
checkArgumentNotNull(name, "name cannot be null");
checkArgumentNotNull(uri, "uri cannot be null");
try {
if (isAtElement(uri, name)) {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
ByteArrayOutputStream bout = new ByteArrayOutputStream();
t.transform(new StAXSource(reader), new StreamResult(bout));
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
Object element = XjcXmlTransformer.unmarshal(bin);
return element;
} else {
throw new IllegalStateException(String.format("Not at element %s:%s", uri, name));
}
} catch (IllegalStateException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Checks if the parser is at an instance of the specified element.
*
* @param uri Element URI
* @param name Element Name
* @return true if the parser is at an instance of the element, false otherwise
*/
private boolean isAtElement(String uri, String name) {
return reader.getEventType() == XMLStreamReader.START_ELEMENT
&& uri.equals(reader.getNamespaceURI()) && name.equals(reader.getName().getLocalPart());
}
/**
* Attempts to advance to the next instance of the specified element.
*
* <p>The parser may skip over other types of elements while advancing to the next instance of the
* specified element.
*
* @param uri Element URI
* @param name Element Name
* @return true if the parser advanced to the element, false otherwise.
*/
private boolean nextElement(String uri, String name) {
try {
while (reader.hasNext()) {
reader.next();
if (isAtElement(uri, name)) {
return true;
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return false;
}
public RdeHeader getHeader() {
return header;
}
/**
* Attempts to skip over a number of specified elements.
*
* <p>If the parser is not currently at one of the specified elements, it will advance to the next
* instance before skipping any.
*
* <p>In the process of skipping over a specific type of element, other elements may be skipped as
* well. Elements of types other than that specified by the uri and name will not be counted.
*
* @param numberOfElements Number of elements to skip
* @param uri Element URI
* @param name Element Name
* @return Number of elements that were skipped
*/
private int skipElements(int numberOfElements, String uri, String name) {
checkArgument(
numberOfElements >= 0, "number of elements must be greater than or equal to zero");
// don't do any skipping if numberOfElements is 0
if (numberOfElements == 0) {
return 0;
}
// unless the parser is at one of the specified elements,
// the first call to nextElement() will advance to the first
// element to be skipped
int skipped = 0;
if (isAtElement(uri, name)) {
skipped = 1;
}
while (nextElement(uri, name) && skipped < numberOfElements) {
skipped++;
}
return skipped;
}
/**
* Advances parser to the next contact element.
*
* <p>The parser may skip over other types of elements while advancing to the next contact
* element.
*
* @return true if the parser advanced to a contact element, false otherwise
*/
public boolean nextContact() {
return nextElement(RDE_CONTACT_URI, "contact");
}
/**
* Checks if the parser is at a contact element.
*
* @return true if the parser is at a contact element, false otherwise
*/
public boolean isAtContact() {
return isAtElement(RDE_CONTACT_URI, "contact");
}
/**
* Attempts to skip over a number of contacts.
*
* <p>If the parser is not currently at a contact element, it will advance to the next instance
* before skipping any.
*
* <p>In the process of skipping over a contact element, other elements may be skipped as well.
* Elements of types other than contact elements will not be counted.
*
* @return Number of contact elements that were skipped
*/
public int skipContacts(int numberOfContacts) {
return skipElements(numberOfContacts, RDE_CONTACT_URI, "contact");
}
/**
* Gets the current contact.
*
* <p>The parser must be at a contact element before this method is called, or an
* {@link IllegalStateException} will be thrown. Check the return value of {@link #isAtContact} or
* {@link #nextContact} to determine if the parser is at a contact element.
*
* @return Jaxb Contact
* @throws IllegalStateException if the parser is not at a contact element
*/
public XjcRdeContact getContact() {
XjcRdeContactElement element =
(XjcRdeContactElement) unmarshalElement(RDE_CONTACT_URI, "contact");
return element.getValue();
}
/**
* Advances parser to the next domain element.
*
* <p>The parser may skip over other types of elements while advancing to the next domain element.
*
* @return true if the parser advanced to a domain element, false otherwise
*/
public boolean nextDomain() {
return nextElement(RDE_DOMAIN_URI, "domain");
}
/**
* Checks if the parser is at a domain element.
*
* @return true if the parser is at a domain element, false otherwise
*/
public boolean isAtDomain() {
return isAtElement(RDE_DOMAIN_URI, "domain");
}
/**
* Attempts to skip over a number of domains.
*
* <p>If the parser is not currently at a domain element, it will advance to the next instance
* before skipping any.
*
* <p>In the process of skipping over a domain element, other elements may be skipped as well.
* Elements of types other than domain elements will not be counted.
*
* @return Number of domain elements that were skipped
*/
public int skipDomains(int numberOfDomains) {
return skipElements(numberOfDomains, RDE_DOMAIN_URI, "domain");
}
/**
* Gets the current domain.
*
* <p>The parser must be at a domain element before this method is called, or an
* {@link IllegalStateException} will be thrown. Check the return value of {@link #isAtDomain} or
* {@link #nextDomain} to determine if the parser is at a domain element.
*
* @return Jaxb Domain
* @throws IllegalStateException if the parser is not at a domain element
*/
public XjcRdeDomain getDomain() {
XjcRdeDomainElement element = (XjcRdeDomainElement) unmarshalElement(RDE_DOMAIN_URI, "domain");
return element.getValue();
}
/**
* Advances parser to the next host element.
*
* <p>The parser may skip over other types of elements while advancing to the next host element.
*
* @return true if the parser advanced to a host element, false otherwise
*/
public boolean nextHost() {
return nextElement(RDE_HOST_URI, "host");
}
/**
* Checks if the parser is at a host element.
*
* @return true if the parser is at a host element, false otherwise
*/
public boolean isAtHost() {
return isAtElement(RDE_HOST_URI, "host");
}
/**
* Attempts to skip over a number of hosts.
*
* <p>If the parser is not currently at a host element, it will advance to the next instance
* before skipping any.
*
* <p>In the process of skipping over a host element, other elements may be skipped as well.
* Elements of types other than host elements will not be counted.
*
* @return Number of host elements that were skipped
*/
public int skipHosts(int numberOfHosts) {
return skipElements(numberOfHosts, RDE_HOST_URI, "host");
}
/**
* Gets the current host.
*
* <p>The parser must be at a host element before this method is called, or an
* {@link IllegalStateException} will be thrown. Check the return value of {@link #isAtHost} or
* {@link #nextHost} to determine if the parser is at a host element.
*
* @return Jaxb Host
* @throws IllegalStateException if the parser is not at a host element
*/
public XjcRdeHost getHost() {
XjcRdeHostElement element = (XjcRdeHostElement) unmarshalElement(RDE_HOST_URI, "host");
return element.getValue();
}
/**
* Advances parser to the next registrar element.
*
* <p>The parser may skip over other types of elements while advancing to the next registrar
* element.
*
* @return true if the parser advanced to a registrar element, false otherwise
*/
public boolean nextRegistrar() {
return nextElement(RDE_REGISTRAR_URI, "registrar");
}
/**
* Checks if the parser is at a registrar element.
*
* @return true if the parser is at a registrar element, false otherwise
*/
public boolean isAtRegistrar() {
return isAtElement(RDE_REGISTRAR_URI, "registrar");
}
/**
* Gets the current registrar.
*
* <p>The parser must be at a registrar element before this method is called, or an
* {@link IllegalStateException} will be thrown. Check the return value of {@link #isAtRegistrar}
* or {@link #nextRegistrar} to determine if the parser is at a registrar element.
*
* @return Jaxb Registrar
* @throws IllegalStateException if the parser is not at a registrar element
*/
public XjcRdeRegistrar getRegistrar() {
XjcRdeRegistrarElement element =
(XjcRdeRegistrarElement) unmarshalElement(RDE_REGISTRAR_URI, "registrar");
return element.getValue();
}
/**
* Advances parser to the next IDN element.
*
* <p>The parser may skip over other types of elements while advancing to the next IDN element.
*
* @return true if the parser advanced to a IDN element, false otherwise
*/
public boolean nextIdn() {
return nextElement(RDE_IDN_URI, "idnTableRef");
}
/**
* Checks if the parser is at a IDN element.
*
* @return true if the parser is at a IDN element, false otherwise
*/
public boolean isAtIdn() {
return isAtElement(RDE_IDN_URI, "idnTableRef");
}
/**
* Gets the current IDN.
*
* <p>The parser must be at a IDN element before this method is called, or an
* {@link IllegalStateException} will be thrown. Check the return value of {@link #isAtIdn} or
* {@link #nextIdn} to determine if the parser is at a IDN element.
*
* @return Jaxb IDN
* @throws IllegalStateException if the parser is not at a IDN element
*/
public XjcRdeIdn getIdn() {
XjcRdeIdnElement element = (XjcRdeIdnElement) unmarshalElement(RDE_IDN_URI, "idnTableRef");
return element.getValue();
}
/**
* Advances parser to the next NNDN element.
*
* <p>The parser may skip over other types of elements while advancing to the next NNDN element.
*
* @return true if the parser advanced to a NNDN element, false otherwise
*/
public boolean nextNndn() {
return nextElement(RDE_NNDN_URI, "NNDN");
}
/**
* Checks if the parser is at a NNDN element.
*
* @return true if the parser is at a NNDN element, false otherwise
*/
public boolean isAtNndn() {
return isAtElement(RDE_NNDN_URI, "NNDN");
}
/**
* Gets the current NNDN.
*
* <p>The parser must be at a NNDN element before this method is called, or an
* {@link IllegalStateException} will be thrown. Check the return value of {@link #isAtNndn} or
* {@link #nextNndn} to determine if the parser is at a NNDN element.
*
* @return Jaxb NNDN
* @throws IllegalStateException if the parser is not at a NNDN element
*/
public XjcRdeNndn getNndn() {
XjcRdeNndnElement element = (XjcRdeNndnElement) unmarshalElement(RDE_NNDN_URI, "NNDN");
return element.getValue();
}
/**
* Advances parser to the next eppParams element.
*
* <p>The parser may skip over other types of elements while advancing to the next eppParams
* element.
*
* @return true if the parser advanced to a eppParams element, false otherwise
*/
public boolean nextEppParams() {
return nextElement(RDE_EPP_PARAMS_URI, "eppParams");
}
/**
* Checks if the parser is at a eppParams element.
*
* @return true if the parser is at a eppParams element, false otherwise
*/
public boolean isAtEppParams() {
return isAtElement(RDE_EPP_PARAMS_URI, "eppParams");
}
/**
* Gets the current eppParams.
*
* <p>The parser must be at a eppParams element before this method is called, or an
* {@link IllegalStateException} will be thrown. Check the return value of {@link #isAtEppParams}
* or {@link #nextEppParams} to determine if the parser is at a eppParams element.
*
* @return Jaxb EppParams
* @throws IllegalStateException if the parser is not at a eppParams element
*/
public XjcRdeEppParams getEppParams() {
XjcRdeEppParamsElement element =
(XjcRdeEppParamsElement) unmarshalElement(RDE_EPP_PARAMS_URI, "eppParams");
return element.getValue();
}
}

View file

@ -455,3 +455,9 @@ def domain_registry_repositories():
artifact = "com.google.truth:truth:0.28",
sha1 = "0a388c7877c845ff4b8e19689dda5ac9d34622c4",
)
native.maven_jar(
name = "stax2_api",
artifact = "org.codehaus.woodstox:stax2-api:3.1.4",
sha1 = "ac19014b1e6a7c08aad07fe114af792676b685b7",
)

View file

@ -0,0 +1,482 @@
// Copyright 2016 The Domain Registry 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.rde;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.io.ByteSource;
import google.registry.rde.RdeParser.RdeHeader;
import google.registry.testing.ExceptionRule;
import google.registry.xjc.rdecontact.XjcRdeContact;
import google.registry.xjc.rdedomain.XjcRdeDomain;
import google.registry.xjc.rdeeppparams.XjcRdeEppParams;
import google.registry.xjc.rdehost.XjcRdeHost;
import google.registry.xjc.rdeidn.XjcRdeIdn;
import google.registry.xjc.rdenndn.XjcRdeNndn;
import google.registry.xjc.rderegistrar.XjcRdeRegistrar;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
/** Unit tests for {@link RdeParser}. */
@RunWith(JUnit4.class)
public class RdeParserTest {
private static final ByteSource DEPOSIT_XML = RdeTestData.get("deposit_full_parser.xml");
private InputStream xml;
@Rule
public final ExceptionRule thrown = new ExceptionRule();
private void checkHeader(RdeHeader header) {
assertThat(header.getTld()).isEqualTo("test");
assertThat(header.getContactCount()).isEqualTo(1L);
assertThat(header.getDomainCount()).isEqualTo(2L);
assertThat(header.getEppParamsCount()).isEqualTo(1L);
assertThat(header.getHostCount()).isEqualTo(1L);
assertThat(header.getIdnCount()).isEqualTo(1L);
assertThat(header.getNndnCount()).isEqualTo(1L);
assertThat(header.getRegistrarCount()).isEqualTo(1L);
}
@Before
public void before() throws IOException {
xml = new ByteArrayInputStream(DEPOSIT_XML.read());
}
@After
public void after() throws IOException {
xml.close();
}
@Test
public void testGetHeader_returnsHeader() throws Exception {
RdeParser parser = new RdeParser(xml);
checkHeader(parser.getHeader());
}
@Test
public void testGetContactNotAtElement_throwsIllegalStateException() throws Exception {
thrown.expect(IllegalStateException.class,
"Not at element urn:ietf:params:xml:ns:rdeContact-1.0:contact");
RdeParser parser = new RdeParser(xml);
parser.getContact();
}
@Test
public void testGetContactAtElement_returnsContact() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextContact();
XjcRdeContact contact = parser.getContact();
assertThat(contact.getId()).isEqualTo("sh8013");
assertThat(contact.getClID()).isEqualTo("RegistrarX");
}
@Test
public void testNextContact_advancesParser() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.isAtContact()).isFalse();
// there is only one contact in the escrow file
assertThat(parser.nextContact()).isTrue();
assertThat(parser.isAtContact()).isTrue();
assertThat(parser.nextContact()).isFalse();
assertThat(parser.isAtContact()).isFalse();
}
@Test
public void testSkipZeroContacts_skipsZero() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.skipContacts(0)).isEqualTo(0);
assertThat(parser.nextContact()).isTrue();
}
@Test
public void testSkipOneContactFromBeginning_skipsOne() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.skipContacts(1)).isEqualTo(1);
assertThat(parser.isAtContact()).isFalse();
}
@Test
public void testSkipOneContactFromFirstContact_skipsOne() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextContact();
assertThat(parser.skipContacts(1)).isEqualTo(1);
assertThat(parser.isAtContact()).isFalse();
}
@Test
public void testSkip9999Contacts_skipsOne() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.skipContacts(9999)).isEqualTo(1);
assertThat(parser.isAtContact()).isFalse();
}
@Test
public void testSkipContactsFromEnd_skipsZero() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextContact();
parser.nextContact();
assertThat(parser.skipContacts(1)).isEqualTo(0);
assertThat(parser.isAtContact()).isFalse();
}
@Test
public void testGetHeaderAfterNextContact_returnsHeader() throws Exception {
// verify that the header is still available after advancing to next contact
RdeParser parser = new RdeParser(xml);
parser.nextContact();
checkHeader(parser.getHeader());
}
@Test
public void testGetDomainNotAtElement_throwsIllegalStateException() throws Exception {
thrown.expect(IllegalStateException.class,
"Not at element urn:ietf:params:xml:ns:rdeDomain-1.0:domain");
RdeParser parser = new RdeParser(xml);
parser.getDomain();
}
@Test
public void testGetDomainAtElement_returnsDomain() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextDomain();
XjcRdeDomain domain = parser.getDomain();
assertThat(domain.getName()).isEqualTo("example1.test");
}
@Test
public void testNextDomain_advancesParser() throws Exception {
RdeParser parser = new RdeParser(xml);
// there are 2 domains in the escrow file
assertThat(parser.isAtDomain()).isFalse();
assertThat(parser.nextDomain()).isTrue();
assertThat(parser.isAtDomain()).isTrue();
assertThat(parser.nextDomain()).isTrue();
assertThat(parser.isAtDomain()).isTrue();
assertThat(parser.nextDomain()).isFalse();
assertThat(parser.isAtDomain()).isFalse();
}
@Test
public void testSkipZeroDomains_skipsZero() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.skipDomains(0)).isEqualTo(0);
assertThat(parser.nextDomain()).isTrue();
}
@Test
public void testSkipOneDomainFromBeginning_skipsOne() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.skipDomains(1)).isEqualTo(1);
// there are two domains
assertThat(parser.isAtDomain()).isTrue();
// prove that the parser advanced to the second domain
assertThat(parser.nextDomain()).isFalse();
assertThat(parser.isAtDomain()).isFalse();
}
@Test
public void testSkipTwoDomainsFromBeginning_skipsTwo() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.skipDomains(2)).isEqualTo(2);
// there are two domains
assertThat(parser.isAtDomain()).isFalse();
}
@Test
public void testSkipOneDomainFromFirstDomain_skipsOne() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextDomain();
assertThat(parser.skipDomains(1)).isEqualTo(1);
// there are two domains
assertThat(parser.isAtDomain()).isTrue();
// prove that the parser advanced to the second domain
assertThat(parser.nextDomain()).isFalse();
assertThat(parser.isAtDomain()).isFalse();
}
@Test
public void testSkipTwoDomainsFromFirstDomain_skipsTwo() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextDomain();
assertThat(parser.skipDomains(2)).isEqualTo(2);
// there are two domains
assertThat(parser.isAtDomain()).isFalse();
}
@Test
public void testSkip9999Domains_skipsTwo() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.skipDomains(9999)).isEqualTo(2);
assertThat(parser.isAtDomain()).isFalse();
}
@Test
public void testSkipDomainsFromEnd_skipsZero() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextDomain();
parser.nextDomain();
parser.nextDomain();
assertThat(parser.skipDomains(1)).isEqualTo(0);
}
@Test
public void testGetHeaderAfterNextDomain_returnsHeader() throws Exception {
// verify that the header is still available after advancing to next domain
RdeParser parser = new RdeParser(xml);
parser.nextDomain();
checkHeader(parser.getHeader());
}
@Test
public void testGetHostNotAtElement_throwsIllegalStateException() throws Exception {
thrown.expect(IllegalStateException.class,
"Not at element urn:ietf:params:xml:ns:rdeHost-1.0:host");
RdeParser parser = new RdeParser(xml);
parser.getHost();
}
@Test
public void testGetHostAtElement_returnsHost() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextHost();
XjcRdeHost host = parser.getHost();
assertThat(host.getName()).isEqualTo("ns1.example.com");
}
@Test
public void testNextHost_advancesParser() throws Exception {
// the header lies, there are 2 hosts in the file
RdeParser parser = new RdeParser(xml);
assertThat(parser.isAtHost()).isFalse();
assertThat(parser.nextHost()).isTrue();
assertThat(parser.isAtHost()).isTrue();
assertThat(parser.nextHost()).isTrue();
assertThat(parser.isAtHost()).isTrue();
assertThat(parser.nextHost()).isFalse();
assertThat(parser.isAtHost()).isFalse();
}
@Test
public void testSkipZeroHosts_skipsZero() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.skipHosts(0)).isEqualTo(0);
assertThat(parser.nextHost()).isTrue();
}
@Test
public void testSkipOneHostFromBeginning_skipsOne() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.skipHosts(1)).isEqualTo(1);
// there are two hosts
assertThat(parser.isAtHost()).isTrue();
// prove that the parser advanced to the second host
assertThat(parser.nextHost()).isFalse();
assertThat(parser.isAtHost()).isFalse();
}
@Test
public void testSkipTwoHostsFromBeginning_skipsTwo() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.skipHosts(2)).isEqualTo(2);
// there are two hosts
assertThat(parser.isAtHost()).isFalse();
}
@Test
public void testSkipOneHostFromFirstHost_skipsOne() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextHost();
assertThat(parser.skipHosts(1)).isEqualTo(1);
// there are two hosts
assertThat(parser.isAtHost()).isTrue();
// prove that the parser advanced to the second host
assertThat(parser.nextHost()).isFalse();
assertThat(parser.isAtHost()).isFalse();
}
@Test
public void testSkipTwoHostsFromFirstHost_skipsTwo() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextHost();
assertThat(parser.skipHosts(2)).isEqualTo(2);
// there are two hosts
assertThat(parser.isAtHost()).isFalse();
}
@Test
public void testSkip9999Hosts_skipsTwo() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.skipHosts(9999)).isEqualTo(2);
// there are two hosts
assertThat(parser.isAtHost()).isFalse();
}
@Test
public void testSkipHostFromEnd_skipsZero() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextHost();
parser.nextHost();
parser.nextHost();
assertThat(parser.skipHosts(1)).isEqualTo(0);
}
@Test
public void testGetHeaderAfterNextHost_returnsHeader() throws Exception {
// verify that the header is still available after advancing to next host
RdeParser parser = new RdeParser(xml);
parser.nextHost();
checkHeader(parser.getHeader());
}
@Test
public void testGetRegistrarNotAtElement_throwsIllegalStateException() throws Exception {
thrown.expect(IllegalStateException.class,
"Not at element urn:ietf:params:xml:ns:rdeRegistrar-1.0:registrar");
RdeParser parser = new RdeParser(xml);
parser.getRegistrar();
}
@Test
public void testGetRegistrarAtElement_returnsRegistrar() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextRegistrar();
XjcRdeRegistrar registrar = parser.getRegistrar();
assertThat(registrar.getId()).isEqualTo("RegistrarX");
assertThat(registrar.getName()).isEqualTo("Registrar X");
}
@Test
public void testNextRegistrar_advancesParser() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.isAtRegistrar()).isFalse();
assertThat(parser.nextRegistrar()).isTrue();
assertThat(parser.isAtRegistrar()).isTrue();
assertThat(parser.nextRegistrar()).isFalse();
assertThat(parser.isAtRegistrar()).isFalse();
}
@Test
public void testGetHeaderAfterNextRegistrar_returnsHeader() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextRegistrar();
checkHeader(parser.getHeader());
}
@Test
public void testGetNndnNotAtElement_throwsIllegalStateException() throws Exception {
thrown.expect(IllegalStateException.class,
"Not at element urn:ietf:params:xml:ns:rdeNNDN-1.0:NNDN");
RdeParser parser = new RdeParser(xml);
parser.getNndn();
}
@Test
public void testGetNndnAtElement_returnsNndn() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextNndn();
XjcRdeNndn nndn = parser.getNndn();
assertThat(nndn.getAName()).isEqualTo("xn--exampl-gva.test");
}
@Test
public void testNextNndn_advancesParser() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.isAtNndn()).isFalse();
assertThat(parser.nextNndn()).isTrue();
assertThat(parser.isAtNndn()).isTrue();
assertThat(parser.nextNndn()).isFalse();
assertThat(parser.isAtNndn()).isFalse();
}
@Test
public void testGetHeaderAfterNextNndn_returnsHeader() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextNndn();
checkHeader(parser.getHeader());
}
@Test
public void testGetIdnNotAtElement_throwsIllegalStateException() throws Exception {
thrown.expect(IllegalStateException.class,
"Not at element urn:ietf:params:xml:ns:rdeIDN-1.0:idnTableRef");
RdeParser parser = new RdeParser(xml);
parser.getIdn();
}
@Test
public void testGetIdnAtElement_returnsIdn() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextIdn();
XjcRdeIdn idn = parser.getIdn();
// url contains whitespace
assertThat(idn.getUrl().trim())
.isEqualTo("http://www.iana.org/domains/idn-tables/tables/br_pt-br_1.0.html");
}
@Test
public void testNextIdn_advancesParser() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.isAtIdn()).isFalse();
assertThat(parser.nextIdn()).isTrue();
assertThat(parser.isAtIdn()).isTrue();
assertThat(parser.nextIdn()).isFalse();
assertThat(parser.isAtIdn()).isFalse();
}
@Test
public void testGetHeaderAfterNextIdn_returnsHeader() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextIdn();
checkHeader(parser.getHeader());
}
@Test
public void testGetEppParamsNotAtElement_throwsIllegalStateException() throws Exception {
thrown.expect(IllegalStateException.class,
"Not at element urn:ietf:params:xml:ns:rdeEppParams-1.0:eppParams");
RdeParser parser = new RdeParser(xml);
parser.getEppParams();
}
@Test
public void testGetEppParamsAtElement_returnsEppParams() throws Exception {
RdeParser parser = new RdeParser(xml);
parser.nextEppParams();
XjcRdeEppParams eppParams = parser.getEppParams();
assertThat(eppParams.getVersions()).containsExactly("1.0");
}
@Test
public void testNextEppParamsAdvancesParser() throws Exception {
RdeParser parser = new RdeParser(xml);
assertThat(parser.isAtEppParams()).isFalse();
assertThat(parser.nextEppParams()).isTrue();
assertThat(parser.isAtEppParams()).isTrue();
assertThat(parser.nextEppParams()).isFalse();
assertThat(parser.isAtEppParams()).isFalse();
}
}

View file

@ -0,0 +1,259 @@
<?xml version="1.0" encoding="UTF-8"?>
<rde:deposit type="FULL" id="20101017001" prevId="20101010001"
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0"
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0"
xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1"
xmlns:rde="urn:ietf:params:xml:ns:rde-1.0"
xmlns:rdeHeader="urn:ietf:params:xml:ns:rdeHeader-1.0"
xmlns:rdeDom="urn:ietf:params:xml:ns:rdeDomain-1.0"
xmlns:rdeHost="urn:ietf:params:xml:ns:rdeHost-1.0"
xmlns:rdeContact="urn:ietf:params:xml:ns:rdeContact-1.0"
xmlns:rdeRegistrar="urn:ietf:params:xml:ns:rdeRegistrar-1.0"
xmlns:rdeIDN="urn:ietf:params:xml:ns:rdeIDN-1.0"
xmlns:rdeNNDN="urn:ietf:params:xml:ns:rdeNNDN-1.0"
xmlns:rdeEppParams="urn:ietf:params:xml:ns:rdeEppParams-1.0"
xmlns:rdePolicy="urn:ietf:params:xml:ns:rdePolicy-1.0"
xmlns:epp="urn:ietf:params:xml:ns:epp-1.0">
<rde:watermark>2010-10-17T00:00:00Z</rde:watermark>
<rde:rdeMenu>
<rde:version>1.0</rde:version>
<rde:objURI>urn:ietf:params:xml:ns:rdeHeader-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeContact-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeHost-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeDomain-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeRegistrar-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeIDN-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeNNDN-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeEppParams-1.0</rde:objURI>
</rde:rdeMenu>
<!-- Contents -->
<rde:contents>
<!-- Header -->
<rdeHeader:header>
<rdeHeader:tld>test</rdeHeader:tld>
<rdeHeader:count
uri="urn:ietf:params:xml:ns:rdeDomain-1.0">2
</rdeHeader:count>
<rdeHeader:count
uri="urn:ietf:params:xml:ns:rdeHost-1.0">1
</rdeHeader:count>
<rdeHeader:count
uri="urn:ietf:params:xml:ns:rdeContact-1.0">1
</rdeHeader:count>
<rdeHeader:count
uri="urn:ietf:params:xml:ns:rdeRegistrar-1.0">1
</rdeHeader:count>
<rdeHeader:count
uri="urn:ietf:params:xml:ns:rdeIDN-1.0">1
</rdeHeader:count>
<rdeHeader:count
uri="urn:ietf:params:xml:ns:rdeNNDN-1.0">1
</rdeHeader:count>
<rdeHeader:count
uri="urn:ietf:params:xml:ns:rdeEppParams-1.0">1
</rdeHeader:count>
</rdeHeader:header>
<!-- Domain: example1.test -->
<rdeDom:domain>
<rdeDom:name>example1.test</rdeDom:name>
<rdeDom:roid>Dexample1-TEST</rdeDom:roid>
<rdeDom:status s="ok"/>
<rdeDom:registrant>jd1234</rdeDom:registrant>
<rdeDom:contact type="admin">sh8013</rdeDom:contact>
<rdeDom:contact type="tech">sh8013</rdeDom:contact>
<rdeDom:ns>
<domain:hostObj>ns1.example.com</domain:hostObj>
<domain:hostObj>ns1.example1.test</domain:hostObj>
</rdeDom:ns>
<rdeDom:clID>RegistrarX</rdeDom:clID>
<rdeDom:crRr client="jdoe">RegistrarX</rdeDom:crRr>
<rdeDom:crDate>1999-04-03T22:00:00.0Z</rdeDom:crDate>
<rdeDom:exDate>2015-04-03T22:00:00.0Z</rdeDom:exDate>
</rdeDom:domain>
<!-- Domain: example2.test -->
<rdeDom:domain>
<rdeDom:name>example2.test</rdeDom:name>
<rdeDom:roid>Dexample2-TEST</rdeDom:roid>
<rdeDom:status s="ok"/>
<rdeDom:status s="clientUpdateProhibited"/>
<rdeDom:registrant>jd1234</rdeDom:registrant>
<rdeDom:contact type="admin">sh8013</rdeDom:contact>
<rdeDom:contact type="tech">sh8013</rdeDom:contact>
<rdeDom:clID>RegistrarX</rdeDom:clID>
<rdeDom:crRr>RegistrarX</rdeDom:crRr>
<rdeDom:crDate>1999-04-03T22:00:00.0Z</rdeDom:crDate>
<rdeDom:exDate>2015-04-03T22:00:00.0Z</rdeDom:exDate>
</rdeDom:domain>
<!-- Host: ns1.example.com -->
<rdeHost:host>
<rdeHost:name>ns1.example.com</rdeHost:name>
<rdeHost:roid>Hns1_example_com-TEST</rdeHost:roid>
<rdeHost:status s="ok"/>
<rdeHost:status s="linked"/>
<rdeHost:addr ip="v4">192.0.2.2</rdeHost:addr>
<rdeHost:addr ip="v4">192.0.2.29</rdeHost:addr>
<rdeHost:addr ip="v6">1080:0:0:0:8:800:200C:417A
</rdeHost:addr>
<rdeHost:clID>RegistrarX</rdeHost:clID>
<rdeHost:crRr>RegistrarX</rdeHost:crRr>
<rdeHost:crDate>1999-05-08T12:10:00.0Z</rdeHost:crDate>
<rdeHost:upRr>RegistrarX</rdeHost:upRr>
<rdeHost:upDate>2009-10-03T09:34:00.0Z</rdeHost:upDate>
</rdeHost:host>
<!-- Host: ns1.example1.test -->
<rdeHost:host>
<rdeHost:name>ns1.example1.test</rdeHost:name>
<rdeHost:roid>Hns1_example1_test-TEST</rdeHost:roid>
<rdeHost:status s="ok"/>
<rdeHost:status s="linked"/>
<rdeHost:addr ip="v4">192.0.2.2</rdeHost:addr>
<rdeHost:addr ip="v4">192.0.2.29</rdeHost:addr>
<rdeHost:addr ip="v6">1080:0:0:0:8:800:200C:417A
</rdeHost:addr>
<rdeHost:clID>RegistrarX</rdeHost:clID>
<rdeHost:crRr>RegistrarX</rdeHost:crRr>
<rdeHost:crDate>1999-05-08T12:10:00.0Z</rdeHost:crDate>
<rdeHost:upRr>RegistrarX</rdeHost:upRr>
<rdeHost:upDate>2009-10-03T09:34:00.0Z</rdeHost:upDate>
</rdeHost:host>
<!-- Contact: sh8013 -->
<rdeContact:contact>
<rdeContact:id>sh8013</rdeContact:id>
<rdeContact:roid>Csh8013-TEST</rdeContact:roid>
<rdeContact:status s="linked"/>
<rdeContact:status s="clientDeleteProhibited"/>
<rdeContact:postalInfo type="int">
<contact:name>John Doe</contact:name>
<contact:org>Example Inc.</contact:org>
<contact:addr>
<contact:street>123 Example Dr.</contact:street>
<contact:street>Suite 100</contact:street>
<contact:city>Dulles</contact:city>
<contact:sp>VA</contact:sp>
<contact:pc>20166-6503</contact:pc>
<contact:cc>US</contact:cc>
</contact:addr>
</rdeContact:postalInfo>
<rdeContact:voice x="1234">+1.7035555555
</rdeContact:voice>
<rdeContact:fax>+1.7035555556
</rdeContact:fax>
<rdeContact:email>jdoe@example.test
</rdeContact:email>
<rdeContact:clID>RegistrarX</rdeContact:clID>
<rdeContact:crRr client="jdoe">RegistrarX
</rdeContact:crRr>
<rdeContact:crDate>2009-09-13T08:01:00.0Z</rdeContact:crDate>
<rdeContact:upRr client="jdoe">RegistrarX
</rdeContact:upRr>
<rdeContact:upDate>2009-11-26T09:10:00.0Z</rdeContact:upDate>
<rdeContact:trDate>2009-12-03T09:05:00.0Z</rdeContact:trDate>
<rdeContact:disclose flag="0">
<contact:voice/>
<contact:email/>
</rdeContact:disclose>
</rdeContact:contact>
<!-- Registrar: RegistrarX -->
<rdeRegistrar:registrar>
<rdeRegistrar:id>RegistrarX</rdeRegistrar:id>
<rdeRegistrar:name>Registrar X</rdeRegistrar:name>
<rdeRegistrar:gurid>123</rdeRegistrar:gurid>
<rdeRegistrar:status>ok</rdeRegistrar:status>
<rdeRegistrar:postalInfo type="int">
<rdeRegistrar:addr>
<rdeRegistrar:street>123 Example Dr.
</rdeRegistrar:street>
<rdeRegistrar:street>Suite 100
</rdeRegistrar:street>
<rdeRegistrar:city>Dulles</rdeRegistrar:city>
<rdeRegistrar:sp>VA</rdeRegistrar:sp>
<rdeRegistrar:pc>20166-6503</rdeRegistrar:pc>
<rdeRegistrar:cc>US</rdeRegistrar:cc>
</rdeRegistrar:addr>
</rdeRegistrar:postalInfo>
<rdeRegistrar:voice x="1234">+1.7035555555
</rdeRegistrar:voice>
<rdeRegistrar:fax>+1.7035555556
</rdeRegistrar:fax>
<rdeRegistrar:email>jdoe@example.test
</rdeRegistrar:email>
<rdeRegistrar:url>http://www.example.test
</rdeRegistrar:url>
<rdeRegistrar:whoisInfo>
<rdeRegistrar:name>whois.example.test
</rdeRegistrar:name>
<rdeRegistrar:url>http://whois.example.test
</rdeRegistrar:url>
</rdeRegistrar:whoisInfo>
<rdeRegistrar:crDate>2005-04-23T11:49:00.0Z</rdeRegistrar:crDate>
<rdeRegistrar:upDate>2009-02-17T17:51:00.0Z</rdeRegistrar:upDate>
</rdeRegistrar:registrar>
<!-- IDN Table -->
<rdeIDN:idnTableRef id="pt-BR">
<rdeIDN:url>
http://www.iana.org/domains/idn-tables/tables/br_pt-br_1.0.html
</rdeIDN:url>
<rdeIDN:urlPolicy>
http://registro.br/dominio/regras.html
</rdeIDN:urlPolicy>
</rdeIDN:idnTableRef>
<!-- NNDN: pinguino.test -->
<rdeNNDN:NNDN>
<rdeNNDN:aName>xn--exampl-gva.test</rdeNNDN:aName>
<rdeNNDN:idnTableId>pt-BR</rdeNNDN:idnTableId>
<rdeNNDN:originalName>example1.test</rdeNNDN:originalName>
<rdeNNDN:nameState>withheld</rdeNNDN:nameState>
<rdeNNDN:crDate>2005-04-23T11:49:00.0Z</rdeNNDN:crDate>
</rdeNNDN:NNDN>
<!-- EppParams -->
<rdeEppParams:eppParams>
<rdeEppParams:version>1.0</rdeEppParams:version>
<rdeEppParams:lang>en</rdeEppParams:lang>
<rdeEppParams:objURI>
urn:ietf:params:xml:ns:domain-1.0
</rdeEppParams:objURI>
<rdeEppParams:objURI>
urn:ietf:params:xml:ns:contact-1.0
</rdeEppParams:objURI>
<rdeEppParams:objURI>
urn:ietf:params:xml:ns:host-1.0
</rdeEppParams:objURI>
<rdeEppParams:svcExtension>
<epp:extURI>urn:ietf:params:xml:ns:rgp-1.0
</epp:extURI>
<epp:extURI>urn:ietf:params:xml:ns:secDNS-1.1
</epp:extURI>
</rdeEppParams:svcExtension>
<rdeEppParams:dcp>
<epp:access><epp:all/></epp:access>
<epp:statement>
<epp:purpose>
<epp:admin/>
<epp:prov/>
</epp:purpose>
<epp:recipient>
<epp:ours/>
<epp:public/>
</epp:recipient>
<epp:retention>
<epp:stated/>
</epp:retention>
</epp:statement>
</rdeEppParams:dcp>
</rdeEppParams:eppParams>
<rdePolicy:policy
scope="//rde:deposit/rde:contents/rdeDomain:domain"
element="rdeDom:registrant" />
</rde:contents>
</rde:deposit>