/**
* Copyright (C) 2008 - 2014 52°North Initiative for Geospatial Open Source
* Software GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* If the program is linked with libraries which are licensed under one of
* the following licenses, the combination of the program with the linked
* library is not considered a "derivative work" of the program:
*
* - Apache License, version 2.0
* - Apache Software License, version 1.0
* - GNU Lesser General Public License, version 3
* - Mozilla Public License, versions 1.0, 1.1 and 2.0
* - Common Development and Distribution License (CDDL), version 1.0
*
* Therefore the distribution of the program linked with libraries licensed
* under the aforementioned licenses, is permitted by the copyright holders
* if the distribution is compliant with both the GNU General Public
* icense version 2 and the aforementioned licenses.
*
* 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.
*/
package org.n52.ses.common.integration.test.concurrency;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.n52.oxf.OXFException;
import org.n52.oxf.adapter.OperationResult;
import org.n52.oxf.adapter.ParameterContainer;
import org.n52.oxf.ows.ExceptionReport;
import org.n52.oxf.ows.capabilities.Operation;
import org.n52.oxf.ses.adapter.ISESRequestBuilder;
import org.n52.oxf.ses.adapter.SESAdapter;
import org.n52.oxf.ses.adapter.SESRequestBuilderFactory;
import org.n52.oxf.ses.adapter.SESRequestBuilder_00;
import org.n52.oxf.ses.adapter.client.Subscription;
import org.n52.ses.common.integration.test.IntegrationTestConfig;
import org.n52.ses.common.integration.test.ServiceInstance;
import org.n52.ses.common.test.TestWSNEndpoint;
import org.n52.ses.util.common.ConfigurationRegistry;
import org.oasisOpen.docs.wsn.b2.UnsubscribeResponseDocument.UnsubscribeResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3.x2003.x05.soapEnvelope.EnvelopeDocument;
public class ConcurrentSubscriptionsIT {
private static final Logger logger = LoggerFactory.getLogger(ConcurrentSubscriptionsIT.class);
private TestWSNEndpoint endpoint;
private String subscribeBConsumer;
private String subscribeAConsumer;
private Subscription subscriptionB;
private Subscription subscriptionA;
private ConcurrentNotificationReceiver notificationReceiver;
@Before
public void
ensureConcurrentMessageHandling() throws IOException {
try {
Assume.assumeTrue(Boolean.parseBoolean(IntegrationTestConfig.getInstance().getConfigPropertyOfDeployedService(
ConfigurationRegistry.USE_CONCURRENT_ORDERED_HANDLING)));
} catch (Exception e) {
logger.warn("Skipping test due to exception: "+ e.getMessage());
Assume.assumeNoException(e);
}
}
@Test
public void
testConcurrentSubscriptionWorkflow()
throws IOException, InterruptedException, OXFException, ExceptionReport, XmlException {
initializeConsumer();
ServiceInstance.getInstance().waitUntilAvailable();
subscribeA();
subscribeB();
notifications();
waitForNotificationArrival();
String error = evaluate();
Assert.assertNull(error, error);
unsubscribe();
}
private void unsubscribe() throws OXFException, ExceptionReport, XmlException, IOException {
unsubscribeById(subscriptionA.getResourceID(), subscriptionA.getManager().getHost());
unsubscribeById(subscriptionB.getResourceID(), subscriptionB.getManager().getHost());
}
private void unsubscribeById(String resourceID, URL host) throws OXFException, ExceptionReport, XmlException, IOException {
SESAdapter adapter = new SESAdapter("0.0.0");
Operation op = new Operation(SESAdapter.UNSUBSCRIBE, null, host.toExternalForm());
ParameterContainer parameter = new ParameterContainer();
parameter.addParameterShell(ISESRequestBuilder.UNSUBSCRIBE_SES_URL, host.toExternalForm());
parameter.addParameterShell(SESRequestBuilder_00.UNSUBSCRIBE_REFERENCE, resourceID);
OperationResult opResult = adapter.doOperation(op, parameter);
EnvelopeDocument env = EnvelopeDocument.Factory.parse(opResult.getIncomingResultAsStream());
XmlCursor cur = env.getEnvelope().getBody().newCursor();
cur.toFirstChild();
if (!(cur.getObject() instanceof UnsubscribeResponse)) {
Assert.fail("Unsubscribe failed! Received an unexpected respone: "+ cur.getObject().xmlText(new XmlOptions().setSaveOuter()));
}
}
private String evaluate() {
Map<String, List<String>> received = notificationReceiver.getUriToNotifications();
if (!received.containsKey(subscribeAConsumer))
return "Did not receive anything for Subscription A";
if (!received.containsKey(subscribeBConsumer))
return "Did not receive anything for Subscription B";
List<String> subANotifies = received.get(subscribeAConsumer);
List<String> subBNotifies = received.get(subscribeBConsumer);
if (subANotifies.size() != 3)
return "Expected count for Subscription A was 3. Instead received "+subANotifies.size();
if (subBNotifies.size() != 3)
return "Expected count for Subscription B was 3. Instead received "+subBNotifies.size();
return checkContents(subANotifies, subBNotifies);
}
private String checkContents(List<String> subANotifies,
List<String> subBNotifies) {
if (!subANotifies.get(0).contains("4.476")) {
return "Wrong contents for first Notification of Subscribption A";
}
if (!subANotifies.get(1).contains("4.176")) {
return "Wrong contents for second Notification of Subscribption A";
}
if (!subANotifies.get(2).contains("4.476")) {
return "Wrong contents for first Notification of Subscribption A";
}
if (!subBNotifies.get(0).contains("4.476")) {
return "Wrong contents for first Notification of Subscribption B";
}
if (!subBNotifies.get(1).contains("4.176")) {
return "Wrong contents for second Notification of Subscribption B";
}
if (!subBNotifies.get(2).contains("4.476")) {
return "Wrong contents for first Notification of Subscribption B";
}
return null;
}
private void waitForNotificationArrival() throws InterruptedException {
long start = System.currentTimeMillis();
while (!allArrived() && System.currentTimeMillis() - start < IntegrationTestConfig.getInstance().getNotificationTimeout()) {
logger.info("waiting for all notifications to arrive...");
Thread.sleep(1000);
}
}
private boolean allArrived() {
Map<String, List<String>> received = notificationReceiver.getUriToNotifications();
if (!received.containsKey(subscribeAConsumer) || !received.containsKey(subscribeBConsumer))
return false;
return received.get(subscribeAConsumer).size() + received.get(subscribeBConsumer).size() >= 6;
}
private void notifications() throws XmlException, IOException, OXFException, ExceptionReport {
List<String> notificiations = readNotifications();
for (int i = 0; i < 2; i++) {
for (String n : notificiations) {
sendNotify(n);
}
}
}
private void sendNotify(String n) throws OXFException, ExceptionReport {
SESAdapter adapter = new SESAdapter("0.0.0");
Operation op = new Operation(SESAdapter.NOTIFY, null, ServiceInstance.getInstance().getHost().toExternalForm());
ParameterContainer parameter = new ParameterContainer();
parameter.addParameterShell(ISESRequestBuilder.NOTIFY_SES_URL, ServiceInstance.getInstance().getHost().toExternalForm());
parameter.addParameterShell(ISESRequestBuilder.NOTIFY_XML_MESSAGE, n);
OperationResult opResult = adapter.doOperation(op, parameter);
if (opResult != null) {
Assert.fail("Could not sent notification: "+new String(opResult.getIncomingResult()));
}
}
private List<String> readNotifications() throws XmlException, IOException {
List<String> result = new ArrayList<String>();
result.add(readXmlContent("Notification1.xml"));
result.add(readXmlContent("Notification2.xml"));
return result;
}
private void subscribeA() throws OXFException, ExceptionReport, XmlException, IOException {
this.subscribeAConsumer = "/A";
this.subscriptionA = subscribe(endpoint.getPublicURL()+this.subscribeAConsumer);
checkForException(this.subscriptionA);
}
private void checkForException(Subscription sub) {
if (sub.isFailed()) {
Assert.fail("Subscription failed: "+ sub.getExceptionText());
}
}
private void subscribeB() throws OXFException, ExceptionReport, XmlException, IOException {
this.subscribeBConsumer = "/B";
this.subscriptionB = subscribe(endpoint.getPublicURL()+this.subscribeBConsumer);
checkForException(this.subscriptionB);
}
private Subscription subscribe(String consumer) throws OXFException, ExceptionReport, XmlException, IOException {
SESAdapter adapter = new SESAdapter("0.0.0");
Operation op = new Operation(SESAdapter.SUBSCRIBE, null, ServiceInstance.getInstance().getHost().toExternalForm());
ParameterContainer parameter = new ParameterContainer();
parameter.addParameterShell(ISESRequestBuilder.SUBSCRIBE_SES_URL, ServiceInstance.getInstance().getHost().toExternalForm());
parameter.addParameterShell(ISESRequestBuilder.SUBSCRIBE_CONSUMER_REFERENCE_ADDRESS,
consumer);
parameter.addParameterShell(ISESRequestBuilder.SUBSCRIBE_FILTER_MESSAGE_CONTENT_DIALECT,
"http://www.opengis.net/ses/filter/level3");
parameter.addParameterShell(ISESRequestBuilder.SUBSCRIBE_FILTER_MESSAGE_CONTENT, readSubscription());
logger.info(SESRequestBuilderFactory.generateRequestBuilder("0.0.0").buildSubscribeRequest(parameter));
OperationResult opResult = adapter.doOperation(op, parameter);
XmlObject xo = XmlObject.Factory.parse(opResult.getIncomingResultAsStream());
logger.info(xo.xmlText());
Subscription sub = new Subscription(null);
sub.parseResponse(xo);
return sub;
}
private void initializeConsumer() throws IOException, InterruptedException {
endpoint = TestWSNEndpoint.getInstance(IntegrationTestConfig.getInstance().getConsumerPort());
notificationReceiver = new ConcurrentNotificationReceiver();
endpoint.addListener(notificationReceiver);
}
private String readSubscription() throws XmlException, IOException {
return readXmlContent("Subscription.xml");
}
private String readXmlContent(String string) throws XmlException, IOException {
XmlObject xo = XmlObject.Factory.parse(getClass().getResourceAsStream(string));
return xo.xmlText(new XmlOptions().setSavePrettyPrint());
}
}