| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.geode.internal.config; |
| |
| import static org.assertj.core.api.Assertions.assertThat; |
| import static org.assertj.core.api.Assertions.assertThatThrownBy; |
| |
| import java.util.List; |
| import java.util.Set; |
| |
| import javax.xml.bind.annotation.XmlAccessType; |
| import javax.xml.bind.annotation.XmlAccessorType; |
| import javax.xml.bind.annotation.XmlElement; |
| import javax.xml.bind.annotation.XmlRootElement; |
| import javax.xml.bind.annotation.XmlType; |
| |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.contrib.java.lang.system.RestoreSystemProperties; |
| |
| import org.apache.geode.cache.configuration.CacheConfig; |
| import org.apache.geode.cache.configuration.CacheElement; |
| import org.apache.geode.cache.configuration.GatewayReceiverConfig; |
| import org.apache.geode.cache.configuration.RegionConfig; |
| import org.apache.geode.internal.lang.SystemPropertyHelper; |
| import org.apache.geode.management.configuration.RegionType; |
| |
| public class JAXBServiceTest { |
| |
| private String xml; |
| private CacheConfig unmarshalled; |
| private JAXBService service; |
| private JAXBService service2; |
| |
| @Rule |
| public RestoreSystemProperties restore = new RestoreSystemProperties(); |
| |
| @Before |
| public void setUp() { |
| service = new JAXBService(CacheConfig.class, ElementOne.class, ElementTwo.class); |
| service.validateWithLocalCacheXSD(); |
| |
| service2 = new JAXBService(CacheConfig.class); |
| service2.validateWithLocalCacheXSD(); |
| } |
| |
| @Test |
| public void getPackagesToScanWithoutSystemProperty() { |
| Set<String> packages = JAXBService.getPackagesToScan(); |
| assertThat(packages).containsExactly("*"); |
| } |
| |
| @Test |
| public void getPackagesToScanWithSystemProperty() { |
| System.setProperty("geode." + SystemPropertyHelper.PACKAGES_TO_SCAN, |
| "org.apache.geode,io.pivotal"); |
| Set<String> packages = JAXBService.getPackagesToScan(); |
| assertThat(packages).containsExactly("org.apache.geode", "io.pivotal"); |
| } |
| |
| @Test |
| public void testCacheMarshall() { |
| CacheConfig cacheConfig = new CacheConfig(); |
| setBasicValues(cacheConfig); |
| |
| xml = service.marshall(cacheConfig); |
| System.out.println(xml); |
| // cache has the default namespace |
| assertThat(xml).contains("xmlns=\"http://geode.apache.org/schema/cache\""); |
| assertThat(xml).contains( |
| "xsi:schemaLocation=\"http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd\""); |
| assertThat(xml).contains("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""); |
| assertThat(xml).contains("</cache>"); |
| |
| unmarshalled = service.unMarshall(xml); |
| } |
| |
| @Test |
| public void invalidXmlShouldFail() { |
| CacheConfig cacheConfig = new CacheConfig(); |
| // missing version attribute |
| assertThatThrownBy(() -> service.marshall(cacheConfig)) |
| .hasStackTraceContaining("Attribute 'version' must appear on element 'cache'"); |
| } |
| |
| @Test |
| public void testCacheOneMarshall() { |
| CacheConfig cache = new CacheConfig(); |
| setBasicValues(cache); |
| cache.getCustomCacheElements().add(new ElementOne("test")); |
| |
| xml = service.marshall(cache); |
| System.out.println(xml); |
| // cache has the default namespace |
| assertThat(xml).contains("xmlns=\"http://geode.apache.org/schema/cache\""); |
| assertThat(xml).contains("custom-one>"); |
| } |
| |
| @Test |
| public void testMixMarshall() { |
| CacheConfig cache = new CacheConfig(); |
| setBasicValues(cache); |
| cache.getCustomCacheElements().add(new ElementOne("testOne")); |
| |
| xml = service.marshall(cache); |
| System.out.println(xml); |
| assertThat(xml).contains("custom-one>"); |
| |
| unmarshalled = service2.unMarshall(xml); |
| unmarshalled.getCustomCacheElements().add(new ElementTwo("testTwo")); |
| |
| // xml generated wtih CacheConfigTwo has both elements in there. |
| xml = service.marshall(unmarshalled); |
| System.out.println(xml); |
| assertThat(xml).contains("custom-one>"); |
| assertThat(xml).contains("custom-two>"); |
| assertThat(xml).containsPattern("xmlns=\"http://geode.apache.org/schema/cache\""); |
| assertThat(xml).containsPattern("xmlns:ns\\d=\"http://geode.apache.org/schema/CustomOne\""); |
| assertThat(xml).containsPattern("xmlns:ns\\d=\"http://geode.apache.org/schema/CustomTwo\""); |
| } |
| |
| @Test |
| public void xmlWithCustomElementsCanBeUnMarshalledByAnotherService() { |
| CacheConfig cache = new CacheConfig(); |
| setBasicValues(cache); |
| cache.getCustomCacheElements().add(new ElementOne("test")); |
| cache.getCustomCacheElements().add(new ElementTwo("test")); |
| |
| String prettyXml = service.marshall(cache); |
| System.out.println(prettyXml); |
| |
| CacheConfig cacheConfig = service2.unMarshall(prettyXml); |
| List elements = cacheConfig.getCustomCacheElements(); |
| assertThat(elements.get(0)).isNotInstanceOf(ElementOne.class); |
| assertThat(elements.get(1)).isNotInstanceOf(ElementTwo.class); |
| |
| String uglyXml = service2.marshall(cacheConfig); |
| System.out.println(uglyXml); |
| assertThat(uglyXml).isNotEqualTo(prettyXml); |
| |
| // the xml can be unmarshalled correctly by the first service |
| String newXml = service.marshall(service.unMarshall(uglyXml)); |
| assertThat(newXml).isEqualTo(prettyXml); |
| } |
| |
| @Test |
| public void unmarshallPartialElement() { |
| String xml = "<region name=\"one\">\n" |
| + " <region-attributes scope=\"distributed-ack\" data-policy=\"replicate\"/>\n" |
| + " </region>"; |
| |
| RegionConfig config = service2.unMarshall(xml, RegionConfig.class); |
| assertThat(config.getName()).isEqualTo("one"); |
| } |
| |
| @Test |
| public void unmarshallAnyElement() { |
| String xml = "<region name=\"one\">\n" |
| + " <region-attributes scope=\"distributed-ack\" data-policy=\"replicate\"/>\n" |
| + " <custom:any xmlns:custom=\"http://geode.apache.org/schema/custom\" id=\"any\"/>" |
| + " </region>"; |
| |
| RegionConfig config = service2.unMarshall(xml, RegionConfig.class); |
| assertThat(config.getName()).isEqualTo("one"); |
| assertThat(config.getCustomRegionElements()).hasSize(1); |
| } |
| |
| @Test |
| public void unmarshallIgnoresUnknownProperties() { |
| // say xml has a type attribute that is removed in the new version |
| String existingXML = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" |
| + "<cache version=\"1.0\" xsi:schemaLocation=\"http://geode.apache.org/schema/cache " |
| + "http://geode.apache.org/schema/cache/cache-1.0.xsd\" " |
| + "xmlns=\"http://geode.apache.org/schema/cache\" " |
| + "xmlns:ns2=\"http://geode.apache.org/schema/CustomOne\" " |
| + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" + " <ns2:custom-one>\n" |
| + " <ns2:id>one</ns2:id>\n" + " <ns2:type>onetype</ns2:type>\n" |
| + " <ns2:value>onevalue</ns2:value>\n" + " </ns2:custom-one>\n" + "</cache>"; |
| |
| CacheConfig cacheConfig = service.unMarshall(existingXML); |
| List elements = cacheConfig.getCustomCacheElements(); |
| assertThat(elements.get(0)).isInstanceOf(ElementOne.class); |
| } |
| |
| @Test |
| public void marshalOlderNameSpace() { |
| String xml = |
| "<cache xsi:schemaLocation=\"http://schema.pivotal.io/gemfire/cache http://schema.pivotal.io/gemfire/cache/cache-8.1.xsd\"\n" |
| + |
| " version=\"8.1\"\n" + |
| " xmlns=\"http://schema.pivotal.io/gemfire/cache\"\n" + |
| " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" + |
| " <region name=\"one\">\n" + |
| " <region-attributes scope=\"distributed-ack\" data-policy=\"replicate\"/>\n" + |
| " </region>\n" + |
| "</cache>"; |
| |
| CacheConfig cacheConfig = service2.unMarshall(xml); |
| assertThat(cacheConfig.getRegions()).hasSize(1); |
| assertThat(cacheConfig.getRegions().get(0).getName()).isEqualTo("one"); |
| } |
| |
| @Test |
| public void marshallNoNameSpace() { |
| String xml = "<cache version=\"1.0\">\n" + |
| " <region name=\"one\">\n" + |
| " <region-attributes scope=\"distributed-ack\" data-policy=\"replicate\"/>\n" + |
| " </region>\n" + |
| "</cache>"; |
| |
| CacheConfig cacheConfig = service2.unMarshall(xml); |
| assertThat(cacheConfig.getRegions()).hasSize(1); |
| assertThat(cacheConfig.getRegions().get(0).getName()).isEqualTo("one"); |
| } |
| |
| private void setBasicValues(CacheConfig cache) { |
| GatewayReceiverConfig receiver = new GatewayReceiverConfig(); |
| receiver.setBindAddress("localhost"); |
| receiver.setEndPort("8080"); |
| receiver.setManualStart(false); |
| receiver.setStartPort("6000"); |
| |
| RegionConfig region = new RegionConfig(); |
| region.setName("testRegion"); |
| region.setType(RegionType.REPLICATE); |
| |
| cache.setCopyOnRead(true); |
| cache.setGatewayReceiver(receiver); |
| cache.setVersion("1.0"); |
| cache.getRegions().add(region); |
| } |
| |
| @XmlAccessorType(XmlAccessType.FIELD) |
| @XmlType(name = "", propOrder = {"id", "value"}) |
| @XmlRootElement(name = "custom-one", namespace = "http://geode.apache.org/schema/CustomOne") |
| public static class ElementOne extends CacheElement { |
| @XmlElement(name = "id", namespace = "http://geode.apache.org/schema/CustomOne") |
| private String id; |
| @XmlElement(name = "value", namespace = "http://geode.apache.org/schema/CustomOne") |
| private String value; |
| |
| public ElementOne() { |
| // nothing |
| } |
| |
| public String getValue() { |
| return value; |
| } |
| |
| public void setValue(String value) { |
| this.value = value; |
| } |
| |
| public ElementOne(String id) { |
| this.id = id; |
| } |
| |
| @Override |
| public String getId() { |
| return id; |
| } |
| |
| public void setId(String value) { |
| id = value; |
| } |
| } |
| |
| @XmlAccessorType(XmlAccessType.FIELD) |
| @XmlType(name = "", propOrder = {"id", "value"}) |
| @XmlRootElement(name = "custom-two", namespace = "http://geode.apache.org/schema/CustomTwo") |
| public static class ElementTwo extends CacheElement { |
| @XmlElement(name = "id", namespace = "http://geode.apache.org/schema/CustomTwo") |
| private String id; |
| @XmlElement(name = "value", namespace = "http://geode.apache.org/schema/CustomTwo") |
| private String value; |
| |
| public ElementTwo() { |
| // nothing |
| } |
| |
| public String getValue() { |
| return value; |
| } |
| |
| public void setValue(String value) { |
| this.value = value; |
| } |
| |
| public ElementTwo(String id) { |
| this.id = id; |
| } |
| |
| @Override |
| public String getId() { |
| return id; |
| } |
| |
| public void setId(String value) { |
| id = value; |
| } |
| } |
| |
| } |