001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.servicemix.eip.patterns;
018
019 import javax.jbi.messaging.ExchangeStatus;
020 import javax.jbi.messaging.InOnly;
021 import javax.jbi.messaging.InOut;
022 import javax.jbi.messaging.MessageExchange;
023 import javax.jbi.messaging.MessagingException;
024 import javax.jbi.messaging.NormalizedMessage;
025 import javax.jbi.messaging.RobustInOnly;
026 import javax.xml.namespace.QName;
027 import javax.xml.parsers.ParserConfigurationException;
028 import javax.xml.transform.Source;
029 import javax.xml.transform.dom.DOMSource;
030
031 import org.w3c.dom.Document;
032 import org.w3c.dom.Element;
033 import org.w3c.dom.Node;
034
035 import org.apache.servicemix.common.util.MessageUtil;
036 import org.apache.servicemix.eip.EIPEndpoint;
037 import org.apache.servicemix.eip.support.ExchangeTarget;
038 import org.apache.servicemix.jbi.jaxp.SourceTransformer;
039
040 /**
041 * Implementation of the
042 * <a href="http://www.enterpriseintegrationpatterns.com/DataEnricher.html">'Content-Enricher'</a>
043 * Pattern.
044 *
045 * @org.apache.xbean.XBean element="content-enricher"
046 * description="A Content Enricher"
047 */
048 public class ContentEnricher extends EIPEndpoint {
049
050 /**
051 * The address of the target endpoint
052 */
053 private ExchangeTarget target;
054
055 /**
056 * the target to enrich the request
057 */
058 private ExchangeTarget enricherTarget;
059
060 /**
061 * the QName of the resulting root node
062 */
063 private QName enricherElementName = new QName("enricher");
064
065 /**
066 * the QName of the element which contains the 'IN Message'
067 * within the response message
068 */
069 private QName requestElementName = new QName("request");
070
071 /**
072 * the QName of the element which contains the message
073 * which was produced by the enricherTarget within the
074 * response message
075 */
076 private QName resultElementName = new QName("result");
077
078 /**
079 * Should message properties be copied ?
080 */
081 private boolean copyProperties;
082
083 /**
084 * Should message attachments be copied ?
085 */
086 private boolean copyAttachments;
087
088 /**
089 * returns the QName of the resulting root node
090 * @return QName of the resulting root node
091 */
092 public QName getEnricherElementName() {
093 return enricherElementName;
094 }
095
096 /**
097 * Sets the QName of the resulting root node
098 * @param enricherElementName QName of the resulting root node
099 */
100 public void setEnricherElementName(QName enricherElementName) {
101 this.enricherElementName = enricherElementName;
102 }
103
104 /**
105 * Returns the QName of the element which contains the 'IN Message'
106 * within the response message
107 *
108 * @return QName
109 */
110 public QName getRequestElementName() {
111 return requestElementName;
112 }
113
114 /**
115 * Sets the QName of the element which contains the 'IN Message'
116 * within the response message
117 *
118 * @param requestElementName QName
119 */
120 public void setRequestElementName(QName requestElementName) {
121 this.requestElementName = requestElementName;
122 }
123
124 /**
125 * Returns the QName of the element which contains the message
126 * which was produced by the enricherTarget within the
127 * response message
128 *
129 * @return QName
130 */
131 public QName getResultElementName() {
132 return resultElementName;
133 }
134
135 /**
136 * Sets the QName of the element which contains the message
137 * which was produced by the enricherTarget within the
138 * response message
139 *
140 * @param resultElementName QName
141 */
142 public void setResultElementName(QName resultElementName) {
143 this.resultElementName = resultElementName;
144 }
145
146 public boolean isCopyProperties() {
147 return copyProperties;
148 }
149
150 /**
151 * If this is set to <code>true</code>, message properties from the incoming exchange and the enricher exchange will be copied
152 * to the outgoing message exchange. The default value is <code>false</code> (do not copy message properties).
153 *
154 * @param copyProperties
155 */
156 public void setCopyProperties(boolean copyProperties) {
157 this.copyProperties = copyProperties;
158 }
159
160 public boolean isCopyAttachments() {
161 return copyAttachments;
162 }
163
164 /**
165 * If this is set to <code>true</code>, message attachments from the incoming exchange and the enricher exchange will be copied
166 * to the outgoing message exchange. The default value is <code>false</code> (do not copy message atachments).
167 *
168 * @param copyAttachments
169 */
170 public void setCopyAttachments(boolean copyAttachments) {
171 this.copyAttachments = copyAttachments;
172 }
173
174 protected void processAsync(MessageExchange exchange) throws Exception {
175 throw new IllegalStateException();
176 }
177
178 protected void processSync(MessageExchange exchange) throws Exception {
179 throw new IllegalStateException();
180 }
181
182 public void process(MessageExchange exchange) throws Exception {
183
184 if (!(exchange instanceof InOnly) && !(exchange instanceof RobustInOnly)) {
185 fail(exchange, new UnsupportedOperationException("Use an InOnly or RobustInOnly MEP"));
186 }
187
188 // Skip done exchanges
189 if (exchange.getStatus() == ExchangeStatus.DONE) {
190 return;
191 // Handle error exchanges
192 } else if (exchange.getStatus() == ExchangeStatus.ERROR) {
193 return;
194 }
195
196 InOut enricherTargetME = getExchangeFactory().createInOutExchange();
197 enricherTarget.configureTarget(enricherTargetME, getContext());
198 MessageUtil.transferInToIn(exchange, enricherTargetME);
199
200 sendSync(enricherTargetME);
201
202 if (enricherTargetME.getStatus() == ExchangeStatus.ERROR) {
203 fail(exchange, enricherTargetME.getError());
204 return;
205 }
206
207 Document document = combineToDOMDocument(exchange.getMessage("in"), enricherTargetME.getMessage("out"));
208
209 done(enricherTargetME);
210
211 MessageExchange outExchange = getExchangeFactory().createInOnlyExchange();
212 NormalizedMessage out = outExchange.createMessage();
213 target.configureTarget(outExchange, getContext());
214 out.setContent(new DOMSource(document));
215
216 outExchange.setMessage(out, "in");
217
218 if (copyProperties || copyAttachments) {
219 copyPropertiesAndAttachments(exchange.getMessage("in"), outExchange.getMessage("in"));
220 copyPropertiesAndAttachments(enricherTargetME.getMessage("out"), outExchange.getMessage("in"));
221 }
222
223 sendSync(outExchange);
224 done(exchange);
225 }
226
227 /**
228 * Combines two NormalizedMessages to one DOM Document. The
229 * element Names are specified via the following properties:
230 * enricherElementName, requestElementName, resultElementName
231 *
232 * Example:
233 * Content of Message1 :
234 *
235 * <hello/>
236 *
237 * Content of Message 2:
238 *
239 * <message2/>
240 *
241 * Result of this method a DOM Document containing the following:
242 *
243 * <enricher>
244 * <request>
245 * <hello/>
246 * </request>
247 * <result>
248 * <message2/>
249 * </result>
250 * </enricher>
251 *
252 */
253 private Document combineToDOMDocument(NormalizedMessage requestMessage, NormalizedMessage targetResultMessage)
254 throws Exception, ParserConfigurationException {
255
256 Node originalDocumentNode = getDOMNode(requestMessage.getContent());
257 Node targetResultNode = getDOMNode(targetResultMessage.getContent());
258
259 Document document = new SourceTransformer().createDocument();
260 Element enricherElement = createChildElement(enricherElementName, document);
261 Element requestElement = createChildElement(requestElementName, document);
262
263 Node node = document.importNode(originalDocumentNode, true);
264 requestElement.appendChild(node);
265 enricherElement.appendChild(requestElement);
266 document.appendChild(enricherElement);
267
268 Element resultElement = createChildElement(resultElementName, document);
269
270 Node node2 = document.importNode(targetResultNode, true);
271
272 resultElement.appendChild(node2);
273 enricherElement.appendChild(resultElement);
274 return document;
275
276 }
277
278 private Element createChildElement(QName name, Document document) {
279 Element elem;
280 if ("".equals(name.getNamespaceURI())) {
281 elem = document.createElement(name.getLocalPart());
282 } else {
283 elem = document.createElementNS(name.getNamespaceURI(), name.getPrefix() + ":" + name.getLocalPart());
284 }
285 return elem;
286 }
287
288 private Node getDOMNode(Source source) throws Exception {
289 SourceTransformer sourceTransformer = new SourceTransformer();
290 Node node = sourceTransformer.toDOMNode(source);
291 if (node.getNodeType() == Node.DOCUMENT_NODE) {
292 node = ((Document) node).getDocumentElement();
293 }
294 return node;
295 }
296
297 public void setTarget(ExchangeTarget target) {
298 this.target = target;
299 }
300
301 public void setEnricherTarget(ExchangeTarget enricherTarget) {
302 this.enricherTarget = enricherTarget;
303 }
304
305
306 /**
307 * Copies properties and attachments from one message to another
308 * depending on the endpoint configuration
309 *
310 * @param from the message containing the properties and attachments
311 * @param to the destination message where the properties and attachments are set
312 */
313 private void copyPropertiesAndAttachments(NormalizedMessage from, NormalizedMessage to) throws MessagingException {
314 if (copyProperties) {
315 copyProperties(from, to);
316 }
317 if (copyAttachments) {
318 copyAttachments(from, to);
319 }
320 }
321
322 }