package com.temenos.interaction.media.odata.xml.atom; /* * #%L * interaction-media-odata-xml * %% * Copyright (C) 2012 - 2013 Temenos Holdings N.V. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import static org.hamcrest.Matchers.greaterThan; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.lang.annotation.Annotation; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; import javax.ws.rs.HttpMethod; import javax.ws.rs.core.GenericEntity; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Request; import javax.ws.rs.core.UriInfo; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import org.custommonkey.xmlunit.Diff; import org.custommonkey.xmlunit.DifferenceListener; import org.custommonkey.xmlunit.IgnoreTextAndAttributeValuesDifferenceListener; import org.custommonkey.xmlunit.XMLUnit; import org.junit.Test; import org.odata4j.core.ImmutableList; import org.odata4j.core.OCollection; import org.odata4j.core.OComplexObject; import org.odata4j.core.OEntities; import org.odata4j.core.OEntity; import org.odata4j.core.OEntityKey; import org.odata4j.core.OLink; import org.odata4j.core.OLinks; import org.odata4j.core.OProperties; import org.odata4j.core.OProperty; import org.odata4j.edm.EdmDataServices; import org.odata4j.edm.EdmEntityContainer; import org.odata4j.edm.EdmEntitySet; import org.odata4j.edm.EdmEntityType; import org.odata4j.edm.EdmProperty; import org.odata4j.edm.EdmSchema; import org.odata4j.edm.EdmSimpleType; import org.odata4j.exceptions.NotFoundException; import com.temenos.interaction.commands.odata.OEntityTransformer; import com.temenos.interaction.core.ExtendedMediaTypes; import com.temenos.interaction.core.MultivaluedMapImpl; import com.temenos.interaction.core.command.CommandHelper; import com.temenos.interaction.core.entity.Entity; import com.temenos.interaction.core.entity.EntityMetadata; import com.temenos.interaction.core.entity.EntityProperties; import com.temenos.interaction.core.entity.EntityProperty; import com.temenos.interaction.core.entity.GenericError; import com.temenos.interaction.core.entity.Metadata; import com.temenos.interaction.core.entity.vocabulary.Vocabulary; import com.temenos.interaction.core.entity.vocabulary.terms.TermComplexGroup; import com.temenos.interaction.core.entity.vocabulary.terms.TermComplexType; import com.temenos.interaction.core.entity.vocabulary.terms.TermIdField; import com.temenos.interaction.core.entity.vocabulary.terms.TermValueType; import com.temenos.interaction.core.hypermedia.Action; import com.temenos.interaction.core.hypermedia.CollectionResourceState; import com.temenos.interaction.core.hypermedia.EntityTransformer; import com.temenos.interaction.core.hypermedia.Link; import com.temenos.interaction.core.hypermedia.LinkGenerator; import com.temenos.interaction.core.hypermedia.LinkGeneratorImpl; import com.temenos.interaction.core.hypermedia.MethodNotAllowedException; import com.temenos.interaction.core.hypermedia.ResourceState; import com.temenos.interaction.core.hypermedia.ResourceStateMachine; import com.temenos.interaction.core.hypermedia.Transformer; import com.temenos.interaction.core.hypermedia.Transition; import com.temenos.interaction.core.hypermedia.UriSpecification; import com.temenos.interaction.core.resource.CollectionResource; import com.temenos.interaction.core.resource.EntityResource; import com.temenos.interaction.core.resource.MetaDataResource; import com.temenos.interaction.core.resource.RESTResource; import com.temenos.interaction.core.web.RequestContext; import com.temenos.interaction.media.odata.xml.CustomError; import com.temenos.interaction.media.odata.xml.Flight; import com.temenos.interaction.media.odata.xml.IgnoreNamedElementsXMLDifferenceListener; import com.temenos.interaction.odataext.entity.MetadataOData4j; public class TestAtomXMLProvider { private final static String EXPECTED_XML = "<?xml version=\"1.0\" encoding=\"utf-8\"?><entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" xml:base=\"http://localhost:8080/responder/rest\"><id>http://localhost:8080/responder/restFlight('123')</id><title type=\"text\"></title><updated>2012-03-14T11:29:19Z</updated><author><name></name></author><category term=\"InteractionTest.Flight\" scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\"></category><content type=\"application/xml\"><m:properties><d:id>1</d:id><d:flight>EI218</d:flight></m:properties></content></entry>"; public final static String FLIGHT_ENTRY_XML = "FlightEntry.xml"; public final static String FLIGHT_ENTRY_SIMPLE_XML = "FlightEntrySimple.xml"; public final static String FLIGHT_COLLECTION_XML = "FlightsFeed.xml"; public final static String ATOM_GENERIC_ERROR_ENTRY_XML = "AtomGenericErrorEntry.xml"; public final static String ATOM_CUSTOM_ERROR_ENTRY_XML = "AtomCustomErrorEntry.xml"; public final static String EMPTY_FUNDS_TRANSFERS_FEED_XML = "EmptyFundsTransfersFeed.xml"; public class MockAtomXMLProvider extends AtomXMLProvider { public MockAtomXMLProvider(MetadataOData4j metadataOData4j) { this(metadataOData4j, mock(Metadata.class)); } public MockAtomXMLProvider(MetadataOData4j metadataOData4j, Metadata metadata) { //super(null, metadata, new EntityTransformer()); super(metadataOData4j, metadata, new ResourceStateMachine(new ResourceState("ServiceDocument", "ServiceDocument", new ArrayList<Action>(), "/")), null); } public void setUriInfo(UriInfo uriInfo) { super.setUriInfo(uriInfo); } }; private MetadataOData4j createMockMetadataOData4j(EdmDataServices mockEDS) { MetadataOData4j mockMetadataOData4j = mock(MetadataOData4j.class); when(mockMetadataOData4j.getMetadata()).thenReturn(mockEDS); return mockMetadataOData4j; } @Test public void testReadEntityResourceOEntity_XML() throws Exception { List<Action> initialActions = new ArrayList<Action>(); Action action = mock(Action.class); when(action.getMethod()).thenReturn("GET"); initialActions.add(action); ResourceState initial = new ResourceState("initial_state", "initial_state", initialActions, "/", null, new UriSpecification("Initial", "/initial")); List<Action> serviceDocActions = new ArrayList<Action>(); serviceDocActions.add(action); ResourceState serviceDoc = new ResourceState("SD", "ServiceDocument", serviceDocActions, "/"); initial.addTransition(new Transition.Builder().method("GET").target(serviceDoc).build()); List<Action> ftCommissionTypeActions = new ArrayList<Action>(); ftCommissionTypeActions.add(action); CollectionResourceState resourceType = new CollectionResourceState("FtCommissionType", "FtCommissionTypes", ftCommissionTypeActions, "/oentitys", null, null); initial.addTransition(new Transition.Builder().method("GET").target(resourceType).build()); ResourceStateMachine hypermediaEngine = new ResourceStateMachine(initial); Metadata metadata = new Metadata("hothouse-models"); MetadataOData4j metadataOData4j = new MetadataOData4j(metadata, new ResourceStateMachine(serviceDoc)); AtomXMLProvider ap = new AtomXMLProvider(metadataOData4j, metadata, hypermediaEngine, new OEntityTransformer()); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getPathParameters(false)).thenReturn(mock(MultivaluedMap.class)); ap.setUriInfo(uriInfo); UriInfo mockUriInfo = mock(UriInfo.class); when(mockUriInfo.getAbsolutePath()).thenReturn(new URI("http://www.temenos.com/rest.svc/oentitys")); when(mockUriInfo.getBaseUri()).thenReturn(new URI("http://www.temenos.com/rest.svc")); ap.setUriInfo(mockUriInfo); Request request = mock(Request.class); when(request.getMethod()).thenReturn("GET"); ap.setRequestContext(request); InputStream in = null; EntityResource<OEntity> entity; try { in = getClass().getClassLoader().getResourceAsStream("issue193_entry_with_Bag.xml"); GenericEntity<EntityResource<OEntity>> ge = new GenericEntity<EntityResource<OEntity>>(new EntityResource<OEntity>(null)) { }; entity = ap.readFrom(RESTResource.class, ge.getType(), null, MediaType.APPLICATION_ATOM_XML_TYPE, null, in); } finally { if(in != null) { in.close(); } } assertNotNull(entity); OEntity oEntity = entity.getEntity(); assertNotNull(oEntity); assertEquals("FtCommissionTypes", oEntity.getEntitySetName()); List<OProperty<?>> properties = oEntity.getProperties(); assertNotNull(properties); boolean ftCommissionType_ShortDescrMvGroupFound = false; boolean ftCommissionType_CurrencyMvGroupFound = false; boolean txnCodeDrFound = false; boolean currencyFound = false; boolean upToAmtFound = false; for(OProperty<?> property: properties) { if("TxnCodeDr".equals(property.getName())) { assertEquals("639", property.getValue()); txnCodeDrFound = true; } if("FtCommissionType_ShortDescrMvGroup".equals(property.getName())) { OCollection<OComplexObject> tmpComplexType = (OCollection<OComplexObject>)property.getValue(); assertNotNull(tmpComplexType.getType()); OComplexObject tmpOComplexObj = tmpComplexType.iterator().next(); assertEquals("Sec Default", tmpOComplexObj.getProperty("ShortDescr").getValue()); ftCommissionType_ShortDescrMvGroupFound = true; } if("FtCommissionType_CurrencyMvGroup".equals(property.getName())) { OCollection<OComplexObject> tmpComplexType = (OCollection<OComplexObject>)property.getValue(); Iterator<OComplexObject> tmpComplexTypeIter = tmpComplexType.iterator(); while(tmpComplexTypeIter.hasNext()) { OComplexObject tmpOComplexObj = tmpComplexTypeIter.next(); List<OProperty<?>> tmpProperties = tmpOComplexObj.getProperties(); for(OProperty<?> tmpProperty: tmpProperties) { if("Currency".equals(tmpProperty.getName()) && !currencyFound) { assertEquals("USD", tmpProperty.getValue()); currencyFound = true; } if("FtCommissionType_CalcTypeSvGroup".equals(tmpProperty.getName())) { ftCommissionType_CurrencyMvGroupFound = true; OCollection<OComplexObject> tmpComplexType2 = (OCollection<OComplexObject>)tmpProperty.getValue(); Iterator<OComplexObject> tmpComplexTypeIter2 = tmpComplexType2.iterator(); while(tmpComplexTypeIter2.hasNext() && !upToAmtFound) { OComplexObject tmpOComplexObj2 = tmpComplexTypeIter2.next(); List<OProperty<?>> tmpProperties2 = tmpOComplexObj2.getProperties(); for(OProperty<?> tmpProperty2: tmpProperties2) { if("UptoAmt".equals(tmpProperty2.getName())) { upToAmtFound = true; assertEquals("500000.00", tmpProperty2.getValue()); } } } } } } } } assertTrue(ftCommissionType_ShortDescrMvGroupFound); assertTrue(ftCommissionType_CurrencyMvGroupFound); assertTrue(txnCodeDrFound); assertTrue(currencyFound); assertTrue(upToAmtFound); } @Test public void testWriteEntityResourceOEntity_XML() throws Exception { EdmEntitySet ees = createMockEdmEntitySet(); EdmDataServices mockEDS = createMockFlightEdmDataServices(); EntityResource<OEntity> er = createMockEntityResourceOEntity(ees); when(mockEDS.getEdmEntitySet(any(EdmEntityType.class))).thenReturn(ees); //Wrap entity resource into a JAX-RS GenericEntity instance GenericEntity<EntityResource<OEntity>> ge = new GenericEntity<EntityResource<OEntity>>(er) {}; //Create provider MockAtomXMLProvider p = new MockAtomXMLProvider(createMockMetadataOData4j(mockEDS)); UriInfo uriInfo = mock(UriInfo.class); URI uri = new URI("http://localhost:8080/responder/rest"); when(uriInfo.getBaseUri()).thenReturn(uri); p.setUriInfo(uriInfo); //Serialize resource ByteArrayOutputStream bos = new ByteArrayOutputStream(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, MediaType.APPLICATION_XML_TYPE, null, bos); String responseString = new String(bos.toByteArray(), "UTF-8"); System.out.println(responseString); //Assert xml string but ignore text and attribute values DifferenceListener myDifferenceListener = new IgnoreTextAndAttributeValuesDifferenceListener(); Diff myDiff = new Diff(responseString, EXPECTED_XML); myDiff.overrideDifferenceListener(myDifferenceListener); assertTrue(myDiff.similar()); } @Test public void testWriteEntityResourceOEntity_AtomXML() throws Exception { EdmEntitySet ees = createMockEdmEntitySet(); EdmDataServices mockEDS = createMockFlightEdmDataServices(); EntityResource<OEntity> er = createMockEntityResourceOEntity(ees); when(mockEDS.getEdmEntitySet(any(EdmEntityType.class))).thenReturn(ees); //Wrap entity resource into a JAX-RS GenericEntity instance GenericEntity<EntityResource<OEntity>> ge = new GenericEntity<EntityResource<OEntity>>(er) {}; //Create provider MockAtomXMLProvider p = new MockAtomXMLProvider(createMockMetadataOData4j(mockEDS)); UriInfo uriInfo = mock(UriInfo.class); URI uri = new URI("http://localhost:8080/responder/rest"); when(uriInfo.getBaseUri()).thenReturn(uri); p.setUriInfo(uriInfo); //Serialize resource ByteArrayOutputStream bos = new ByteArrayOutputStream(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, MediaType.APPLICATION_ATOM_XML_TYPE, null, bos); String responseString = new String(bos.toByteArray(), "UTF-8"); //Assert xml string but ignore text and attribute values DifferenceListener myDifferenceListener = new IgnoreTextAndAttributeValuesDifferenceListener(); Diff myDiff = new Diff(responseString, EXPECTED_XML); myDiff.overrideDifferenceListener(myDifferenceListener); assertTrue(myDiff.similar()); } private EdmEntitySet createMockEdmEntitySet() { // Create an entity set List<EdmProperty.Builder> eprops = new ArrayList<EdmProperty.Builder>(); EdmProperty.Builder ep = EdmProperty.newBuilder("id").setType(EdmSimpleType.STRING); eprops.add(ep); EdmEntityType.Builder eet = EdmEntityType.newBuilder().setNamespace("InteractionTest").setName("Flight").addKeys(Arrays.asList("id")).addProperties(eprops); EdmEntitySet.Builder eesb = EdmEntitySet.newBuilder().setName("Flight").setEntityType(eet); return eesb.build(); } private EdmDataServices createMockFlightEdmDataServices() { EdmDataServices mockEDS = mock(EdmDataServices.class); //Mock EdmDataServices List<String> keys = new ArrayList<String>(); keys.add("MyId"); List<EdmProperty.Builder> properties = new ArrayList<EdmProperty.Builder>(); EdmProperty.Builder ep = EdmProperty.newBuilder("MyId").setType(EdmSimpleType.STRING); properties.add(ep); EdmEntityType.Builder eet = EdmEntityType.newBuilder().setNamespace("FlightModelModel").setAlias("MyAlias").setName("Flight").addKeys(keys).addProperties(properties); EdmEntitySet.Builder ees = EdmEntitySet.newBuilder().setName("Flight").setEntityType(eet); List<EdmEntityType.Builder> mockEntityTypes = new ArrayList<EdmEntityType.Builder>(); mockEntityTypes.add(eet); List<EdmEntitySet.Builder> mockEntitySets = new ArrayList<EdmEntitySet.Builder>(); mockEntitySets.add(ees); EdmEntityContainer.Builder eec = EdmEntityContainer.newBuilder().setName("MyEntityContainer").addEntitySets(mockEntitySets); List<EdmEntityContainer.Builder> mockEntityContainers = new ArrayList<EdmEntityContainer.Builder>(); mockEntityContainers.add(eec); EdmSchema.Builder es = EdmSchema.newBuilder().setNamespace("MyNamespace").setAlias("MyAlias").addEntityTypes(mockEntityTypes).addEntityContainers(mockEntityContainers); List<EdmSchema> mockSchemas = new ArrayList<EdmSchema>(); mockSchemas.add(es.build()); when(mockEDS.getSchemas()).thenReturn(ImmutableList.copyOf(mockSchemas)); when(mockEDS.findEdmEntitySet(anyString())).thenReturn(ees.build()); when(mockEDS.getEdmEntitySet(any(EdmEntityType.class))).thenReturn(ees.build()); return mockEDS; } private EdmDataServices createMockEdmDataServices(String entitySetName) { EdmDataServices edmDataServices = mock(EdmDataServices.class); EdmEntitySet entitySet = mock(EdmEntitySet.class); when(entitySet.getName()).thenReturn(entitySetName); when(edmDataServices.getEdmEntitySet(any(EdmEntityType.class))).thenReturn(entitySet); EdmEntityType entityType = mock(EdmEntityType.class); when(edmDataServices.findEdmEntityType(anyString())).thenReturn(entityType); return edmDataServices; } private EntityResource<Entity> createMockEntityResourceEntity(String name) { //Create an Entity EntityProperties properties = new EntityProperties(); properties.setProperty(new EntityProperty("id", "1")); properties.setProperty(new EntityProperty("flight", "EI218")); Entity entity = new Entity(name, properties); return new EntityResource<Entity>(name, entity); } private EntityResource<OEntity> createMockEntityResourceOEntity(EdmEntitySet ees) { return createMockEntityResourceOEntity(ees, null); } private EntityResource<OEntity> createMockEntityResourceOEntity(EdmEntitySet ees, String etag) { //Create an OEntity OEntityKey entityKey = OEntityKey.create("1"); List<OProperty<?>> properties = new ArrayList<OProperty<?>>(); properties.add(OProperties.string("id", "1")); properties.add(OProperties.string("flight", "EI218")); OEntity entity = OEntities.create(ees, null, entityKey, etag, properties, new ArrayList<OLink>()); return new EntityResource<OEntity>(entity); } private Metadata createMockFlightMetadata() { Metadata mockMetadata = new Metadata("FlightModel"); // Define vocabulary for this entity - minimum fields for an input EntityMetadata entityMetadata = new EntityMetadata("Flight"); Vocabulary voc_id = new Vocabulary(); voc_id.setTerm(new TermValueType(TermValueType.TEXT)); voc_id.setTerm(new TermIdField(true)); entityMetadata.setPropertyVocabulary("id", voc_id); Vocabulary voc_flight = new Vocabulary(); voc_flight.setTerm(new TermValueType(TermValueType.TEXT)); entityMetadata.setPropertyVocabulary("flight", voc_flight); // MvSv Group Vocabulary voc_MvSvGroup = new Vocabulary(); voc_MvSvGroup.setTerm(new TermComplexType(true)); entityMetadata.setPropertyVocabulary("MvSvGroup", voc_MvSvGroup); Stack<String> mvParentProperties = new Stack<String>(); mvParentProperties.push("MvSvGroup"); Vocabulary voc_MvSv = new Vocabulary(); voc_MvSv.setTerm(new TermComplexGroup("MvSvGroup")); voc_MvSv.setTerm(new TermValueType(TermValueType.TEXT)); entityMetadata.setPropertyVocabulary("MvSv", voc_MvSv, mvParentProperties.elements()); Vocabulary voc_MvSvStartGroup = new Vocabulary(); voc_MvSvStartGroup.setTerm(new TermComplexType(true)); voc_MvSvStartGroup.setTerm(new TermComplexGroup("MvSvGroup")); entityMetadata.setPropertyVocabulary("MvSvStartGroup", voc_MvSvStartGroup, mvParentProperties.elements()); Stack<String> svParentProperties = new Stack<String>(); svParentProperties.push("MvSvGroup"); svParentProperties.push("MvSvStartGroup"); Vocabulary voc_MvSvStart = new Vocabulary(); voc_MvSvStart.setTerm(new TermComplexGroup("MvSvStartGroup")); voc_MvSvStart.setTerm(new TermValueType(TermValueType.TEXT)); entityMetadata.setPropertyVocabulary("MvSvStart", voc_MvSvStart, svParentProperties.elements()); Vocabulary voc_MvSvEnd = new Vocabulary(); voc_MvSvEnd.setTerm(new TermComplexGroup("MvSvStartGroup")); voc_MvSvEnd.setTerm(new TermValueType(TermValueType.TEXT)); entityMetadata.setPropertyVocabulary("MvSvEnd", voc_MvSvEnd, svParentProperties.elements()); mockMetadata.setEntityMetadata(entityMetadata); //Define a custom error entity EntityMetadata mdCustomError = new EntityMetadata("CustomError"); Vocabulary vocCustomError = new Vocabulary(); vocCustomError.setTerm(new TermValueType(TermValueType.TEXT)); mdCustomError.setPropertyVocabulary("mycustomerror", vocCustomError); mockMetadata.setEntityMetadata(mdCustomError); return mockMetadata; } private Metadata createMockMetadata(String modelName) { Metadata metadata = mock(Metadata.class); when(metadata.getModelName()).thenReturn(modelName); return metadata; } private CollectionResource<Entity> createMockCollectionResourceEntity() { List<EntityResource<Entity>> erList = new ArrayList<EntityResource<Entity>>(); erList.add(createMockEntityResourceEntity()); CollectionResource<Entity> cr = new CollectionResource<Entity>("Flights", erList); cr.setLinks(new ArrayList<Link>()); cr.setEntityName("Flight"); return cr; } @SuppressWarnings("unchecked") private EntityResource<Entity> createMockEntityResourceEntity() { EntityResource<Entity> er = mock(EntityResource.class); // Create entity EntityProperties properties = new EntityProperties(); properties.setProperty(new EntityProperty("id", "123")); properties.setProperty(new EntityProperty("flight", "EI218")); // Multi-value group with sub-value group List<EntityProperties> mvSvGroup = new ArrayList<EntityProperties>(); EntityProperties mvSvGroup1 = new EntityProperties(); mvSvGroup1.setProperty(new EntityProperty("MvSv", "mv sv 1:1")); List<EntityProperties> mvSvStartGroup1 = new ArrayList<EntityProperties>(); // Sub-value group EntityProperties mvSvStartGroup1_1 = new EntityProperties(); mvSvStartGroup1_1.setProperty(new EntityProperty("MvSvStart", "mv sv start 1:1")); mvSvStartGroup1_1.setProperty(new EntityProperty("MvSvEnd", "mv sv end 1:1")); mvSvStartGroup1.add(mvSvStartGroup1_1); EntityProperties mvSvStartGroup1_2 = new EntityProperties(); mvSvStartGroup1_2.setProperty(new EntityProperty("MvSvStart", "mv sv start 1:2")); mvSvStartGroup1_2.setProperty(new EntityProperty("MvSvEnd", "mv sv end 1:2")); mvSvStartGroup1.add(mvSvStartGroup1_2); mvSvGroup1.setProperty(new EntityProperty("MvSvStartGroup", mvSvStartGroup1)); mvSvGroup.add(mvSvGroup1); // Multi-value group EntityProperties mvSvGroup2 = new EntityProperties(); mvSvGroup2.setProperty(new EntityProperty("MvSv", "mv sv 2:1")); List<EntityProperties> mvSvStartGroup2 = new ArrayList<EntityProperties>(); // Sub-value group EntityProperties mvSvStartGroup2_1 = new EntityProperties(); mvSvStartGroup2_1.setProperty(new EntityProperty("MvSvStart", "mv sv start 2:1")); mvSvStartGroup2_1.setProperty(new EntityProperty("MvSvEnd", "mv sv end 2:1")); mvSvStartGroup2.add(mvSvStartGroup2_1); EntityProperties mvSvStartGroup2_2 = new EntityProperties(); mvSvStartGroup2_2.setProperty(new EntityProperty("MvSvStart", "mv sv start 2:2")); mvSvStartGroup2_2.setProperty(new EntityProperty("MvSvEnd", "mv sv end 2:2")); mvSvStartGroup2.add(mvSvStartGroup2_2); mvSvGroup2.setProperty(new EntityProperty("MvSvStartGroup", mvSvStartGroup2)); mvSvGroup.add(mvSvGroup2); properties.setProperty(new EntityProperty("MvSvGroup", mvSvGroup)); // End Multi-value group Entity entity = new Entity("Flight", properties); when(er.getEntity()).thenReturn(entity); when(er.getEntityName()).thenReturn("Flight"); return er; } @SuppressWarnings("unchecked") private EntityResource<Flight> createMockEntityResourceObject() throws Exception { String testXMLString = "<resource><Flight><id>123</id><flight>EI218</flight></Flight></resource>"; JAXBContext jc = JAXBContext.newInstance(EntityResource.class, Flight.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); EntityResource<Flight> er = (EntityResource<Flight>) unmarshaller.unmarshal(new ByteArrayInputStream(testXMLString.getBytes())); er.setEntityName("Flight"); return er; } @Test (expected = AssertionError.class) public void testUnhandledRawType() throws IOException, URISyntaxException { EdmDataServices metadata = mock(EdmDataServices.class); MetadataOData4j metadataOData4j = createMockMetadataOData4j(metadata); EdmEntitySet edmEntitySet = mock(EdmEntitySet.class); when(metadataOData4j.getEdmEntitySetByEntityName(eq("ServiceDocument"))).thenReturn(edmEntitySet); AtomXMLProvider ap = new AtomXMLProvider(metadataOData4j, mock(Metadata.class), mockResourceStateMachine(), new OEntityTransformer()); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI("/myapp.svc")); when(uriInfo.getPath()).thenReturn("/"); ap.setUriInfo(uriInfo); Request request = mock(Request.class); when(request.getMethod()).thenReturn("GET"); ap.setRequestContext(request); // Wrap an unsupported resource into a JAX-RS GenericEntity instance GenericEntity<MetaDataResource<String>> ge = new GenericEntity<MetaDataResource<String>>(new MetaDataResource<String>("")) {}; // will throw exception if we check the class properly Annotation[] annotations = null; MediaType mediaType = MediaType.APPLICATION_ATOM_XML_TYPE; MultivaluedMap<String, String> headers = null; InputStream content = null; ap.readFrom(RESTResource.class, ge.getType(), annotations, mediaType, headers, content); } @Test public void testWriteCollectionResourceEntity_AtomXML() throws Exception { EdmEntitySet ees = createMockEdmEntitySet(); EdmDataServices mockEDS = createMockFlightEdmDataServices(); when(mockEDS.getEdmEntitySet(anyString())).thenReturn(ees); Metadata mockMetadata = createMockFlightMetadata(); CollectionResource<Entity> cr = createMockCollectionResourceEntity(); //Wrap entity resource into a JAX-RS GenericEntity instance GenericEntity<CollectionResource<Entity>> ge = new GenericEntity<CollectionResource<Entity>>(cr) {}; //Create provider MockAtomXMLProvider p = new MockAtomXMLProvider(createMockMetadataOData4j(mockEDS), mockMetadata); UriInfo uriInfo = mock(UriInfo.class); URI uri = new URI("http://localhost:8080/responder/rest/"); when(uriInfo.getBaseUri()).thenReturn(uri); when(uriInfo.getPath()).thenReturn("Flight()"); p.setUriInfo(uriInfo); //Serialize resource ByteArrayOutputStream bos = new ByteArrayOutputStream(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, MediaType.APPLICATION_ATOM_XML_TYPE, null, bos); String responseString = new String(bos.toByteArray(), "UTF-8"); //Check response XMLUnit.setIgnoreWhitespace(true); Diff myDiff = XMLUnit.compareXML(readTextFile(FLIGHT_COLLECTION_XML), responseString); myDiff.overrideDifferenceListener(new IgnoreNamedElementsXMLDifferenceListener("updated")); if(!myDiff.similar()) { fail(myDiff.toString()); } } @Test public void testWriteEntityResourceEntity_AtomXML() throws Exception { EdmEntitySet ees = createMockEdmEntitySet(); EdmDataServices mockEDS = createMockFlightEdmDataServices(); when(mockEDS.getEdmEntitySet(anyString())).thenReturn(ees); Metadata mockMetadata = createMockFlightMetadata(); EntityResource<Entity> er = createMockEntityResourceEntity(); //Wrap entity resource into a JAX-RS GenericEntity instance GenericEntity<EntityResource<Entity>> ge = new GenericEntity<EntityResource<Entity>>(er) {}; //Create provider MockAtomXMLProvider p = new MockAtomXMLProvider(createMockMetadataOData4j(mockEDS), mockMetadata); UriInfo uriInfo = mock(UriInfo.class); URI uri = new URI("http://localhost:8080/responder/rest/"); when(uriInfo.getBaseUri()).thenReturn(uri); when(uriInfo.getPath()).thenReturn("Flight('123')"); p.setUriInfo(uriInfo); //Serialize resource ByteArrayOutputStream bos = new ByteArrayOutputStream(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, MediaType.APPLICATION_ATOM_XML_TYPE, null, bos); String responseString = new String(bos.toByteArray(), "UTF-8"); //Check response XMLUnit.setIgnoreWhitespace(true); Diff myDiff = XMLUnit.compareXML(readTextFile(FLIGHT_ENTRY_XML), responseString); myDiff.overrideDifferenceListener(new IgnoreNamedElementsXMLDifferenceListener("updated")); if(!myDiff.similar()) { fail(myDiff.toString()); } } @Test public void testWriteEntityResourceObject_AtomXML() throws Exception { EdmEntitySet ees = createMockEdmEntitySet(); EdmDataServices mockEDS = createMockFlightEdmDataServices(); when(mockEDS.getEdmEntitySet(anyString())).thenReturn(ees); Metadata mockMetadata = createMockFlightMetadata(); // change id to integer for this test EntityMetadata entityMetadata = mockMetadata.getEntityMetadata("Flight"); Vocabulary voc_id = new Vocabulary(); voc_id.setTerm(new TermValueType(TermValueType.INTEGER_NUMBER)); voc_id.setTerm(new TermIdField(true)); entityMetadata.setPropertyVocabulary("id", voc_id); EntityResource<Flight> er = createMockEntityResourceObject(); //Wrap entity resource into a JAX-RS GenericEntity instance GenericEntity<EntityResource<Flight>> ge = new GenericEntity<EntityResource<Flight>>(er) {}; //Create provider MockAtomXMLProvider p = new MockAtomXMLProvider(createMockMetadataOData4j(mockEDS), mockMetadata); UriInfo uriInfo = mock(UriInfo.class); URI uri = new URI("http://localhost:8080/responder/rest/"); when(uriInfo.getBaseUri()).thenReturn(uri); when(uriInfo.getPath()).thenReturn("Flight(123)"); p.setUriInfo(uriInfo); //Serialize resource ByteArrayOutputStream bos = new ByteArrayOutputStream(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, MediaType.APPLICATION_ATOM_XML_TYPE, null, bos); String responseString = new String(bos.toByteArray(), "UTF-8"); //Check response XMLUnit.setIgnoreWhitespace(true); Diff myDiff = XMLUnit.compareXML(readTextFile(FLIGHT_ENTRY_SIMPLE_XML), responseString); myDiff.overrideDifferenceListener(new IgnoreNamedElementsXMLDifferenceListener("updated")); if(!myDiff.similar()) { fail(myDiff.toString()); } } @Test public void testSkipSelfIfEditExists() { /* * Is this in the OData spec? It seems that if a 'self' and 'edit' link relation exists * then ODataExplorer barfs */ EdmDataServices edmDataServices = createMockEdmDataServices("FundsTransfers"); Metadata metadata = createMockMetadata("MyModel"); Transition transition = createMockTransition( createMockResourceState("FundsTransfers", "FundsTransfer", true), createMockResourceState("fundstransfer", "FundsTransfer", false)); AtomXMLProvider provider = new AtomXMLProvider(createMockMetadataOData4j(edmDataServices), metadata, mockResourceStateMachine(), mock(Transformer.class)); Collection<Link> processedLinks = null; List<Link> links = new ArrayList<Link>(); links.add(new Link.Builder() .transition(transition) .title("title") .rel("self") .href("href") .id("id") .build()); EntityResource<OEntity> entityResource = new EntityResource<OEntity>(mock(OEntity.class)); entityResource.setLinks(links); provider.processLinks(entityResource); processedLinks = entityResource.getLinks(); assertEquals(1, processedLinks.size()); // now add the 'edit' link, it should replace the 'self' link links.add(new Link.Builder() .transition(transition) .title("title") .rel("edit") .href("href") .id("id") .build()); entityResource.setLinks(links); provider.processLinks(entityResource); processedLinks = entityResource.getLinks(); assertEquals(1, processedLinks.size()); } @Test public void testSingleLinkEntryToCollection() { ResourceState account = new ResourceState("Account", "customerAccount", new ArrayList<Action>(), "/CustomerAccounts('{id}')"); ResourceState fundsTransfers = new CollectionResourceState("FundsTransfer", "FundsTransfers", new ArrayList<Action>(), "/FundsTransfers"); Map<String, String> uriLinkageMap = new HashMap<String, String>(); uriLinkageMap.put("DebitAcctNo", "{Acc}"); account.addTransition(new Transition.Builder().method(HttpMethod.GET).target(fundsTransfers).uriParameters(uriLinkageMap).label("Debit funds transfers").build()); EdmDataServices mockEDS = createMockEdmDataServices("FundsTransfers"); AtomXMLProvider provider = new AtomXMLProvider(createMockMetadataOData4j(mockEDS), createMockMetadata("MyModel"), mockResourceStateMachine(), mock(Transformer.class)); Transition t = account.getTransition(fundsTransfers); List<Link> links = new ArrayList<Link>(); links.add(new Link(t, t.getTarget().getRel(), "/FundsTransfers()?$filter=DebitAcctNo eq '123'", HttpMethod.GET)); EntityResource<OEntity> entityResource = new EntityResource<OEntity>(mock(OEntity.class)); entityResource.setLinks(links); provider.processLinks(entityResource); Collection<Link> processedLinks = entityResource.getLinks(); assertEquals(1, processedLinks.size()); Link theLink = processedLinks.iterator().next(); //Link relation should contain MS-DATA base uri + /related/ + navigation property. The nav. property in this case is the EntitySet name assertEquals("http://schemas.microsoft.com/ado/2007/08/dataservices/related/FundsTransfers", theLink.getRel()); assertEquals("Debit funds transfers", theLink.getTitle()); assertEquals("/FundsTransfers()?$filter=DebitAcctNo eq '123'", theLink.getHref()); } @Test public void testMultipleLinksEntryToCollection() { ResourceState account = new ResourceState("Account", "customerAccount", new ArrayList<Action>(), "/CustomerAccounts('{id}')"); ResourceState fundsTransfers = new CollectionResourceState("FundsTransfer", "FundsTransfers", new ArrayList<Action>(), "/FundsTransfers"); Map<String, String> uriLinkageMap = new HashMap<String, String>(); uriLinkageMap.put("DebitAcctNo", "{Acc}"); account.addTransition(new Transition.Builder().method(HttpMethod.GET).target(fundsTransfers).uriParameters(uriLinkageMap).label("Debit funds transfers").build()); uriLinkageMap.clear(); uriLinkageMap.put("CreditAcctNo", "{Acc}"); account.addTransition(new Transition.Builder().method(HttpMethod.GET).target(fundsTransfers).uriParameters(uriLinkageMap).label("Credit funds transfers").build()); AtomXMLProvider provider = new AtomXMLProvider(createMockMetadataOData4j(createMockEdmDataServices("FundsTransfers")), createMockMetadata("MyModel"), mockResourceStateMachine(), mock(Transformer.class)); List<Transition> transitions = account.getTransitions(fundsTransfers); assertEquals(2, transitions.size()); List<Link> links = new ArrayList<Link>(); links.add(new Link(transitions.get(0), transitions.get(0).getTarget().getRel(), transitions.get(0).getLabel().contains("Debit") ? "/FundsTransfers()?$filter=DebitAcctNo eq '123'" : "/FundsTransfers()?$filter=CreditAcctNo eq '123'", HttpMethod.GET)); links.add(new Link(transitions.get(1), transitions.get(1).getTarget().getRel(), transitions.get(1).getLabel().contains("Debit") ? "/FundsTransfers()?$filter=DebitAcctNo eq '123'" : "/FundsTransfers()?$filter=CreditAcctNo eq '123'", HttpMethod.GET)); EntityResource<OEntity> entityResource = new EntityResource<OEntity>(mock(OEntity.class)); entityResource.setLinks(links); provider.processLinks(entityResource); Collection<Link> processedLinks = entityResource.getLinks(); assertEquals(2, processedLinks.size()); Iterator<Link> iterator = processedLinks.iterator(); Link debitLink = iterator.next(); Link creditLink = iterator.next(); //Link relation should contain MS-DATA base uri + /related/ + navigation property. However, the nav. property in this case is NOT the EntitySet name //but a transition ID identifying the link (the link title at the moment). It does not fully comply with OData but this one does not cater for multiple links to the same target. assertEquals("Credit funds transfers", creditLink.getTitle()); assertEquals("/FundsTransfers()?$filter=CreditAcctNo eq '123'", creditLink.getHref()); assertEquals("http://schemas.microsoft.com/ado/2007/08/dataservices/related/FundsTransfers", creditLink.getRel()); assertEquals("Debit funds transfers", debitLink.getTitle()); assertEquals("/FundsTransfers()?$filter=DebitAcctNo eq '123'", debitLink.getHref()); assertEquals("http://schemas.microsoft.com/ado/2007/08/dataservices/related/FundsTransfers", debitLink.getRel()); } @Test public void testSingleLinkFeedToCollectionSameEntity() throws Exception { // initialise the thread local request context with requestUri and baseUri RequestContext ctx = new RequestContext("http://localhost:8080/responder/rest", "/FundsTransfers", null); RequestContext.setRequestContext(ctx); //Create rsm ResourceState initial = new ResourceState("ServiceDocument", "ServiceDocument", new ArrayList<Action>(), "/"); ResourceState fundsTransfers = new CollectionResourceState("FundsTransfer", "FundsTransfers", new ArrayList<Action>(), "/FundsTransfers"); ResourceState fundsTransfersIAuth = new CollectionResourceState("FundsTransfer", "FundsTransfersIAuth", new ArrayList<Action>(), "/FundsTransfersIAuth"); fundsTransfers.addTransition(new Transition.Builder().method(HttpMethod.GET).target(fundsTransfersIAuth).label("Unauthorised input records").build()); initial.addTransition(new Transition.Builder().method(HttpMethod.GET) .target(fundsTransfers) .build()); ResourceStateMachine rsm = new ResourceStateMachine(initial); //Create collection resource CollectionResource<Entity> cr = new CollectionResource<Entity>("FundsTransfers", new ArrayList<EntityResource<Entity>>()); List<Link> links = new ArrayList<Link>(); links.add(createLink(rsm, fundsTransfers.getTransition(fundsTransfersIAuth), null, null, null)); cr.setLinks(links); GenericEntity<CollectionResource<Entity>> ge = new GenericEntity<CollectionResource<Entity>>(cr) {}; //Create provider AtomXMLProvider p = new AtomXMLProvider(createMockMetadataOData4j(createMockEdmDataServices("FundsTransfers")), mock(Metadata.class), rsm, null); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI(ctx.getBasePath())); when(uriInfo.getPath()).thenReturn(ctx.getRequestUri()); p.setUriInfo(uriInfo); //Serialize resource ByteArrayOutputStream bos = new ByteArrayOutputStream(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, MediaType.APPLICATION_ATOM_XML_TYPE, null, bos); String responseString = new String(bos.toByteArray(), "UTF-8"); System.out.println(responseString); //Check response XMLUnit.setIgnoreWhitespace(true); Diff myDiff = XMLUnit.compareXML(readTextFile(EMPTY_FUNDS_TRANSFERS_FEED_XML), responseString); myDiff.overrideDifferenceListener(new IgnoreNamedElementsXMLDifferenceListener("updated")); if(!myDiff.similar()) { fail(myDiff.toString()); } } private final static String COMPANY_COLLECTION_LINK_COLLECTION = "<?xml version='1.0' encoding='UTF-8'?>" + "<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" xml:base=\"http://localhost:8080/responder/rest/MockCompany001/\">" + "<title type=\"text\">FundsTransfers</title>" + "<id>http://localhost:8080/responder/rest/MockCompany001/FundsTransfers</id>" + "<updated>2014-02-20T09:27:18Z</updated>" + "<link rel=\"http://schemas.microsoft.com/ado/2007/08/dataservices/related/FundsTransfers\" title=\"Unauthorised input records\" href=\"FundsTransfersIAuth\">" + "</link>" + "</feed>"; private ResourceStateMachine createCollectionToCollectionRSM() { ResourceState initial = new ResourceState("ServiceDocument", "ServiceDocument", new ArrayList<Action>(), "/{companyid}"); ResourceState fundsTransfers = new CollectionResourceState("FundsTransfer", "FundsTransfers", new ArrayList<Action>(), "/{companyid}/FundsTransfers"); ResourceState fundsTransfersIAuth = new CollectionResourceState("FundsTransfer", "FundsTransfersIAuth", new ArrayList<Action>(), "/{companyid}/FundsTransfersIAuth"); fundsTransfers.addTransition(new Transition.Builder().method(HttpMethod.GET).target(fundsTransfersIAuth).label("Unauthorised input records").build()); initial.addTransition(new Transition.Builder().method(HttpMethod.GET) .target(fundsTransfers) .build()); ResourceStateMachine rsm = new ResourceStateMachine(initial); return rsm; } @Test public void testCollectionToCollectionEntityWithCompanyBasePath() throws Exception { // initialise the thread local request context with requestUri and baseUri RequestContext ctx = new RequestContext("http://localhost:8080/responder/rest", "/MockCompany001/FundsTransfers", null); RequestContext.setRequestContext(ctx); //Create rsm ResourceStateMachine rsm = createCollectionToCollectionRSM(); ResourceState fundsTransfers = rsm.getResourceStateByName("FundsTransfers"); ResourceState fundsTransfersIAuth = rsm.getResourceStateByName("FundsTransfersIAuth"); //Create collection resource CollectionResource<Entity> cr = new CollectionResource<Entity>("FundsTransfers", new ArrayList<EntityResource<Entity>>()); List<Link> links = new ArrayList<Link>(); MultivaluedMap<String, String> pathParameters = new MultivaluedMapImpl<String>(); pathParameters.add("companyid", "MockCompany001"); links.add(createLink(rsm, fundsTransfers.getTransition(fundsTransfersIAuth), null, pathParameters, null)); cr.setLinks(links); GenericEntity<CollectionResource<Entity>> ge = new GenericEntity<CollectionResource<Entity>>(cr) {}; //Create provider AtomXMLProvider p = new AtomXMLProvider(createMockMetadataOData4j(createMockEdmDataServices("FundsTransfers")), createMockMetadata("MyModel"), rsm, mock(Transformer.class)); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI(ctx.getBasePath())); when(uriInfo.getPath()).thenReturn(ctx.getRequestUri()); p.setUriInfo(uriInfo); //Serialize resource ByteArrayOutputStream bos = new ByteArrayOutputStream(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, MediaType.APPLICATION_ATOM_XML_TYPE, null, bos); String responseString = new String(bos.toByteArray(), "UTF-8"); System.out.println(responseString); //Check response assertTrue(responseString.contains("href=\"FundsTransfersIAuth\"")); //Check response XMLUnit.setIgnoreWhitespace(true); Diff myDiff = XMLUnit.compareXML(COMPANY_COLLECTION_LINK_COLLECTION, responseString); myDiff.overrideDifferenceListener(new IgnoreNamedElementsXMLDifferenceListener("updated")); if(!myDiff.similar()) { fail(myDiff.toString()); } } @Test public void testCollectionToCollectionOEntityWithCompanyBasePath() throws Exception { // initialise the thread local request context with requestUri and baseUri RequestContext ctx = new RequestContext("http://localhost:8080/responder/rest", "/MockCompany001/FundsTransfers", null); RequestContext.setRequestContext(ctx); //Create rsm ResourceStateMachine rsm = createCollectionToCollectionRSM(); ResourceState fundsTransfers = rsm.getResourceStateByName("FundsTransfers"); ResourceState fundsTransfersIAuth = rsm.getResourceStateByName("FundsTransfersIAuth"); //Create collection resource CollectionResource<OEntity> cr = new CollectionResource<OEntity>("FundsTransfers", new ArrayList<EntityResource<OEntity>>()); List<Link> links = new ArrayList<Link>(); MultivaluedMap<String, String> pathParameters = new MultivaluedMapImpl<String>(); pathParameters.add("companyid", "MockCompany001"); links.add(createLink(rsm, fundsTransfers.getTransition(fundsTransfersIAuth), null, pathParameters, null)); cr.setLinks(links); GenericEntity<CollectionResource<OEntity>> ge = new GenericEntity<CollectionResource<OEntity>>(cr) {}; //Create provider AtomXMLProvider p = new AtomXMLProvider(createMockMetadataOData4j(createMockEdmDataServices("FundsTransfers")), createMockMetadata("MyModel"), rsm, mock(Transformer.class)); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI(ctx.getBasePath())); when(uriInfo.getPath()).thenReturn(ctx.getRequestUri()); p.setUriInfo(uriInfo); //Serialize resource ByteArrayOutputStream bos = new ByteArrayOutputStream(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, MediaType.APPLICATION_ATOM_XML_TYPE, null, bos); String responseString = new String(bos.toByteArray(), "UTF-8"); System.out.println(responseString); //Check response assertTrue(responseString.contains("href=\"FundsTransfersIAuth\"")); //Check response XMLUnit.setIgnoreWhitespace(true); Diff myDiff = XMLUnit.compareXML(COMPANY_COLLECTION_LINK_COLLECTION, responseString); myDiff.overrideDifferenceListener(new IgnoreNamedElementsXMLDifferenceListener("updated")); if(!myDiff.similar()) { fail(myDiff.toString()); } } private final static String ENTITY_COLLECTION_LINK_ITEM = "<?xml version='1.0' encoding='utf-8'?>" + "<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" " + "xml:base=\"http://localhost:8080/responder/rest/\">" + "<title type=\"text\">Flight</title>" + "<id>http://localhost:8080/responder/rest/FundsTransfers</id>" + "<updated>2014-02-20T08:56:32Z</updated>" + "<m:count>100</m:count>" + "<entry><id>http://localhost:8080/responder/rest/Flight('1')</id>" + "<title type=\"text\" />" + "<updated>2014-02-20T08:56:32Z</updated>" + "<author><name /></author>" + "<link rel=\"self\" title=\"Link to entity\" href=\"Flights('1')\" profile=\"item\" />" + "<category term=\"FlightModelModel.Flight\" scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\" />" + "<content type=\"application/xml\">" + "<m:properties><d:id>1</d:id><d:flight>EI218</d:flight></m:properties></content>" + "</entry>" + "</feed>"; private final static String OENTITY_COLLECTION_LINK_ITEM = "<?xml version='1.0' encoding='utf-8'?>" + "<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" " + "xml:base=\"http://localhost:8080/responder/rest/\">" + "<title type=\"text\">Flight</title>" + "<id>http://localhost:8080/responder/rest/FundsTransfers</id>" + "<updated>2014-02-20T08:56:32Z</updated>" + "<m:count>30</m:count>" + "<entry m:etag=\"07u1PAxpJ7RGGblAB8FicpJF18wtzngF71WGQUMlABE=\"><id>http://localhost:8080/responder/rest/Flight('1')</id>" + "<title type=\"text\" />" + "<updated>2014-02-20T08:56:32Z</updated>" + "<author><name /></author>" + "<link rel=\"self\" title=\"Link to entity\" href=\"Flights('1')\" />" + "<link rel=\"http://schemas.microsoft.com/ado/2007/08/dataservices/related/FlightView\" type=\"application/atom+xml;type=entry\" title=\"Link to entity with id 1\" href=\"Flights('1')/view\" id=\"1\" />" + "<link rel=\"http://schemas.microsoft.com/ado/2007/08/dataservices/related/FlightView\" type=\"application/atom+xml;type=entry\" title=\"Link to entity with id 2\" href=\"Flights('1')/view\" id=\"2\" />" + "<category term=\"FlightModelModel.Flight\" scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\" />" + "<content type=\"application/xml\">" + "<m:properties><d:id>1</d:id><d:flight>EI218</d:flight></m:properties></content>" + "</entry>" + "</feed>"; private ResourceStateMachine createCollectionToItemRSM(Transformer transformer) { List<Action> serviceDocActions = new ArrayList<Action>(); Action action = mock(Action.class); when(action.getMethod()).thenReturn("GET"); serviceDocActions.add(action); List<Action> flightsActions = new ArrayList<Action>(); flightsActions.add(action); List<Action> flightActions = new ArrayList<Action>(); flightActions.add(action); ResourceState initial = new ResourceState("ServiceDocument", "ServiceDocument", serviceDocActions, "/"); ResourceState flights = new CollectionResourceState("Flight", "Flights", flightsActions, "/Flights"); ResourceState flight = new ResourceState("Flight", "Flight", flightActions, "/Flights('{id}')"); ResourceState flightView = new ResourceState("FlightView", "FlightView", flightActions, "/Flights('{id}')/view"); flights.addTransition(new Transition.Builder().method(HttpMethod.GET).target(flight).label("Link to entity").build()); flights.addTransition(new Transition.Builder().method(HttpMethod.GET).target(flightView).label("Link to entity with id 1").linkId("1").build()); flights.addTransition(new Transition.Builder().method(HttpMethod.GET).target(flightView).label("Link to entity with id 2").linkId("2").build()); initial.addTransition(new Transition.Builder().method(HttpMethod.GET) .target(flights) .build()); ResourceStateMachine rsm = new ResourceStateMachine(initial, transformer); return rsm; } @Test public void testCollectionToItemEntityBasePath() throws Exception { // initialise the thread local request context with requestUri and baseUri RequestContext ctx = new RequestContext("http://localhost:8080/responder/rest", "/FundsTransfers", null); RequestContext.setRequestContext(ctx); // metadata EdmDataServices edmDataServices = createMockFlightEdmDataServices(); Metadata metadata = createMockFlightMetadata(); // Create rsm ResourceStateMachine rsm = createCollectionToItemRSM(new EntityTransformer()); ResourceState flights = rsm.getResourceStateByName("Flights"); ResourceState flight = rsm.getResourceStateByName("Flight"); // Build up some entities List<EntityResource<Entity>> entities = new ArrayList<EntityResource<Entity>>(); EntityResource<Entity> er = createMockEntityResourceEntity("Flight"); List<Link> links = new ArrayList<Link>(); MultivaluedMap<String, String> pathParameters = new MultivaluedMapImpl<String>(); links.add(createLink(rsm, flights.getTransition(flight), er.getEntity(), pathParameters, null)); er.setLinks(links); entities.add(er); // Create collection resource CollectionResource<Entity> cr = new CollectionResource<Entity>("Flight", entities); cr.setInlineCount(100); GenericEntity<CollectionResource<Entity>> ge = new GenericEntity<CollectionResource<Entity>>(cr) {}; //Create provider AtomXMLProvider p = new AtomXMLProvider(createMockMetadataOData4j(edmDataServices), metadata, rsm, mock(Transformer.class)); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI(ctx.getBasePath())); when(uriInfo.getPath()).thenReturn(ctx.getRequestUri()); p.setUriInfo(uriInfo); //Serialize resource ByteArrayOutputStream bos = new ByteArrayOutputStream(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, MediaType.APPLICATION_ATOM_XML_TYPE, null, bos); String responseString = new String(bos.toByteArray(), "UTF-8"); System.out.println(responseString); //Check response XMLUnit.setIgnoreWhitespace(true); Diff myDiff = XMLUnit.compareXML(ENTITY_COLLECTION_LINK_ITEM, responseString); myDiff.overrideDifferenceListener(new IgnoreNamedElementsXMLDifferenceListener("updated")); if(!myDiff.similar()) { fail(myDiff.toString()); } } @Test public void testCollectionToItemOEntityBasePath() throws Exception { // initialise the thread local request context with requestUri and baseUri RequestContext ctx = new RequestContext("http://localhost:8080/responder/rest", "/FundsTransfers", null); RequestContext.setRequestContext(ctx); // metadata EdmDataServices edmDataServices = createMockFlightEdmDataServices(); Metadata metadata = createMockFlightMetadata(); // Create rsm ResourceStateMachine rsm = createCollectionToItemRSM(new OEntityTransformer()); ResourceState flights = rsm.getResourceStateByName("Flights"); // Build up some entities List<EntityResource<OEntity>> oentities = new ArrayList<EntityResource<OEntity>>(); EntityResource<OEntity> er = createMockEntityResourceOEntity(edmDataServices.findEdmEntitySet("Flights"), "07u1PAxpJ7RGGblAB8FicpJF18wtzngF71WGQUMlABE="); List<Link> links = new ArrayList<Link>(); MultivaluedMap<String, String> pathParameters = new MultivaluedMapImpl<String>(); for (Transition transition : flights.getTransitions()) { links.add(createLink(rsm, transition, er.getEntity(), pathParameters, null)); } er.setLinks(links); oentities.add(er); // Create collection resource CollectionResource<OEntity> cr = new CollectionResource<OEntity>("Flights", oentities); cr.setInlineCount(30); GenericEntity<CollectionResource<OEntity>> ge = new GenericEntity<CollectionResource<OEntity>>(cr) {}; //Create provider AtomXMLProvider p = new AtomXMLProvider(createMockMetadataOData4j(edmDataServices), metadata, rsm, mock(Transformer.class)); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI(ctx.getBasePath())); when(uriInfo.getPath()).thenReturn(ctx.getRequestUri()); p.setUriInfo(uriInfo); //Serialize resource ByteArrayOutputStream bos = new ByteArrayOutputStream(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, MediaType.APPLICATION_ATOM_XML_TYPE, null, bos); String responseString = new String(bos.toByteArray(), "UTF-8"); System.out.println(responseString); //Check response XMLUnit.setIgnoreWhitespace(true); Diff myDiff = XMLUnit.compareXML(OENTITY_COLLECTION_LINK_ITEM, responseString); myDiff.overrideDifferenceListener(new IgnoreNamedElementsXMLDifferenceListener("updated")); if(!myDiff.similar()) { fail(myDiff.toString()); } } private final static String ENTITY_COMPANY_COLLECTION_LINK_ITEM = "<?xml version='1.0' encoding='utf-8'?>" + "<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" " + "xml:base=\"http://localhost:8080/responder/rest/MockCompany001/\">" + "<title type=\"text\">Flight</title>" + "<id>http://localhost:8080/responder/rest/MockCompany001/FundsTransfers</id>" + "<updated>2014-02-20T08:56:32Z</updated>" + "<entry><id>http://localhost:8080/responder/rest/MockCompany001/Flight('1')</id>" + "<title type=\"text\" />" + "<updated>2014-02-20T08:56:32Z</updated>" + "<author><name /></author>" + "<link rel=\"self\" title=\"Link to entity\" href=\"Flights('1')\" profile=\"item\" />" + "<category term=\"FlightModelModel.Flight\" scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\" />" + "<content type=\"application/xml\">" + "<m:properties><d:id>1</d:id><d:flight>EI218</d:flight></m:properties></content>" + "</entry>" + "</feed>"; private final static String OENTITY_COMPANY_COLLECTION_LINK_ITEM = "<?xml version='1.0' encoding='utf-8'?>" + "<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" " + "xml:base=\"http://localhost:8080/responder/rest/MockCompany001/\">" + "<title type=\"text\">Flight</title>" + "<id>http://localhost:8080/responder/rest/MockCompany001/FundsTransfers</id>" + "<updated>2014-02-20T08:56:32Z</updated>" + "<entry><id>http://localhost:8080/responder/rest/MockCompany001/Flight('1')</id>" + "<title type=\"text\" />" + "<updated>2014-02-20T08:56:32Z</updated>" + "<author><name /></author>" + "<link rel=\"self\" title=\"Link to entity\" href=\"Flights('1')\" />" + "<category term=\"FlightModelModel.Flight\" scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\" />" + "<content type=\"application/xml\">" + "<m:properties><d:id>1</d:id><d:flight>EI218</d:flight></m:properties></content>" + "</entry>" + "</feed>"; private ResourceStateMachine createCompanyCollectionToItemRSM(Transformer transformer) { List<Action> serviceDocActions = new ArrayList<Action>(); Action action = mock(Action.class); when(action.getMethod()).thenReturn("GET"); serviceDocActions.add(action); List<Action> flightsActions = new ArrayList<Action>(); flightsActions.add(action); List<Action> flightActions = new ArrayList<Action>(); flightActions.add(action); ResourceState initial = new ResourceState("ServiceDocument", "ServiceDocument", serviceDocActions, "/{companyid}"); ResourceState flights = new CollectionResourceState("Flight", "Flights", flightsActions, "/{companyid}/Flights"); ResourceState flight = new ResourceState("Flight", "Flight", flightActions, "/{companyid}/Flights('{id}')"); flights.addTransition(new Transition.Builder().method(HttpMethod.GET).target(flight).label("Link to entity").build()); initial.addTransition(new Transition.Builder().method(HttpMethod.GET) .target(flights) .build()); ResourceStateMachine rsm = new ResourceStateMachine(initial, transformer); return rsm; } @Test public void testCollectionToItemEntityWithCompanyBasePath() throws Exception { // initialise the thread local request context with requestUri and baseUri RequestContext ctx = new RequestContext("http://localhost:8080/responder/rest", "/MockCompany001/FundsTransfers", null); RequestContext.setRequestContext(ctx); // metadata EdmDataServices edmDataServices = createMockFlightEdmDataServices(); Metadata metadata = createMockFlightMetadata(); // Create rsm ResourceStateMachine rsm = createCompanyCollectionToItemRSM(new EntityTransformer()); ResourceState flights = rsm.getResourceStateByName("Flights"); ResourceState flight = rsm.getResourceStateByName("Flight"); // Build up some entities List<EntityResource<Entity>> entities = new ArrayList<EntityResource<Entity>>(); EntityResource<Entity> er = createMockEntityResourceEntity("Flight"); List<Link> links = new ArrayList<Link>(); MultivaluedMap<String, String> pathParameters = new MultivaluedMapImpl<String>(); pathParameters.add("companyid", "MockCompany001"); links.add(createLink(rsm, flights.getTransition(flight), er.getEntity(), pathParameters, null)); er.setLinks(links); entities.add(er); // Create collection resource CollectionResource<Entity> cr = new CollectionResource<Entity>("Flight", entities); GenericEntity<CollectionResource<Entity>> ge = new GenericEntity<CollectionResource<Entity>>(cr) {}; //Create provider AtomXMLProvider p = new AtomXMLProvider(createMockMetadataOData4j(edmDataServices), metadata, rsm, mock(Transformer.class)); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI(ctx.getBasePath())); when(uriInfo.getPath()).thenReturn(ctx.getRequestUri()); p.setUriInfo(uriInfo); //Serialize resource ByteArrayOutputStream bos = new ByteArrayOutputStream(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, MediaType.APPLICATION_ATOM_XML_TYPE, null, bos); String responseString = new String(bos.toByteArray(), "UTF-8"); System.out.println(responseString); //Check response XMLUnit.setIgnoreWhitespace(true); Diff myDiff = XMLUnit.compareXML(ENTITY_COMPANY_COLLECTION_LINK_ITEM, responseString); myDiff.overrideDifferenceListener(new IgnoreNamedElementsXMLDifferenceListener("updated")); if(!myDiff.similar()) { fail(myDiff.toString()); } } @Test public void testCollectionToItemOEntityWithCompanyBasePath() throws Exception { // initialise the thread local request context with requestUri and baseUri RequestContext ctx = new RequestContext("http://localhost:8080/responder/rest", "/MockCompany001/FundsTransfers", null); RequestContext.setRequestContext(ctx); // metadata EdmDataServices edmDataServices = createMockFlightEdmDataServices(); Metadata metadata = createMockFlightMetadata(); // Create rsm ResourceStateMachine rsm = createCompanyCollectionToItemRSM(new OEntityTransformer()); ResourceState flights = rsm.getResourceStateByName("Flights"); ResourceState flight = rsm.getResourceStateByName("Flight"); // Build up some entities List<EntityResource<OEntity>> oentities = new ArrayList<EntityResource<OEntity>>(); EntityResource<OEntity> er = createMockEntityResourceOEntity(edmDataServices.findEdmEntitySet("Flights")); List<Link> links = new ArrayList<Link>(); MultivaluedMap<String, String> pathParameters = new MultivaluedMapImpl<String>(); pathParameters.add("companyid", "MockCompany001"); links.add(createLink(rsm, flights.getTransition(flight), er.getEntity(), pathParameters, null)); er.setLinks(links); oentities.add(er); // Create collection resource CollectionResource<OEntity> cr = new CollectionResource<OEntity>("Flights", oentities); GenericEntity<CollectionResource<OEntity>> ge = new GenericEntity<CollectionResource<OEntity>>(cr) {}; //Create provider AtomXMLProvider p = new AtomXMLProvider(createMockMetadataOData4j(edmDataServices), metadata, rsm, mock(Transformer.class)); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI(ctx.getBasePath())); when(uriInfo.getPath()).thenReturn(ctx.getRequestUri()); p.setUriInfo(uriInfo); //Serialize resource ByteArrayOutputStream bos = new ByteArrayOutputStream(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, MediaType.APPLICATION_ATOM_XML_TYPE, null, bos); String responseString = new String(bos.toByteArray(), "UTF-8"); System.out.println(responseString); //Check response XMLUnit.setIgnoreWhitespace(true); Diff myDiff = XMLUnit.compareXML(OENTITY_COMPANY_COLLECTION_LINK_ITEM, responseString); myDiff.overrideDifferenceListener(new IgnoreNamedElementsXMLDifferenceListener("updated")); if(!myDiff.similar()) { fail(myDiff.toString()); } } @Test public void testLinkEntryToEntity() { List<Action> serviceDocActions = new ArrayList<Action>(); Action action = mock(Action.class); when(action.getMethod()).thenReturn("GET"); serviceDocActions.add(action); List<Action> customerAccountActions = new ArrayList<Action>(); customerAccountActions.add(action); List<Action> currnecyActions = new ArrayList<Action>(); currnecyActions.add(action); ResourceState initial = new ResourceState("ServiceDocument", "ServiceDocument", serviceDocActions, "/"); ResourceState account = new ResourceState("Account", "customerAccount", customerAccountActions, "/CustomerAccounts('{id}')"); ResourceState currency = new ResourceState("Currency", "currency", currnecyActions, "/Currencys('{id}')"); account.addTransition(new Transition.Builder().method(HttpMethod.GET).target(currency).label("currency").linkId("123456").build()); initial.addTransition(new Transition.Builder().method(HttpMethod.GET) .target(account) .build()); ResourceStateMachine rsm = new ResourceStateMachine(initial); AtomXMLProvider provider = new AtomXMLProvider(createMockMetadataOData4j(createMockEdmDataServices("Currencys")), createMockMetadata("MyModel"), rsm, mock(Transformer.class)); Transition t = account.getTransition(currency); List<Link> links = new ArrayList<Link>(); links.add(new Link(t, t.getTarget().getRel(), "/Currencys('USD')", HttpMethod.GET)); EntityResource<OEntity> entityResource = new EntityResource<OEntity>(mock(OEntity.class)); entityResource.setLinks(links); provider.processLinks(entityResource); Collection<Link> processedLinks = entityResource.getLinks(); assertEquals(1, processedLinks.size()); Link theLink = processedLinks.iterator().next(); //Link relation should contain MS-DATA base uri + /related/ + navigation property. The nav. property in this case is the entity (type) name assertEquals("http://schemas.microsoft.com/ado/2007/08/dataservices/related/Currency", theLink.getRel()); assertEquals("currency", theLink.getTitle()); assertEquals("/Currencys('USD')", theLink.getHref()); assertEquals("123456", theLink.getLinkId()); } @Test public void testEmbeddedEntry() throws URISyntaxException { // Create the RIM ResourceState initial = new ResourceState("ServiceDocument", "ServiceDocument", new ArrayList<Action>(), "/"); ResourceState parent = new ResourceState("Flight", "parent", new ArrayList<Action>(), "/Flight('{id}')"); ResourceState child = new ResourceState("Flight", "child", new ArrayList<Action>(), "/Flight('id')/child"); parent.addTransition(new Transition.Builder().method(HttpMethod.GET).target(child).label("My Child Link").linkId("123456").build()); initial.addTransition(new Transition.Builder().method(HttpMethod.GET) .target(parent) .build()); ResourceStateMachine rsm = new ResourceStateMachine(initial); EdmDataServices edmDataServices = createMockFlightEdmDataServices(); EdmEntitySet persons = edmDataServices.findEdmEntitySet("Flight"); EntityResource<OEntity> childResource = createMockEntityResourceOEntity(persons); List<OLink> olinks = new ArrayList<OLink>(); olinks.add(OLinks.relatedEntityInline("relation", "child", null, childResource.getEntity())); List<OProperty<?>> properties = new ArrayList<OProperty<?>>(); properties.add(OProperties.string("name", "blah")); OEntity accountOEntity = OEntities.create(persons, OEntityKey.create("USD"), properties, olinks); EntityResource<OEntity> accountEntityResource = new EntityResource<OEntity>(accountOEntity); List<Link> links = new ArrayList<Link>(); links.add(new Link("title", "http://schemas.microsoft.com/ado/2007/08/dataservices/related/title", "Flight('USD')/child", "type", null)); accountEntityResource.setLinks(links); AtomXMLProvider provider = new AtomXMLProvider(createMockMetadataOData4j(edmDataServices), createMockMetadata("MyModel"), rsm, mock(Transformer.class)); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI("http://localhost:8080/responder/rest")); when(uriInfo.getPath()).thenReturn("/mock"); provider.setUriInfo(uriInfo); provider.addExpandedLinks(accountEntityResource); Map<Transition,RESTResource> embeddedResources = accountEntityResource.getEmbedded(); assertNotNull(embeddedResources); assertEquals(1, embeddedResources.size()); } @Test public void testSingleLinkToCollectionNotEntitySet() { ResourceState serviceRoot = new ResourceState("SD", "ServiceDocument", new ArrayList<Action>(), "/"); ResourceState fundsTransfer = new ResourceState("FundsTransfer", "fundsTransfer", new ArrayList<Action>(), "/FundsTransfers('{id}')"); ResourceState fundsTransfersIAuth = new CollectionResourceState("Dummy", "FundsTransfersIAuth", new ArrayList<Action>(), "/FundsTransfersIAuth"); serviceRoot.addTransition(new Transition.Builder().flags(Transition.AUTO).target(fundsTransfer).build()); fundsTransfer.addTransition(new Transition.Builder().method(HttpMethod.GET).target(fundsTransfersIAuth).label("Unauthorised funds transfers").build()); //FundsTransfersIAuth is not an entity set EdmDataServices edmDataServices = createMockEdmDataServices("FundsTransfers"); when(edmDataServices.getEdmEntitySet(any(EdmEntityType.class))).thenThrow(new NotFoundException("EntitySet for entity type Dummy has not been found")); MetadataOData4j mockMetadataOData4j = createMockMetadataOData4j(edmDataServices); when(mockMetadataOData4j.getEdmEntitySetByEntityName(anyString())).thenThrow(new NotFoundException("EntitySet for entity type Dummy has not been found"));; AtomXMLProvider provider = new AtomXMLProvider(mockMetadataOData4j, createMockMetadata("MyModel"), new ResourceStateMachine(serviceRoot), mock(Transformer.class)); Transition t = fundsTransfer.getTransition(fundsTransfersIAuth); List<Link> links = new ArrayList<Link>(); links.add(new Link(t, t.getTarget().getRel(), "/FundsTransfersIAuth()", HttpMethod.GET)); EntityResource<OEntity> entityResource = new EntityResource<OEntity>(mock(OEntity.class)); entityResource.setLinks(links); provider.processLinks(entityResource); Collection<Link> processedLinks = entityResource.getLinks(); assertEquals(1, processedLinks.size()); Link theLink = processedLinks.iterator().next(); //Link relation should contain MS-DATA base uri + /related/ + navigation property. The nav. property in this case would be the EntitySet name, however, it is not //an entity set so use the name of the target state. assertEquals("http://schemas.microsoft.com/ado/2007/08/dataservices/related/FundsTransfersIAuth", theLink.getRel()); assertEquals("Unauthorised funds transfers", theLink.getTitle()); assertEquals("/FundsTransfersIAuth()", theLink.getHref()); } @Test public void testSingleLinkOEntityFeedToNonEntitySet() throws Exception { // initialise the thread local request context with requestUri and baseUri RequestContext ctx = new RequestContext("http://localhost:8080/responder/rest", "/FundsTransfers", null); RequestContext.setRequestContext(ctx); //Create rsm ResourceState serviceRoot = new ResourceState("SD", "initial", new ArrayList<Action>(), "/"); ResourceState fundsTransfers = new CollectionResourceState("FundsTransfer", "FundsTransfers", new ArrayList<Action>(), "/FundsTransfers"); ResourceState fundsTransfersIAuth = new CollectionResourceState("FundsTransfer", "FundsTransfersIAuth", new ArrayList<Action>(), "/FundsTransfersIAuth"); serviceRoot.addTransition(new Transition.Builder().flags(Transition.AUTO).target(fundsTransfers).build()); fundsTransfers.addTransition(new Transition.Builder().method(HttpMethod.GET).target(fundsTransfersIAuth).label("Unauthorised input records").build()); ResourceStateMachine rsm = new ResourceStateMachine(fundsTransfers); //Create collection resource CollectionResource<OEntity> cr = new CollectionResource<OEntity>("FundsTransfers", new ArrayList<EntityResource<OEntity>>()); List<Link> links = new ArrayList<Link>(); links.add(createLink(rsm, fundsTransfers.getTransition(fundsTransfersIAuth), null, null, null)); cr.setLinks(links); GenericEntity<CollectionResource<OEntity>> ge = new GenericEntity<CollectionResource<OEntity>>(cr) {}; //Create provider EdmDataServices edmDataServices = createMockEdmDataServices("FundsTransfers"); Metadata metadata = mock(Metadata.class); when(metadata.getModelName()).thenReturn("MyModel"); MockAtomXMLProvider p = new MockAtomXMLProvider(createMockMetadataOData4j(edmDataServices), metadata); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI(ctx.getBasePath())); when(uriInfo.getPath()).thenReturn(ctx.getRequestUri()); p.setUriInfo(uriInfo); //Serialize resource ByteArrayOutputStream bos = new ByteArrayOutputStream(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, MediaType.APPLICATION_ATOM_XML_TYPE, null, bos); String responseString = new String(bos.toByteArray(), "UTF-8"); System.out.println(responseString); //Check response XMLUnit.setIgnoreWhitespace(true); Diff myDiff = XMLUnit.compareXML(readTextFile(EMPTY_FUNDS_TRANSFERS_FEED_XML), responseString); myDiff.overrideDifferenceListener(new IgnoreNamedElementsXMLDifferenceListener("updated")); if(!myDiff.similar()) { fail(myDiff.toString()); } } @Test public void testWriteEntityResourceGenericError_AtomXML() throws Exception { EdmEntitySet ees = createMockEdmEntitySet(); EdmDataServices mockEDS = createMockFlightEdmDataServices(); when(mockEDS.getEdmEntitySet(anyString())).thenReturn(ees); Metadata mockMetadata = createMockFlightMetadata(); EntityResource<GenericError> er = createMockEntityResourceGenericError(); //Wrap entity resource into a JAX-RS GenericEntity instance GenericEntity<EntityResource<GenericError>> ge = new GenericEntity<EntityResource<GenericError>>(er) {}; //Create provider MockAtomXMLProvider p = new MockAtomXMLProvider(createMockMetadataOData4j(mockEDS), mockMetadata); UriInfo uriInfo = mock(UriInfo.class); URI uri = new URI("http://localhost:8080/responder/rest/"); when(uriInfo.getBaseUri()).thenReturn(uri); when(uriInfo.getPath()).thenReturn("Flight(123)"); p.setUriInfo(uriInfo); //Serialize resource ByteArrayOutputStream bos = new ByteArrayOutputStream(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, MediaType.APPLICATION_ATOM_XML_TYPE, null, bos); String responseString = new String(bos.toByteArray(), "UTF-8"); //Check response XMLUnit.setIgnoreWhitespace(true); Diff myDiff = XMLUnit.compareXML(readTextFile(ATOM_GENERIC_ERROR_ENTRY_XML), responseString); myDiff.overrideDifferenceListener(new IgnoreNamedElementsXMLDifferenceListener("updated")); if(!myDiff.similar()) { fail(myDiff.toString()); } } @Test public void testWriteEntityResourceAcceptAtomSvc() throws Exception { EdmEntitySet ees = createMockEdmEntitySet(); EdmDataServices mockEDS = createMockFlightEdmDataServices(); when(mockEDS.getEdmEntitySet(anyString())).thenReturn(ees); Metadata mockMetadata = createMockFlightMetadata(); EntityResource<GenericError> er = createMockEntityResourceGenericError(); GenericEntity<EntityResource<GenericError>> ge = new GenericEntity<EntityResource<GenericError>>(er) {}; //Create provider MockAtomXMLProvider p = new MockAtomXMLProvider(createMockMetadataOData4j(mockEDS), mockMetadata); UriInfo uriInfo = mock(UriInfo.class); URI uri = new URI("http://localhost:8080/responder/rest/"); when(uriInfo.getBaseUri()).thenReturn(uri); when(uriInfo.getPath()).thenReturn("Flight(123)"); p.setUriInfo(uriInfo); //Set accept header to atomsvc+xml MultivaluedMap<String, Object> httpHeaders = new MultivaluedMapImpl<Object>(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, ExtendedMediaTypes.APPLICATION_ATOMSVC_XML_TYPE, httpHeaders, new ByteArrayOutputStream()); //Make sure the response is atom+xml assertEquals(MediaType.APPLICATION_ATOM_XML, httpHeaders.getFirst(HttpHeaders.CONTENT_TYPE)); //content length must be greater than zero assertThat(Integer.parseInt((String)httpHeaders.getFirst(HttpHeaders.CONTENT_LENGTH)), greaterThan(0)); } @Test public void testWriteEntityResourceCustomError_AtomXML() throws Exception { EdmEntitySet ees = createMockEdmEntitySet(); EdmDataServices mockEDS = createMockFlightEdmDataServices(); when(mockEDS.getEdmEntitySet(anyString())).thenReturn(ees); Metadata mockMetadata = createMockFlightMetadata(); EntityResource<CustomError> er = CommandHelper.createEntityResource("CustomError", new CustomError("My custom error message."), CustomError.class); //Wrap entity resource into a JAX-RS GenericEntity instance GenericEntity<EntityResource<CustomError>> ge = new GenericEntity<EntityResource<CustomError>>(er) {}; //Create provider MockAtomXMLProvider p = new MockAtomXMLProvider(createMockMetadataOData4j(mockEDS), mockMetadata); UriInfo uriInfo = mock(UriInfo.class); URI uri = new URI("http://localhost:8080/responder/rest/"); when(uriInfo.getBaseUri()).thenReturn(uri); when(uriInfo.getPath()).thenReturn("Flight(123)"); p.setUriInfo(uriInfo); //Serialize resource ByteArrayOutputStream bos = new ByteArrayOutputStream(); p.writeTo(ge.getEntity(), ge.getRawType(), ge.getType(), null, MediaType.APPLICATION_ATOM_XML_TYPE, null, bos); String responseString = new String(bos.toByteArray(), "UTF-8"); //Check response XMLUnit.setIgnoreWhitespace(true); Diff myDiff = XMLUnit.compareXML(readTextFile(ATOM_CUSTOM_ERROR_ENTRY_XML), responseString); myDiff.overrideDifferenceListener(new IgnoreNamedElementsXMLDifferenceListener("updated")); if(!myDiff.similar()) { fail(myDiff.toString()); } } private ResourceState createMockResourceState(String name, String entityName, boolean isCollection) { ResourceState state = null; if (isCollection) { state = mock(CollectionResourceState.class); } else { state = mock(ResourceState.class); } when(state.getName()).thenReturn(name); when(state.getEntityName()).thenReturn(entityName); when(state.getRel()).thenReturn(isCollection ? "collection" : "item"); return state; } private Transition createMockTransition(ResourceState source, ResourceState target) { Transition.Builder builder = new Transition.Builder(); builder.source(source); builder.target(target); builder.method("GET"); return builder.build(); } @SuppressWarnings("unchecked") private EntityResource<GenericError> createMockEntityResourceGenericError() { EntityResource<GenericError> er = mock(EntityResource.class); GenericError error = new GenericError("UPSTREAM_SERVER_UNAVAILABLE", "Failed to connect to resource manager."); when(er.getEntity()).thenReturn(error); when(er.getEntityName()).thenReturn("Flight"); when(er.getGenericEntity()).thenReturn(new GenericEntity<EntityResource<GenericError>>(er, er.getClass().getGenericSuperclass())); return er; } /* * Read a text file */ private String readTextFile(String textFile) { InputStream is = this.getClass().getClassLoader().getResourceAsStream(textFile); BufferedReader br = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String read; try { while((read = br.readLine()) != null) { sb.append(read).append(System.getProperty("line.separator")); } } catch(IOException ioe) { fail(ioe.getMessage()); } return sb.toString(); } public ResourceStateMachine mockResourceStateMachine() { ResourceState initial = new ResourceState("ServiceDocument", "ServiceDocument", new ArrayList<Action>(), "/"); ResourceStateMachine rsm = new ResourceStateMachine(initial); return rsm; } @Test public void testBaseUri() throws URISyntaxException { ResourceState initial = new ResourceState("ServiceDocument", "ServiceDocument", new ArrayList<Action>(), "/"); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI("http://localhost:8080/responder/rest")); when(uriInfo.getPath()).thenReturn("/test"); assertEquals("http://localhost:8080/responder/rest/", AtomXMLProvider.getBaseUri(initial, uriInfo)); } @Test public void testBaseUriNested() throws URISyntaxException { ResourceState initial = new ResourceState("ServiceDocument", "ServiceDocument", new ArrayList<Action>(), "/"); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI("http://localhost:8080/responder/rest")); when(uriInfo.getPath()).thenReturn("/test/blah"); assertEquals("http://localhost:8080/responder/rest/", AtomXMLProvider.getBaseUri(initial, uriInfo)); } @Test public void testBaseUriServiceDocumentTemplate() throws URISyntaxException { ResourceState initial = new ResourceState("ServiceDocument", "ServiceDocument", new ArrayList<Action>(), "/{companyid}"); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI("http://localhost:8080/responder/rest")); when(uriInfo.getPath()).thenReturn("/MockCompany001/test"); assertEquals("http://localhost:8080/responder/rest/MockCompany001/", AtomXMLProvider.getBaseUri(initial, uriInfo)); } @Test public void testBaseUriNestedServiceDocumentTemplate() throws URISyntaxException { ResourceState initial = new ResourceState("ServiceDocument", "ServiceDocument", new ArrayList<Action>(), "/{companyid}"); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI("http://localhost:8080/responder/rest")); when(uriInfo.getPath()).thenReturn("/MockCompany001/test/blah"); assertEquals("http://localhost:8080/responder/rest/MockCompany001/", AtomXMLProvider.getBaseUri(initial, uriInfo)); } @Test public void testGetCurrentState() throws URISyntaxException, MethodNotAllowedException { // Create rsm ResourceStateMachine rsm = createCollectionToItemRSM(new EntityTransformer()); ResourceState serviceDocument = rsm.getResourceStateByName("ServiceDocument"); ResourceState flights = rsm.getResourceStateByName("Flights"); //Create provider AtomXMLProvider p = new AtomXMLProvider(createMockMetadataOData4j(mock(EdmDataServices.class)), mock(Metadata.class), rsm, mock(Transformer.class)); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getAbsolutePath()).thenReturn(new URI("www.treething.com/Flights")); when(uriInfo.getBaseUri()).thenReturn(new URI("www.treething.com/")); p.setUriInfo(uriInfo); Request request = mock(Request.class); when(request.getMethod()).thenReturn("GET"); p.setRequestContext(request); ResourceState result = p.getCurrentState(serviceDocument, "/Flights"); assertEquals(flights, result); } @Test public void testGetCurrentStateCompany() throws URISyntaxException, MethodNotAllowedException { // Create rsm (creates a service document with '/{companyid}) ResourceStateMachine rsm = createCompanyCollectionToItemRSM(new EntityTransformer()); ResourceState serviceDocument = rsm.getResourceStateByName("ServiceDocument"); ResourceState flights = rsm.getResourceStateByName("Flights"); //Create provider AtomXMLProvider p = new AtomXMLProvider(createMockMetadataOData4j(mock(EdmDataServices.class)), mock(Metadata.class), rsm, mock(Transformer.class)); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getAbsolutePath()).thenReturn(new URI("www.treething.com/123/Flights")); when(uriInfo.getBaseUri()).thenReturn(new URI("www.treething.com/")); p.setUriInfo(uriInfo); Request request = mock(Request.class); when(request.getMethod()).thenReturn("GET"); p.setRequestContext(request); ResourceState result = p.getCurrentState(serviceDocument, "/Flights"); assertEquals(flights, result); } @Test public void testGetCurrentStateCompanyNoPath() throws URISyntaxException, MethodNotAllowedException { // Create rsm (creates a service document with '/{companyid}) ResourceStateMachine rsm = createCompanyCollectionToItemRSM(new EntityTransformer()); ResourceState serviceDocument = rsm.getResourceStateByName("ServiceDocument"); ResourceState flights = rsm.getResourceStateByName("Flights"); //Create provider AtomXMLProvider p = new AtomXMLProvider(createMockMetadataOData4j(mock(EdmDataServices.class)), mock(Metadata.class), rsm, mock(Transformer.class)); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI("www.jedssheds.com")); when(uriInfo.getAbsolutePath()).thenReturn(new URI("www.jedssheds.com/123/Flights")); p.setUriInfo(uriInfo); Request request = mock(Request.class); when(request.getMethod()).thenReturn("GET"); p.setRequestContext(request); ResourceState result = p.getCurrentState(serviceDocument, "Flights"); assertEquals(flights, result); } @Test public void testGetCurrentStateCompanyWithPath() throws URISyntaxException, MethodNotAllowedException { // Create rsm (creates a service document with '/{companyid}/) List<Action> serviceDocActions = new ArrayList<Action>(); Action action = mock(Action.class); when(action.getMethod()).thenReturn("GET"); serviceDocActions.add(action); ResourceState serviceDocument = new ResourceState("ServiceDocument", "ServiceDocument", serviceDocActions, "/{companyid}/"); List<Action> flightsActions = new ArrayList<Action>(); flightsActions.add(action); ResourceState flights = new CollectionResourceState("Flight", "Flights", flightsActions, "/{companyid}/Flights"); serviceDocument.addTransition(new Transition.Builder().method(HttpMethod.GET) .target(flights) .build()); ResourceStateMachine rsm = new ResourceStateMachine(serviceDocument, mock(Transformer.class)); //Create provider AtomXMLProvider p = new AtomXMLProvider(createMockMetadataOData4j(mock(EdmDataServices.class)), mock(Metadata.class), rsm, mock(Transformer.class)); p.setUriInfo(mock(UriInfo.class)); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getBaseUri()).thenReturn(new URI("/myapp.svc")); when(uriInfo.getAbsolutePath()).thenReturn(new URI("/myapp.svc/123/Flights")); MultivaluedMap pathParams = mock(MultivaluedMap.class); List <String> pathValues = new ArrayList<String>(); pathValues.add("123"); when(pathParams.get(eq("companyid"))).thenReturn(pathValues); Set<String> pathKeys = new HashSet<String>(); pathKeys.add("companyid"); when(pathParams.keySet()).thenReturn(pathKeys); when(uriInfo.getPathParameters()).thenReturn(pathParams); p.setUriInfo(uriInfo); Request request = mock(Request.class); when(request.getMethod()).thenReturn("GET"); p.setRequestContext(request); ResourceState result = p.getCurrentState(serviceDocument, "Flights"); assertEquals(flights, result); } @Test public void testLinkId() { ResourceState account = new ResourceState("Account", "customerAccount", new ArrayList<Action>(), "/CustomerAccounts('{id}')"); ResourceState fundsTransfers = new CollectionResourceState("FundsTransfer", "FundsTransfers", new ArrayList<Action>(), "/FundsTransfers"); Map<String, String> uriLinkageMap = new HashMap<String, String>(); uriLinkageMap.put("DebitAcctNo", "{Acc}"); account.addTransition(new Transition.Builder() .method(HttpMethod.GET) .target(fundsTransfers) .uriParameters(uriLinkageMap) .label("Debit funds transfers") .linkId("123456") .build()); uriLinkageMap.clear(); uriLinkageMap.put("CreditAcctNo", "{Acc}"); account.addTransition(new Transition.Builder() .method(HttpMethod.GET) .target(fundsTransfers) .uriParameters(uriLinkageMap) .label("Credit funds transfers") .linkId("654321") .build()); AtomXMLProvider provider = new AtomXMLProvider(createMockMetadataOData4j(createMockEdmDataServices("FundsTransfers")), createMockMetadata("MyModel"), mockResourceStateMachine(), mock(Transformer.class)); List<Transition> transitions = account.getTransitions(fundsTransfers); assertEquals(2, transitions.size()); List<Link> links = new ArrayList<Link>(); links.add(new Link(transitions.get(0), transitions.get(0).getTarget().getRel(), transitions.get(0).getLabel().contains("Debit") ? "/FundsTransfers()?$filter=DebitAcctNo eq '123'" : "/FundsTransfers()?$filter=CreditAcctNo eq '123'", HttpMethod.GET)); links.add(new Link(transitions.get(1), transitions.get(1).getTarget().getRel(), transitions.get(1).getLabel().contains("Debit") ? "/FundsTransfers()?$filter=DebitAcctNo eq '123'" : "/FundsTransfers()?$filter=CreditAcctNo eq '123'", HttpMethod.GET)); EntityResource<OEntity> entityResource = new EntityResource<OEntity>(mock(OEntity.class)); entityResource.setLinks(links); provider.processLinks(entityResource); Collection<Link> processedLinks = entityResource.getLinks(); assertEquals(2, processedLinks.size()); Iterator<Link> iterator = processedLinks.iterator(); Link debitLink = iterator.next(); Link creditLink = iterator.next(); assertEquals("123456", debitLink.getLinkId()); assertEquals("654321", creditLink.getLinkId()); } @Test public void testGetAbsolutePath() throws URISyntaxException, UnsupportedEncodingException { String pathDecoded = "resourceTest('1234://ABC')"; String pathEncodedUTF8 = new String(pathDecoded.getBytes("UTF-8"), "UTF-8"); String pathEncodedWrong = new String(pathDecoded.getBytes("UTF-8"), "x-UTF-16LE-BOM"); String absPath = null; UriInfo uriInfo = mock(UriInfo.class); URI uri = new URI(""); when(uriInfo.getBaseUri()).thenReturn(uri); // Test encoded string utf8 when(uriInfo.getPath()).thenReturn(pathEncodedUTF8); absPath = AtomXMLProvider.getAbsolutePath(uriInfo); assertNotNull(absPath); assertEquals(pathDecoded, absPath); // Test encoded string utf16 when(uriInfo.getPath()).thenReturn(pathEncodedWrong); absPath = AtomXMLProvider.getAbsolutePath(uriInfo); assertNotNull(absPath); assertNotSame(pathDecoded, absPath); // Test encoded null string when(uriInfo.getPath()).thenReturn(null); absPath = AtomXMLProvider.getAbsolutePath(uriInfo); assertNotNull(absPath); assertEquals("null", absPath); } private Link createLink(ResourceStateMachine rsm, Transition transition, Object entity, MultivaluedMap<String, String> pathParameters, MultivaluedMap<String, String> queryParameters) { LinkGenerator linkGenerator = new LinkGeneratorImpl(rsm, transition, null); Collection<Link> links = linkGenerator.createLink(pathParameters, queryParameters, entity); return (!links.isEmpty()) ? links.iterator().next() : null; } }