This is an automated email from the ASF dual-hosted git repository. jgallimore pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tomee.git
The following commit(s) were added to refs/heads/master by this push: new cdbf507 Add README.adoc to applicationcomposer-jaxws-cdi/ - TOMEE-2370 new 138993f Merge pull request #379 from BogdanStirbat/TOMEE-2370 cdbf507 is described below commit cdbf507b26a0f13d45e0aa58f75b36cd2d9c0cc2 Author: Bogdan Stirbat <bogdan.stir...@gmail.com> AuthorDate: Sat Jan 19 18:48:23 2019 +0200 Add README.adoc to applicationcomposer-jaxws-cdi/ - TOMEE-2370 --- examples/applicationcomposer-jaxws-cdi/README.adoc | 232 +++++++++++++++++++++ .../superbiz/example/jaxws/MeetingPlannerTest.java | 46 +++- 2 files changed, 271 insertions(+), 7 deletions(-) diff --git a/examples/applicationcomposer-jaxws-cdi/README.adoc b/examples/applicationcomposer-jaxws-cdi/README.adoc new file mode 100644 index 0000000..07421ff --- /dev/null +++ b/examples/applicationcomposer-jaxws-cdi/README.adoc @@ -0,0 +1,232 @@ += Application Composer with JAX-WS and CDI +:index-group: Testing Techniques +:jbake-type: page +:jbake-status: published + +This example shows the use of `@ApplicationComposer` annotation, in the context of a JAX-WS application. + +Application Composer is an API for creating an EE application programmatically. It is very useful in a text context, so it's no wonder that it originated from here. +For more information about Application Composer, please refer to http://tomee.apache.org/tomee-8.0/docs/application-composer/index.html[Application Composer section in the documentation]. +In this example, we will use `@ApplicationComposer` in the context of a JAX-WS application. + +== Example + +This example is a meeting planner application. It is a JAX-WS application, and it accepts incoming booking meeting requests. The application first checks if the request can be booked, books it if possible, +and returns to the caller if the request was booked (a boolean value). This is a simple, demo-purpose application, so it is greatly simplified. A book request is represented only by the meeting start date (a `java.util.Date` value). +A book request is bookable if it starts after current date. + +The business logic is implemented using a `MeetingPlannerImpl` class (implementing `MeetingPlanner`). This class is a JAX-WS service, exposing the following method: `boolean book(final Date date)`. +The client will send a request, containing a date; the service will return if the request can be booked, true or false. The exposed JAX-WS service uses in addition a different feature, CDI, injecting a +business logic service class checking if the request is bookable. So, when the time will come to test the `@ApplicationComposer` annotation, we will both check that CDI worked in our programmatically +started application and that the JAX-WS service is up and running. + +The business logic that checks if a request is bookable is defined by the following interface: + +.... +import java.util.Date; + +public interface Agenda { + boolean isBookable(Date d); +} +.... + +The implementation is a simple one, without distracting details: + +.... +import java.util.Date; + +public class LazyAgenda implements Agenda { + @Override + public boolean isBookable(final Date d) { + return d.after(new Date()); + } +} +.... + +The JAX-WS service is defined by the following interface: + +.... +import javax.jws.WebMethod; +import javax.jws.WebService; +import java.util.Date; + +@WebService +public interface MeetingPlanner { + + @WebMethod(operationName = "book", exclude = false) + boolean book(final Date date); +} +.... + +The class implementing this interface is: + +.... +import javax.inject.Inject; +import javax.jws.WebService; +import java.util.Date; + +@WebService +public class MeetingPlannerImpl implements MeetingPlanner { + @Inject + private Agenda agenda; + + @Override + public boolean book(final Date date) { + return agenda.isBookable(date); + } +} +.... + +== Using Application Composer + +Now, that the application is completed, it's time to test it. For this, we will add a unit test that will use Application Composer to start and deploy our application in a full JEE environment. +The full test: + +.... +import org.apache.openejb.jee.WebApp; +import org.apache.openejb.junit.ApplicationComposer; +import org.apache.openejb.testing.Classes; +import org.apache.openejb.testing.Configuration; +import org.apache.openejb.testing.EnableServices; +import org.apache.openejb.testing.Module; +import org.apache.openejb.testng.PropertiesBuilder; +import org.apache.openejb.util.NetworkUtil; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.xml.bind.JAXBContext; +import javax.xml.namespace.QName; +import javax.xml.ws.Dispatch; +import javax.xml.ws.Service; +import java.net.URL; +import java.util.Date; +import java.util.Properties; + +import static org.junit.Assert.assertTrue; + +@EnableServices("jax-ws") +@RunWith(ApplicationComposer.class) +public class MeetingPlannerTest { + private static final int JAX_WS_PORT = NetworkUtil.getNextAvailablePort(); + + @Configuration + public Properties configuration() { + return new PropertiesBuilder().p("httpejbd.port", Integer.toString(JAX_WS_PORT)).build(); + } + + @Module + @Classes(cdi = true, value = {MeetingPlannerImpl.class, LazyAgenda.class}) + public WebApp war() { + return new WebApp() + .contextRoot("/demo") + .addServlet("jaxws", MeetingPlannerImpl.class.getName(), "/meeting-planner"); + } + + @Test + public void bookPort() throws Exception { + final Service service = Service.create( + new URL("http://127.0.0.1:" + JAX_WS_PORT + "/demo/meeting-planner?wsdl"), + new QName("http://jaxws.example.superbiz.org/", "MeetingPlannerImplService")); + final MeetingPlanner planner = service.getPort(MeetingPlanner.class); + assertTrue(planner.book(new Date(System.currentTimeMillis() + 1000000))); + } +} +.... + +First thing to see, we use Application Composer as a JUnit runner. So, our test integrates with current tools just like any other JUnit test. The test's configuration is defined in the method annotated with `@Configuration`. + +The application is started in the method having the `@Module` annotation. In this example, we specify the classes we want to scan, and the fact that we want to use CDI. + +Our test makes a booking request, sending a date in the future, then it verifies that booking is done. + +== Running the test + +Running the test we can see that the application was successfully started, that the JAX-WS service is running and that it fulfills incoming requests correctly. + +.... +------------------------------------------------------- + T E S T S +------------------------------------------------------- +Running org.superbiz.example.jaxws.MeetingPlannerTest +INFO - Created new singletonService org.apache.openejb.cdi.ThreadSingletonServiceImpl@49993335 +INFO - Succeeded in installing singleton service +INFO - Cannot find the configuration file [conf/openejb.xml]. Will attempt to create one for the beans deployed. +INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service) +INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager) +INFO - Creating TransactionManager(id=Default Transaction Manager) +INFO - Creating SecurityService(id=Default Security Service) +INFO - Initializing network services +INFO - Creating ServerService(id=cxf) +INFO - Creating ServerService(id=httpejbd) +INFO - Created ServicePool 'httpejbd' with (10) core threads, limited to (200) threads with a queue of (9) +INFO - Initializing network services +INFO - ** Bound Services ** +INFO - NAME IP PORT +INFO - httpejbd 127.0.0.1 39649 +INFO - ------- +INFO - Ready! +INFO - Configuring enterprise application: /home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest +INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container) +INFO - Auto-creating a container for bean org.superbiz.example.jaxws.MeetingPlannerTest: Container(type=MANAGED, id=Default Managed Container) +INFO - Creating Container(id=Default Managed Container) +INFO - Using directory /tmp for stateful session passivation +INFO - Enterprise application "/home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest" loaded. +INFO - Creating dedicated application classloader for MeetingPlannerTest +INFO - Assembling app: /home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest +INFO - Existing thread singleton service in SystemInstance(): org.apache.openejb.cdi.ThreadSingletonServiceImpl@49993335 +INFO - Some Principal APIs could not be loaded: org.eclipse.microprofile.jwt.JsonWebToken out of org.eclipse.microprofile.jwt.JsonWebToken not found +INFO - OpenWebBeans Container is starting... +INFO - Adding OpenWebBeansPlugin : [CdiPlugin] +INFO - All injection points were validated successfully. +INFO - OpenWebBeans Container has started, it took 406 ms. +INFO - Webservice(wsdl=http://127.0.0.1:39649/demo/meeting-planner, qname={http://jaxws.example.superbiz.org/}MeetingPlannerImplService) --> Pojo(id=null./demo.jaxws) +INFO - Deployed Application(path=/home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest) +INFO - Creating Service {http://jaxws.example.superbiz.org/}MeetingPlannerImplService from WSDL: http://127.0.0.1:39649/demo/meeting-planner?wsdl +INFO - Creating Service {http://jaxws.example.superbiz.org/}MeetingPlannerImplService from WSDL: http://127.0.0.1:39649/demo/meeting-planner?wsdl +INFO - Undeploying app: /home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest +INFO - Stopping network services +INFO - Stopping server services +INFO - Created new singletonService org.apache.openejb.cdi.ThreadSingletonServiceImpl@49993335 +INFO - Succeeded in installing singleton service +INFO - Cannot find the configuration file [conf/openejb.xml]. Will attempt to create one for the beans deployed. +INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service) +INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager) +INFO - Creating TransactionManager(id=Default Transaction Manager) +INFO - Creating SecurityService(id=Default Security Service) +INFO - Initializing network services +INFO - Creating ServerService(id=cxf) +INFO - Creating ServerService(id=httpejbd) +INFO - Created ServicePool 'httpejbd' with (10) core threads, limited to (200) threads with a queue of (9) +INFO - Initializing network services +INFO - ** Bound Services ** +INFO - NAME IP PORT +INFO - httpejbd 127.0.0.1 39649 +INFO - ------- +INFO - Ready! +INFO - Configuring enterprise application: /home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest +INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container) +INFO - Auto-creating a container for bean org.superbiz.example.jaxws.MeetingPlannerTest: Container(type=MANAGED, id=Default Managed Container) +INFO - Creating Container(id=Default Managed Container) +INFO - Using directory /tmp for stateful session passivation +INFO - Enterprise application "/home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest" loaded. +INFO - Creating dedicated application classloader for MeetingPlannerTest +INFO - Assembling app: /home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest +INFO - Existing thread singleton service in SystemInstance(): org.apache.openejb.cdi.ThreadSingletonServiceImpl@49993335 +INFO - Some Principal APIs could not be loaded: org.eclipse.microprofile.jwt.JsonWebToken out of org.eclipse.microprofile.jwt.JsonWebToken not found +INFO - OpenWebBeans Container is starting... +INFO - Adding OpenWebBeansPlugin : [CdiPlugin] +INFO - All injection points were validated successfully. +INFO - OpenWebBeans Container has started, it took 52 ms. +INFO - Webservice(wsdl=http://127.0.0.1:39649/demo/meeting-planner, qname={http://jaxws.example.superbiz.org/}MeetingPlannerImplService) --> Pojo(id=null./demo.jaxws) +INFO - Deployed Application(path=/home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest) +INFO - Undeploying app: /home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest +INFO - Stopping network services +INFO - Stopping server services +Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.076 sec + +Results : + +Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 +.... + +Full example can be found https://github.com/apache/tomee/tree/master/examples/applicationcomposer-jaxws-cdi[here]. \ No newline at end of file diff --git a/examples/applicationcomposer-jaxws-cdi/src/test/java/org/superbiz/example/jaxws/MeetingPlannerTest.java b/examples/applicationcomposer-jaxws-cdi/src/test/java/org/superbiz/example/jaxws/MeetingPlannerTest.java index 8664015..6bbfa45 100644 --- a/examples/applicationcomposer-jaxws-cdi/src/test/java/org/superbiz/example/jaxws/MeetingPlannerTest.java +++ b/examples/applicationcomposer-jaxws-cdi/src/test/java/org/superbiz/example/jaxws/MeetingPlannerTest.java @@ -24,19 +24,26 @@ import org.apache.openejb.testing.EnableServices; import org.apache.openejb.testing.Module; import org.apache.openejb.testng.PropertiesBuilder; import org.apache.openejb.util.NetworkUtil; -import org.codehaus.stax2.io.Stax2StringSource; import org.junit.Test; import org.junit.runner.RunWith; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.util.JAXBSource; import javax.xml.namespace.QName; +import javax.xml.transform.OutputKeys; import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import javax.xml.ws.Dispatch; import javax.xml.ws.Service; -import java.net.MalformedURLException; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.io.StringReader; import java.net.URL; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.Properties; @@ -74,9 +81,34 @@ public class MeetingPlannerTest { final Service service = Service.create( new URL("http://127.0.0.1:" + JAX_WS_PORT + "/demo/meeting-planner?wsdl"), new QName("http://jaxws.example.superbiz.org/", "MeetingPlannerImplService")); - final JAXBContext jc = JAXBContext.newInstance(MeetingPlannerImpl.class); - final Dispatch<Object> dispatch = service.createDispatch(new QName("http://jaxws.example.superbiz.org/", "MeetingPlannerImplPort"), jc, Service.Mode.PAYLOAD); + final Dispatch<Source> dispatch = service.createDispatch(new QName("http://jaxws.example.superbiz.org/", "MeetingPlannerImplPort"), Source.class, Service.Mode.PAYLOAD); - //TODO - Complete + Date currentDate = new Date(); + LocalDateTime nowPlusTwoDays = LocalDateTime.from(currentDate.toInstant().atZone(ZoneId.systemDefault())).plusDays(2); + String dateArgument = nowPlusTwoDays.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + + String request = "<ns1:book xmlns:ns1=\"http://jaxws.example.superbiz.org/\"><arg0>"+ dateArgument +"</arg0></ns1:book>"; + Source invoke = dispatch.invoke(new StreamSource(new StringReader(request))); + String result = sourceToXMLString(invoke); + + assertTrue(result.contains("<return>true</return>")); + } + + private String sourceToXMLString(Source result) { + String xmlResult = null; + try { + TransformerFactory factory = TransformerFactory.newInstance(); + Transformer transformer = factory.newTransformer(); + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); + OutputStream out = new ByteArrayOutputStream(); + StreamResult streamResult = new StreamResult(); + streamResult.setOutputStream(out); + transformer.transform(result, streamResult); + xmlResult = streamResult.getOutputStream().toString(); + } catch (TransformerException e) { + e.printStackTrace(); + } + return xmlResult; } }