1 package com.trendmicro.grid.acl.ds.msmq;
2
3 import net.sf.tinyjee.streams.ByteBufferOutputStream;
4 import net.sf.tinyjee.util.FileUtils;
5 import org.w3c.dom.*;
6
7 import javax.xml.parsers.DocumentBuilder;
8 import javax.xml.parsers.DocumentBuilderFactory;
9 import javax.xml.transform.Transformer;
10 import javax.xml.transform.TransformerException;
11 import javax.xml.transform.TransformerFactory;
12 import javax.xml.transform.dom.DOMSource;
13 import javax.xml.transform.stream.StreamResult;
14 import java.io.IOException;
15 import java.io.OutputStream;
16 import java.net.HttpURLConnection;
17 import java.net.URI;
18 import java.net.URL;
19 import java.text.DateFormat;
20 import java.text.SimpleDateFormat;
21 import java.util.Arrays;
22 import java.util.Date;
23 import java.util.List;
24 import java.util.UUID;
25
26
27
28
29
30
31
32 public class MSMQSender implements Sender {
33
34 static final long MS_PER_MONTH = 30 * 24 * 60 * 60 * 1000L;
35
36 static final UUID sourceQMGuid = UUID.randomUUID();
37 static final Document template;
38 static final DateFormat dateFormatTemplate = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
39
40 static {
41 try {
42 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
43 factory.setNamespaceAware(true);
44 DocumentBuilder builder = factory.newDocumentBuilder();
45 template = builder.parse(MSMQSender.class.getResourceAsStream("/msmq-soap-send-template.xml"));
46
47
48 findFirstElement(template.getDocumentElement(), "Header", "Msmq", "SourceQmGuid").setTextContent(sourceQMGuid.toString());
49 } catch (Exception e) {
50 throw new RuntimeException(e);
51 }
52 }
53
54 static Element findFirstElement(Node startNode, String... path) {
55 NodeList nl = startNode.getChildNodes();
56
57 final int length = nl.getLength();
58 for (int i = 0; i < length; i++) {
59 final Node node = nl.item(i);
60
61 if (!(node instanceof Element))
62 continue;
63
64 final Element el = (Element) node;
65 if (path.length > 0 && !path[0].equals(el.getLocalName()))
66 continue;
67
68 if (path.length > 1) {
69 String[] reducedPath = new String[path.length - 1];
70 System.arraycopy(path, 1, reducedPath, 0, reducedPath.length);
71 return findFirstElement(el, reducedPath);
72 }
73
74 return el;
75 }
76
77
78 throw new IllegalArgumentException("Didn't find the requested element " + Arrays.toString(path) + " inside " + startNode);
79 }
80
81 static String toMSMQPriority(int priority) {
82
83
84 return String.valueOf(priority);
85 }
86
87 URI endpoint;
88 String queueName;
89 DateFormat dateFormat = (DateFormat) dateFormatTemplate.clone();
90
91
92 Document message;
93 Element headerElement, pathElement, propertiesElement, msmqElement;
94
95 @Override
96 public void reset(List<URI> endpoints, String queueName) {
97 endpoint = endpoints.get(0);
98 this.queueName = queueName;
99 message = (Document) template.cloneNode(true);
100
101 final Element rootElement = message.getDocumentElement();
102 headerElement = findFirstElement(rootElement, "Header");
103 pathElement = findFirstElement(headerElement, "path");
104 propertiesElement = findFirstElement(headerElement, "properties");
105 msmqElement = findFirstElement(headerElement, "Msmq");
106 }
107
108 @Override
109 public void send(int priority, String messageBody) throws IOException {
110
111
112
113 URL url = new URL(endpoint.toURL(), queueName);
114 HttpURLConnection huc = (HttpURLConnection) url.openConnection();
115 huc.setRequestMethod("POST");
116 huc.setDoOutput(true);
117
118 send(priority, messageBody, huc.getOutputStream());
119
120 if (huc.getResponseCode() != HttpURLConnection.HTTP_OK) {
121 ByteBufferOutputStream bOut = new ByteBufferOutputStream();
122 FileUtils.copy(huc.getErrorStream(), bOut);
123
124 throw new IOException("Failed sending message to " + queueName +
125 ", caused by; HTTP-Response: " + huc.getResponseCode() + " " + huc.getResponseMessage() +
126 "\nDetails:\n" + bOut.toString());
127 }
128 }
129
130 void send(int priority, String messageBody, OutputStream out) throws IOException {
131
132
133
134
135 findFirstElement(pathElement, "to").setTextContent("MSMQ:DIRECT=OS:..???../" + queueName);
136 findFirstElement(pathElement, "id").setTextContent("uuid:1000@" + UUID.randomUUID());
137
138
139 findFirstElement(msmqElement, "Priority").setTextContent(toMSMQPriority(priority));
140
141
142 long timeOffset = System.currentTimeMillis();
143 findFirstElement(propertiesElement, "expiresAt").setTextContent(
144 dateFormat.format(new Date(timeOffset + MS_PER_MONTH)));
145 findFirstElement(propertiesElement, "sentAt").setTextContent(
146 dateFormat.format(new Date(timeOffset)));
147 findFirstElement(msmqElement, "TTrq").setTextContent(
148 dateFormat.format(new Date(timeOffset)));
149
150
151 CDATASection cdataSection = message.createCDATASection(messageBody);
152 findFirstElement(message.getDocumentElement(), "Body").appendChild(cdataSection);
153
154
155 try {
156 Transformer tf = TransformerFactory.newInstance().newTransformer();
157 tf.transform(new DOMSource(message), new StreamResult(out));
158 } catch (TransformerException e) {
159 throw new IOException(e);
160 }
161 }
162 }