/** * Copyright (C) 2010 Talend Inc. - www.talend.com */ package client; import java.awt.Image; import java.io.InputStream; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Properties; import javax.activation.DataHandler; import javax.imageio.ImageIO; import javax.mail.util.ByteArrayDataSource; import common.attachment.Book; import common.attachment.MultipartsService; import common.attachment.XopAttachmentService; import common.attachment.XopBean; import org.apache.cxf.helpers.IOUtils; import org.apache.cxf.jaxrs.client.JAXRSClientFactory; import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean; import org.apache.cxf.jaxrs.client.WebClient; import org.apache.cxf.jaxrs.ext.multipart.Attachment; import org.apache.cxf.jaxrs.ext.multipart.MultipartBody; import org.apache.cxf.jaxrs.provider.json.JSONProvider; /** * Example showing the interaction between HTTP-centric and proxy based RESTful clients and JAX-RS server * providing multiple services (PersonService and SearchService) */ public final class RESTClient { private static final String PORT_PROPERTY = "http.port"; private static final int DEFAULT_PORT_VALUE = 8080; private static final String HTTP_PORT; static { Properties props = new Properties(); try { props.load(RESTClient.class.getResourceAsStream("/client.properties")); } catch (Exception ex) { throw new RuntimeException("client.properties resource is not available"); } HTTP_PORT = props.getProperty(PORT_PROPERTY); } int port; public RESTClient() { this(getPort()); } public RESTClient(int port) { this.port = port; } /** * Writes and reads the XOP attachment using a CXF JAX-RS WebClient. * Note that WebClient is created with the help of JAXRSClientFactoryBean. * JAXRSClientFactoryBean can be used when neither of the WebClient factory * methods is appropriate. For example, in this case, an "mtom-enabled" * property is set on the factory bean first. * * * @throws Exception */ public void useXopAttachmentServiceWithWebClient() throws Exception { final String serviceURI = "http://localhost:" + port + "/services/attachments/xop"; JAXRSClientFactoryBean factoryBean = new JAXRSClientFactoryBean(); factoryBean.setAddress(serviceURI); factoryBean.setProperties(Collections.singletonMap(org.apache.cxf.message.Message.MTOM_ENABLED, (Object)"true")); WebClient client = factoryBean.createWebClient(); WebClient.getConfig(client).getRequestContext().put("support.type.as.multipart", "true"); client.type("multipart/related").accept("multipart/related"); XopBean xop = createXopBean(); System.out.println(); System.out.println("Posting a XOP attachment with a WebClient"); XopBean xopResponse = client.post(xop, XopBean.class); verifyXopResponse(xop, xopResponse); } /** * Writes and reads the XOP attachment using a CXF JAX-RS Proxy * The proxy automatically sets the "mtom-enabled" property by checking * the CXF EndpointProperty set on the XopAttachment interface. * * @throws Exception */ public void useXopAttachmentServiceWithProxy() throws Exception { final String serviceURI = "http://localhost:" + port + "/services/attachments"; XopAttachmentService proxy = JAXRSClientFactory.create(serviceURI, XopAttachmentService.class); XopBean xop = createXopBean(); System.out.println(); System.out.println("Posting a XOP attachment with a proxy"); XopBean xopResponse = proxy.echoXopAttachment(xop); verifyXopResponse(xop, xopResponse); } /** * Writes and reads the multipart/mixed attachments using a CXF JAX-RS WebClient * Note that a custom JAXB-driven JSONProvider is registered to simpify dealing * with one of the parts in the JSON format: it is configured to drop namespace * prefixes on the write and add a namespace to the incoming payload so that it * can be read into the namespace-qualified JAXB Book bean. * * @throws Exception */ public void useAttachmentServiceWithWebClient() throws Exception { final String serviceURI = "http://localhost:" + port + "/services/attachments/multipart"; JSONProvider provider = new JSONProvider(); provider.setIgnoreNamespaces(true); provider.setInTransformElements( Collections.singletonMap("Book", "{http://books}Book")); WebClient client = WebClient.create(serviceURI, Collections.singletonList(provider)); client.type("multipart/mixed").accept("multipart/mixed"); MultipartBody body = createMultipartBody(); System.out.println(); System.out.println("Posting Book attachments with a WebClient"); MultipartBody bodyResponse = client.post(body, MultipartBody.class); verifyMultipartResponse(bodyResponse); } /** * Writes and reads the multipart/mixed attachments using a CXF JAX-RS Proxy * Note that a custom JAXB-driven JSONProvider is registered to simpify dealing * with one of the parts in the JSON format: it is configured to drop namespace * prefixes on the write and add a namespace to the incoming payload so that it * can be read into the namespace-qualified JAXB Book bean. * * @throws Exception */ public void useAttachmentServiceWithProxy() throws Exception { final String serviceURI = "http://localhost:" + port + "/services/attachments"; JSONProvider provider = new JSONProvider(); provider.setIgnoreNamespaces(true); provider.setInTransformElements( Collections.singletonMap("Book", "{http://books}Book")); MultipartsService client = JAXRSClientFactory.create(serviceURI, MultipartsService.class, Collections.singletonList(provider)); MultipartBody body = createMultipartBody(); System.out.println(); System.out.println("Posting Book attachments with a proxy"); MultipartBody bodyResponse = client.echoAttachment(body); verifyMultipartResponse(bodyResponse); } /** * Creates a XopBean. The image on the disk is included as a byte array, * a DataHandler and java.awt.Image * @return the bean * @throws Exception */ private XopBean createXopBean() throws Exception { XopBean xop = new XopBean(); xop.setName("xopName"); InputStream is = getClass().getResourceAsStream("/java.jpg"); byte[] data = IOUtils.readBytesFromStream(is); // Pass java.jpg as an array of bytes xop.setBytes(data); // Wrap java.jpg as a DataHandler xop.setDatahandler(new DataHandler( new ByteArrayDataSource(data, "application/octet-stream"))); if (Boolean.getBoolean("java.awt.headless")) { System.out.println("Running headless. Ignoring an Image property."); } else { xop.setImage(getImage("/java.jpg")); } return xop; } /** * Verifies that the received image is identical to the original one. * @param xopOriginal * @param xopResponse */ private void verifyXopResponse(XopBean xopOriginal, XopBean xopResponse) { if (!Arrays.equals(xopResponse.getBytes(), xopOriginal.getBytes())) { throw new RuntimeException("Received XOP attachment is corrupted"); } System.out.println(); System.out.println("XOP attachment has been successfully received"); } private Image getImage(String name) throws Exception { return ImageIO.read(getClass().getResource(name)); } /** * Creates MultipartBody. It contains 3 parts, "book1", "book2" and "image". * These individual parts have their Content-Type set to application/xml, * application/json and application/octet-stream * * MultipartBody will use the Content-Type value of the individual * part to write its data by delegating to a matching JAX-RS MessageBodyWriter * provider * * @return * @throws Exception */ private MultipartBody createMultipartBody() throws Exception { List<Attachment> atts = new LinkedList<Attachment>(); atts.add(new Attachment("book1", "application/xml", new Book("JAXB", 1L))); atts.add(new Attachment("book2", "application/json", new Book("JSON", 2L))); atts.add(new Attachment("image", "application/octet-stream", getClass().getResourceAsStream("/java.jpg"))); return new MultipartBody(atts, true); } private void verifyMultipartResponse(MultipartBody bodyResponse) throws Exception { Book jaxbBook = bodyResponse.getAttachmentObject("book1", Book.class); Book jsonBook = bodyResponse.getAttachmentObject("book2", Book.class); byte[] receivedImageBytes = bodyResponse.getAttachmentObject("image", byte[].class); InputStream is = getClass().getResourceAsStream("/java.jpg"); byte[] imageBytes = IOUtils.readBytesFromStream(is); if ("JAXB".equals(jaxbBook.getName()) && 1L == jaxbBook.getId() && "JSON".equals(jsonBook.getName()) && 2L == jsonBook.getId() && Arrays.equals(imageBytes, receivedImageBytes)) { System.out.println(); System.out.println("Book attachments have been successfully received"); } else { throw new RuntimeException("Received Book attachment is corrupted"); } } public static void main(String[] args) throws Exception { RESTClient client = new RESTClient(); // Post XOP with CXF JAX-RS WebClient client.useXopAttachmentServiceWithWebClient(); // Post XOP with CXF JAX-RS Proxy client.useXopAttachmentServiceWithProxy(); // Post Book attachments in XML and JSON formats with CXF JAX-RS WebClient client.useAttachmentServiceWithWebClient(); // Post Book attachments in XML and JSON formats with CXF JAX-RS Proxy client.useAttachmentServiceWithProxy(); } private static int getPort() { try { return Integer.valueOf(HTTP_PORT); } catch (NumberFormatException ex) { // ignore } return DEFAULT_PORT_VALUE; } }