package com.cloudhopper.commons.xbean; /* * #%L * ch-commons-xbean * %% * Copyright (C) 2012 Cloudhopper by Twitter * %% * 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. * #L% */ // third party imports import java.io.ByteArrayInputStream; import java.net.MalformedURLException; import java.net.URL; import org.junit.*; import org.apache.log4j.Logger; // my imports import com.cloudhopper.commons.xml.*; public class XmlBeanTest { private static final Logger logger = Logger.getLogger(XmlBeanTest.class); @Test public void configureSimpleProperties() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) // NOTE: leave out xml version on purpose since it should have // no effect on processing the configuration file //.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <port>80</port>\n") .append(" <host>www.google.com</host>\n") .append(" <url>http://www.google.com/</url>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure SimpleConfiguration config = new SimpleConfiguration(); // configure it using default options XmlBean bean = new XmlBean(); bean.configure(rootNode, config); // confirm properties Assert.assertNull(config.size); Assert.assertEquals(80, config.port); Assert.assertEquals("www.google.com", config.host); Assert.assertEquals("http://www.google.com/", config.url); } @Test(expected=RootTagMismatchException.class) public void configureThrowRootTagMismatchException() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure SimpleConfiguration config = new SimpleConfiguration(); // configure it using default options XmlBean bean = new XmlBean(); // this should cause a check of what the root tag actually is bean.setRootTag("configuration2"); bean.configure(rootNode, config); } @Test(expected=PropertyNotFoundException.class) public void configureThrowPropertyNotFoundException() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <port2>80</port2>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure SimpleConfiguration config = new SimpleConfiguration(); // configure it using default options XmlBean bean = new XmlBean(); bean.configure(rootNode, config); } @Test(expected=PropertyPermissionException.class) public void configureThrowPropertyPermissionException() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <size>80</size>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure SimpleConfiguration config = new SimpleConfiguration(); // configure it using default options XmlBean bean = new XmlBean(); bean.configure(rootNode, config); } @Test(expected=PropertyIsEmptyException.class) public void configureThrowPropertyIsEmptyException() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <port></port>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure SimpleConfiguration config = new SimpleConfiguration(); // configure it using default options XmlBean bean = new XmlBean(); bean.configure(rootNode, config); } @Test(expected=PropertyConversionException.class) public void configureThrowPropertyConversionException() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <port>joe</port>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure SimpleConfiguration config = new SimpleConfiguration(); // configure it using default options XmlBean bean = new XmlBean(); bean.configure(rootNode, config); } @Test(expected=PropertyInvocationException.class) public void configureThrowPropertyInvocationException() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <port>-1</port>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure SimpleConfiguration config = new SimpleConfiguration(); // configure it using default options XmlBean bean = new XmlBean(); bean.configure(rootNode, config); } @Test public void configureWithAccessPrivateProperties() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <size>80</size>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure SimpleConfiguration config = new SimpleConfiguration(); // configure it using default options XmlBean bean = new XmlBean(); // setting this to true allows access to internal private properties // that normally aren't allowed to be set bean.setAccessPrivateProperties(true); bean.configure(rootNode, config); // confirm properties Assert.assertEquals(new Integer(80), config.size); Assert.assertEquals(0, config.port); Assert.assertNull(config.host); Assert.assertNull(config.url); } @Test public void configureComplex() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <server>\n") .append(" <port>80</port>\n") .append(" <host>www.google.com</host>\n") .append(" </server>\n") .append(" <url>http://www.google.com/</url>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure ComplexConfiguration config = new ComplexConfiguration(); Assert.assertNull(config.getServer()); Assert.assertNull(config.url); // configure it using default options XmlBean bean = new XmlBean(); bean.configure(rootNode, config); // confirm properties Assert.assertNotNull(config.getServer()); Assert.assertEquals("http://www.google.com/", config.url); Assert.assertEquals(80, config.getServer().port); Assert.assertEquals("www.google.com", config.getServer().host); } @Test public void configureComplexWithProvidedInstance() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <server>\n") .append(" <host>www.google.com</host>\n") .append(" </server>\n") .append(" <url>http://www.google.com/</url>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure ComplexConfiguration config = new ComplexConfiguration(); // create our own server instance though, configure() method should try // try to "get" it first to configure it Server server = new Server(); server.setPort(80); config.setServer(server); config.setUrl("http://www.abc.com/"); // configure it using default options XmlBean bean = new XmlBean(); bean.configure(rootNode, config); // confirm properties Assert.assertSame(server, config.getServer()); Assert.assertEquals("http://www.google.com/", config.url); Assert.assertEquals(80, config.getServer().port); Assert.assertEquals("www.google.com", config.getServer().host); } @Test public void configureComplexNoChildProperties() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <server />\n") .append(" <url>http://www.google.com/</url>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure ComplexConfiguration config = new ComplexConfiguration(); Assert.assertNull(config.getServer()); Assert.assertNull(config.url); // configure it using default options XmlBean bean = new XmlBean(); bean.configure(rootNode, config); // confirm properties Assert.assertNotNull(config.getServer()); Assert.assertEquals("http://www.google.com/", config.url); Assert.assertEquals(0, config.getServer().port); Assert.assertEquals(null, config.getServer().host); } @Test(expected=PropertyNotFoundException.class) public void configureComplexWithPropertyNotFoundException() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <server>\n") .append(" <port2>80</port2>\n") .append(" </server>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure ComplexConfiguration config = new ComplexConfiguration(); // configure it using default options XmlBean bean = new XmlBean(); bean.configure(rootNode, config); } /** * Xbean attempts to create a new instance of a class that doesn't have * any empty constructor. Causes an instantiation exception to be thrown. */ @Test(expected=XmlBeanClassException.class) public void configureComplexWithBadConstructor() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <complexServer />\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure ComplexConfiguration config = new ComplexConfiguration(); // configure it using default options XmlBean bean = new XmlBean(); bean.setAccessPrivateProperties(true); bean.configure(rootNode, config); } /** * Tests whether failure to successfully configure a child complex object * ensures that it isn't set on a property in the root object. Basically, * ensures that configuring child objects are sort of "atomic". */ @Test public void configureComplexWithPropertyNotFoundExceptionEnsureOnlyOnePropertyChanged() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <url>http://www.google.com/</url>\n") .append(" <server>\n") .append(" <host>www2.google.com</host>\n") // this should be changed since server reference already existed .append(" <port2>80</port2>\n") // this should cause an error to be thrown .append(" </server>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure ComplexConfiguration config = new ComplexConfiguration(); Server server = new Server(); config.setServer(server); server.setHost("www.google.com"); server.setPort(443); // configure it using default options XmlBean bean = new XmlBean(); try { bean.configure(rootNode, config); Assert.fail("Configure should have failed"); } catch (XmlBeanException e) { // ignore it } // server should remain the same Assert.assertSame(server, config.getServer()); Assert.assertEquals("http://www.google.com/", config.url); Assert.assertEquals(443, config.getServer().port); // this property should have changed since "server" was already stored in main config object Assert.assertEquals("www2.google.com", config.getServer().host); } /** * Tests if failing to configure a child complex object causes a new reference * to never be saved on the parent object. Different from previous test * since a new instance was created and configured and then NOT saved. */ @Test public void configureComplexWithPropertyNotFoundExceptionEnsureNoPropertiesChanged() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <url>http://www.google.com/</url>\n") .append(" <server>\n") .append(" <host>www2.google.com</host>\n") // this should be changed .append(" <port2>80</port2>\n") // this should cause an error to be thrown and caused "server" to not be saved .append(" </server>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure ComplexConfiguration config = new ComplexConfiguration(); // configure it using default options XmlBean bean = new XmlBean(); try { bean.configure(rootNode, config); Assert.fail("Configure should have failed"); } catch (XmlBeanException e) { // ignore it } // server should remain the same Assert.assertNull(config.getServer()); Assert.assertEquals("http://www.google.com/", config.url); } @Test(expected=PropertyNoAttributesExpectedException.class) public void configureNoAttributesExpectedInRootNode() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration id=\"stratus\">\n") // should cause exception .append(" <port>80</port>\n") .append(" <host>www.google.com</host>\n") .append(" <url>http://www.google.com/</url>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure SimpleConfiguration config = new SimpleConfiguration(); // configure it using default options XmlBean bean = new XmlBean(); bean.configure(rootNode, config); } @Test(expected=PropertyNoAttributesExpectedException.class) public void configureNoAttributesExpectedInProperty() throws Exception { // build xml StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <port>80</port>\n") .append(" <host id=\"1\">www.google.com</host>\n") // should cause exception .append(" <url>http://www.google.com/</url>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure SimpleConfiguration config = new SimpleConfiguration(); // configure it using default options XmlBean bean = new XmlBean(); bean.configure(rootNode, config); } @Test public void configureComplexTwice() throws Exception { // build xml once StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <server>\n") .append(" <port>80</port>\n") .append(" <host>www.google.com</host>\n") .append(" </server>\n") .append(" <url>http://www.google.com/</url>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure ComplexConfiguration config = new ComplexConfiguration(); // configure it using default options XmlBean bean = new XmlBean(); bean.configure(rootNode, config); // confirm properties Assert.assertNotNull(config.getServer()); Assert.assertEquals("http://www.google.com/", config.url); Assert.assertEquals(80, config.getServer().port); Assert.assertEquals("www.google.com", config.getServer().host); // build xml override some properties StringBuilder string1 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <server>\n") .append(" <port>8080</port>\n") .append(" </server>\n") .append(" <url>http://www2.google.com/</url>\n") .append("</configuration>"); // parse new xml is = new ByteArrayInputStream(string1.toString().getBytes()); rootNode = parser.parse(is); // configure it again bean.configure(rootNode, config); // confirm properties Assert.assertNotNull(config.getServer()); Assert.assertEquals("http://www2.google.com/", config.url); Assert.assertEquals(8080, config.getServer().port); Assert.assertEquals("www.google.com", config.getServer().host); } @Test(expected=PropertyAlreadySetException.class) public void configureSamePropertyTwiceCausesException() throws Exception { // build xml once StringBuilder string0 = new StringBuilder(200) .append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n") .append("<configuration>\n") .append(" <server>\n") .append(" <port>80</port>\n") .append(" <port>8080</port>\n") // this should cause an exception .append(" </server>\n") .append("</configuration>") .append(""); // parse xml ByteArrayInputStream is = new ByteArrayInputStream(string0.toString().getBytes()); XmlParser parser = new XmlParser(); XmlParser.Node rootNode = parser.parse(is); // object we'll configure ComplexConfiguration config = new ComplexConfiguration(); // configure it using default options XmlBean bean = new XmlBean(); bean.configure(rootNode, config); } public static class ComplexConfiguration { private Server server; private ComplexServer complexServer; private String url; public void setServer(Server value) { this.server = value; } public Server getServer() { return this.server; } public void setUrl(String value) throws MalformedURLException { URL aURL = new URL(value); this.url = value; } } public static class ComplexServer { private int port; public ComplexServer(int port) { this.port = port; } } public static class Server { private int port; private String host; public void setPort(int value) throws ConfigurationException { if (value <= 0) { throw new ConfigurationException("Port must be > 0"); } this.port = value; } public void setHost(String value) throws MalformedURLException { this.host = value; } } public static class SimpleConfiguration { private Integer size; private int port; private String host; private String url; public void setPort(int value) throws ConfigurationException { if (value <= 0) { throw new ConfigurationException("Port must be > 0"); } this.port = value; } public void setHost(String value) throws MalformedURLException { //URL aURL = new URL(value); /** System.out.println("protocol = " + aURL.getProtocol()); System.out.println("authority = " + aURL.getAuthority()); System.out.println("host = " + aURL.getHost()); System.out.println("port = " + aURL.getPort()); System.out.println("path = " + aURL.getPath()); System.out.println("query = " + aURL.getQuery()); System.out.println("filename = " + aURL.getFile()); System.out.println("ref = " + aURL.getRef()); */ this.host = value; } public void setUrl(String value) throws MalformedURLException { URL aURL = new URL(value); /** System.out.println("protocol = " + aURL.getProtocol()); System.out.println("authority = " + aURL.getAuthority()); System.out.println("host = " + aURL.getHost()); System.out.println("port = " + aURL.getPort()); System.out.println("path = " + aURL.getPath()); System.out.println("query = " + aURL.getQuery()); System.out.println("filename = " + aURL.getFile()); System.out.println("ref = " + aURL.getRef()); */ this.url = value; } } public static class ConfigurationException extends Exception { public ConfigurationException(String msg) { super(msg); } } }