I have a custom SoapEnvelopeLoggingInterceptor to log the soap envelope of the ws service calls using a transformer.
Is there a way to log the remote URL of the call in this class? (ex. ip address)
The best is to manipulate something like HttpServletRequest.
In context I have:
<sws:interceptors>
<bean id="envelopeLoggingInterceptor" class="path.to.my.CustomSoapEnvelopeLoggingInterceptor">
<property name="loggerName" value="myLogger" />
<property name="logRequest" value="true" />
<property name="logResponse" value="true" />
<property name="logFault" value="true" />
</bean>
</sws:interceptors>
My CustomSoapEnvelopeLoggingInterceptor:
public class CustomSoapEnvelopeLoggingInterceptor extends SoapEnvelopeLoggingInterceptor {
#Override
protected void logMessageSource(String message, Source source) throws TransformerException {
if (source != null){
Transformer trf = this.getTransformerFactory().newTransformer();
trf.setOutputProperty(OutputKeys.INDENT, "yes");
trf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
StringWriter writer = new StringWriter();
StreamResult stream = new StreamResult(writer);
trf.transform(source, stream);
writer.flush();
this.logger.debug(message + stream.getWriter().toString());
}
}
}
Related
I need to to have the requests and responses in the logs of the application but the requests sent by Apache CXF are in FastInfoset (Content-Type: application/fastinfoset) which results in the log of the request and response being unreadable (since it's binary). Is there a way around that so that I keep FastInfoset messages (for performance reasons) but I get proper XML in the logs?
Here is the CXF configuration I have right now, if that helps:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cxf="http://cxf.apache.org/core"
xsi:schemaLocation="
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="logInbound" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
<bean id="logOutbound" class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
<cxf:bus>
<cxf:inInterceptors>
<ref bean="logInbound" />
</cxf:inInterceptors>
<cxf:outInterceptors>
<ref bean="logOutbound" />
</cxf:outInterceptors>
<cxf:outFaultInterceptors>
<ref bean="logOutbound" />
</cxf:outFaultInterceptors>
<cxf:inFaultInterceptors>
<ref bean="logInbound" />
</cxf:inFaultInterceptors>
</cxf:bus>
</beans>
Thank you in advance for any help.
I have taken a look at LoggingInInterceptor.logInputStream and it seems that it does not support fastinfoset. But you can use a custom interceptor instead of LoggingInInterceptor and LoggingOutInterceptor to extract the payload, decode it, and log the original message.
public class CustomInterceptor extends AbstractPhaseInterceptor<Message> {
public CustomInterceptor () {
super(Phase.RECEIVE);
}
public void handleMessage(Message message) {
//Get the message body into payload[] and set a new non-consumed inputStream into Message
InputStream in = message.getContent(InputStream.class);
byte payload[] = IOUtils.readBytesFromStream(in);
ByteArrayInputStream bin = new ByteArrayInputStream(payload);
message.setContent(InputStream.class, bin);
//Decode from FastInfoset and write the payload in your preferred log system
OutputStream out = System.out
decodeFI(in,out);
}
public void handleFault(Message messageParam) {
//Invoked when interceptor fails
//Exception e = message.getContent(Exception.class);
}
}
Replace in the XML file
<bean id="logInbound" class="test.CustomInterceptor" />
<bean id="logOutbound" class="test.CustomInterceptor" />
Finding an example of how to decode a FastInfoset has not been easy. Try this using DOM and FastInfoset-1.2.12.jar. In this repo you have several examples using sTAX and SAX
public void decodeFI(InputStream in, OutputStream out) throws Exception{
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
DOMDocumentParser parser = new DOMDocumentParser();
parser.parse(doc, in);
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(out);
transformer.transform(source, result);
}
I have a requirement to publish an encrypted file (file size can be upto 100 M.B) to a jms queue. Along with the file i have to send a decryption key to the same message which is used by the jms listener to to decrypt file.
I have attached the applicationContext.xml and the jms publisher. Currently i am tryign to use MapMessage to publish both the file and the key, but getting the below error.
2015-12-09 19:31:12,709 INFO [simBatchQueueListener-1] - Received a message for updating organization
2015-12-09 19:31:12,719 DEBUG [simBatchQueueListener-1] - Received a JMS message: Key ->null
2015-12-09 19:31:12,729 DEBUG [simBatchQueueListener-1] - Received a JMS message: File ->null
2015-12-09 19:31:12,729 DEBUG [simBatchQueueListener-1] - Received a JMS message: bytesMessage ->null
weblogic.jms.common.MessageFormatException: [JMSClientExceptions:055130]Invalid data type: java.io.BufferedWriter
at weblogic.jms.common.MapMessageImpl.setObject(MapMessageImpl.java:234)
at com.vodafone.m2m.kssv.jms.JMSNotifier$1.createMessage(JMSNotifier.java:113)
at com.vodafone.m2m.kssv.jms.JMSNotifier$1.createMessage(JMSNotifier.java:106)
at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:602)
at org.springframework.jms.core.JmsTemplate$4.doInJms(JmsTemplate.java:583)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:493)
at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:579)
at com.vodafone.m2m.kssv.jms.JMSNotifier.publishMessage(JMSNotifier.java:106)
at com.vodafone.m2m.kssv.directoryscanner.file.SIMBatchReturnFileProcessor.run(SIMBatchReturnFileProcessor.java:88)
at java.lang.Thread.run(Thread.java:744)
The jms publish should be synchronous. Once the message is read from the queue an ID will be created and the ID need to be acknowledged to the publisher.
As I am new to coding jms could anyone please help me how I can achieve this.
public class JMSNotifier {
private final Logger LOG = LoggerFactory.getLogger(JMSNotifier.class);
private static final String myName = JMSNotifier.class.getSimpleName();
private String filename = null;
private FileInputStream inStream = null;
private BytesMessage bytesMessage = null;
private int bytes_read = 0;
private int BUFLEN = 64;
private byte[] buf1 = new byte[BUFLEN];
private byte[] buf2 = new byte[BUFLEN];
private int length = 0;
private int exitResult = 0;
#Autowired
private JmsTemplate jmsTemplate;
private String simBatchQueue;
private MapMessage m = null;
#Required
public void setSimBatchQueue(String simBatchQueue) {
this.simBatchQueue = simBatchQueue;
}
public synchronized void publishMessage(String destinationName, String msg) throws JMSException {
LOG.debug("Sending message {} on {} queue...", msg.toString(), destinationName);
try {
filename = new String("C:\\Vijay\\cleartext.txt");
inStream = new FileInputStream(filename);
} catch (IOException e) {
System.out.println("Problem getting file: " + e.toString());
System.exit(1);
}
if (Constants.SIM_BATCH_QUEUE.equals(destinationName)) {
destinationName = simBatchQueue;
LOG.trace("{}: Attempting messgage for D_N_SIM_BATCH_QUEUE {} ", myName, simBatchQueue);
} else {
LOG.trace("{}: Unknow JMS destinaion name {} ", myName, destinationName);
throw new JMSException("Unknow JMS destinaion name {}" + destinationName);
}
jmsTemplate.send(destinationName, new MessageCreator() {
#Override
public MapMessage createMessage(Session session) throws JMSException {
try {
m = session.createMapMessage();
m.setObject("file", writeToFile(inStream));
m.setObject("key","123");
return m;
} catch (Exception ex) {
ex.printStackTrace();
return m;
}
}
});
}
public static String prepareNormalDateString() {
Calendar tzCal = Calendar.getInstance();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-ddhhmmss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
StringBuffer date = new StringBuffer(dateFormat.format(tzCal.getTime()));
date.append("UTC");
return (date.toString());
}
private BufferedWriter writeToFile(InputStream is) {
BufferedReader br = null;
String time = prepareNormalDateString();
String filepath = "C:\\vijay\\File" + time + ".csv";
String line;
BufferedWriter bufferedWriter = null;
try {
bufferedWriter = new BufferedWriter(new FileWriter(filepath));
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
bufferedWriter.write(line);
}
bufferedWriter.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return bufferedWriter;
}
}
public class SimBatchQueueMessageHandler implements MessageListener {
private static org.slf4j.Logger myLogger = LoggerFactory.getLogger(SimBatchQueueMessageHandler.class);
private String myName = SimBatchQueueMessageHandler.class.getSimpleName();
int bytes_read = 0;
final int BUFLEN = 64;
byte[] buf1 = new byte[BUFLEN];
byte[] buf2 = new byte[BUFLEN];
int length = 0;
int exitResult = 0;
FileOutputStream fos = null;
File newFile = null;
private static int count = 1;
#Override
public synchronized void onMessage(Message message) {
try {
myLogger.info("Received a message for updating organization");
Source source;
count = count + 1;
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
source = new StringSource(textMessage.getText());
myLogger.debug("Text Message received {}", textMessage.getText());
} else if (message instanceof MapMessage) {
MapMessage msg = (MapMessage) message;
myLogger.debug("Received a JMS message: Key ->" + msg.getObject("key"));
myLogger.debug("Received a JMS message: File ->" + msg.getObject("file"));
Object bytesMessage = msg.getObject("file");
myLogger.debug("Received a JMS message: bytesMessage ->" + bytesMessage);
} else if (message instanceof BytesMessage) {
else {
throw new MessageConversionException("Unsupported JMS Message type " + message.getClass() + ", expected instance of TextMessage or BytesMessage for " + message);
}
Object[] params = new Object[]{myName};
} catch (JMSException jmsEx) {
myLogger.error("Error occured while publishing" + jmsEx);
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:ws="http://jax-ws.dev.java.net/spring/core"
xmlns:wss="http://jax-ws.dev.java.net/spring/servlet"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd
http://jax-ws.dev.java.net/spring/core
http://jax-ws.java.net/spring/core.xsd
http://jax-ws.dev.java.net/spring/servlet
http://jax-ws.java.net/spring/servlet.xsd">
<!--
Activates various annotations to be detected in bean classes:
Spring's #Required and #Autowired, as well as JSR 250's #Resource.
-->
<context:annotation-config/>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.springframework.util.Log4jConfigurer" />
<property name="targetMethod" value="initLogging" />
<property name="arguments">
<list>
<value>file:///${MYCOMPONENT_CONFIG_PATH}/log4j.properties</value>
</list>
</property>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="searchSystemEnvironment" value="true" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>file:///${MYCOMPONENT_CONFIG_PATH}/jdbc.properties</value>
<!--<value>file:///${MYCOMPONENT_CONFIG_PATH}/MYCOMPONENTConfig.xml</value>-->
<value>file:///${MYCOMPONENT_CONFIG_PATH}/MYCOMPONENT.properties</value>
</list>
</property>
</bean>
<!--
Uses Apache Commons DBCP for connection pooling. See Commons DBCP documentation
for the required JAR files. Alternatively you can use another connection pool
such as C3P0, similarly configured using Spring.
-->
<!-- USE FOR GLASSFISH DATABASE POOLING
<bean id="dataSourceMYCOMPONENT" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${MYCOMPONENT.jdbc.dataSource}"/>
</bean>-->
<!-- USE FOR SPRING DATABASE POOLING -->
<bean id="dataSourceMYCOMPONENT" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}"
p:password="${jdbc.password}" >
<property name="defaultAutoCommit" value="false"/>
<property name="maxActive" value="10"/>
<property name="maxIdle" value="5"/>
<property name="minIdle" value="2"/>
<property name="initialSize" value="1"/>
<property name="maxWait" value="500"/>
<property name="testOnBorrow" value ="true"/>
<property name="timeBetweenEvictionRunsMillis" value ="1800000"/>
<property name="minEvictableIdleTimeMillis" value ="300000"/>
</bean>
<bean id="lobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler" lazy-init="true">
<property name="nativeJdbcExtractor" ref="nativeJdbcExtractor"/>
</bean>
<bean id="dao" class="com.mycompany.m2m.MYCOMPONENT.support.dataaccess.jdbc.JdbcDataAccessObject">
<!-- Must set schemaName before dataSource! -->
<property name="schemaName" value="${jdbc.schema}"/>
<property name="dbUser" value="${jdbc.username}"/>
<property name="dataSource" ref="dataSourceMYCOMPONENT"/>
</bean>
<!-- Ends -->
<!-- USE FOR JMS CONFIGURATION ************************* -->
<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplate" />
<property name="jndiName" value="${MYCOMPONENT.jms.connectionFactory}" />
</bean>
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">${MYCOMPONENT.jndi.initialFactory}</prop>
<prop key="java.naming.provider.url">${MYCOMPONENT.jndi.providerUrl}</prop>
</props>
</property>
</bean>
<bean id="jmsDestinationResolver" class="org.springframework.jms.support.destination.JndiDestinationResolver">
<property name="jndiTemplate" ref="jndiTemplate" />
<property name="cache" value="true" />
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="defaultDestination" ref="simBatchQueue" />
<property name="destinationResolver" ref="jmsDestinationResolver" />
<property name="connectionFactory" ref="connectionFactory" />
<property name="sessionAcknowledgeModeName" value="AUTO_ACKNOWLEDGE" />
<property name="sessionTransacted" value="false" />
</bean>
<bean id="jmsNotifier" class="com.mycompany.m2m.MYCOMPONENT.jms.JMSNotifier">
<property name="simBatchQueue" value="${MYCOMPONENT.jms.simBatchQueue}" />
</bean>
<!-- JMS Message Listener to handle messages from MYCOMPONENT-->
<bean id="simBatchQueueMessageListener" class="com.mycompany.m2m.MYCOMPONENT.jms.listener.SimBatchQueueMessageHandler"/>
<bean id="simBatchQueue" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplate" />
<property name="jndiName" value="${MYCOMPONENT.jms.simBatchQueue}" />
</bean>
<bean id="simBatchQueueListener" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="concurrentConsumers" value="1" />
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="simBatchQueue" />
<property name="messageListener" ref="simBatchQueueMessageListener" />
<property name="pubSubDomain" value="true"/>
<property name="subscriptionDurable" value="false"/>
<!--<property name="durableSubscriptionName" value="${sasm.jms.orgDurableSubName}"/>-->
</bean>
</beans>
I'm making a SOAP request with custom headers which contains the security part of the request.
But the request now contains two headers and its throwing the following error :
[Request processing failed; nested exception is org.springframework.ws.soap.client.SoapFaultClientException: No WS-Security header found] with root cause
The headers that is formed is :
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header><soapenv:Envelope xmlns:ser="dasdasdasd" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header><wsse:Security xmlns:wsse="asdasdasdas" soapenv:mustUnderstand="1"> <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-2"><wsse:Username>test</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">adasdasdasdasd</wsse:Password><wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">!##!####$#!#!##%*(&*&^%#$##</wsse:Nonce><wsu:Created>2014-09-04 T1015.41.649Z</wsu:Created></wsse:UsernameToken></wsse:Security></soapenv:Header></soapenv:Envelope></SOAP-ENV:Header><SOAP-ENV:Body><ns2:CreateSaleOrderRequest xmlns:ns2="http://uniware.unicommerce.com/services/"><ns2:SaleOrder><ns2:DisplayOrderCode>200</ns2:DisplayOrderCode></ns2:SaleOrder></ns2:CreateSaleOrderRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>
My code for the above request is below :
private static final String uri = "http://requestb.in/1eh2un81";
public String createSaleOrder(Suborder suborder)
{
SaleOrder saleorder = new SaleOrder();
saleorder = setSaleOrderObject(suborder);
CreateSaleOrderRequest request = new CreateSaleOrderRequest();
request.setSaleOrder(saleorder);
String response = this.getWebServiceTemplate().marshalSendAndReceive(uri, request,
new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException
{
SoapMessage soapmessage = (SoapMessage)message;
SoapHeader header = soapmessage.getSoapHeader();
//soapmessage.getEnvelope().addAttribute(, "soapenv");
StringBuilder soapheader = new StringBuilder();
soapheader.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ser=\"zsdasdasdasd">");
soapheader.append("<soapenv:Header>");
soapheader.append("<wsse:Security soapenv:mustUnderstand=\"1\" xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\"> ");
soapheader.append("<wsse:UsernameToken wsu:Id=\"UsernameToken-2\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">");
soapheader.append("<wsse:Username>test</wsse:Username>");
soapheader.append("<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\">adasdasdasdasd</wsse:Password>");
soapheader.append("<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">!2312312!##!##!#$##%R</wsse:Nonce>");
soapheader.append("<wsu:Created>2014-09-04 T1015.41.649Z</wsu:Created>");
soapheader.append("</wsse:UsernameToken>");
soapheader.append("</wsse:Security>");
soapheader.append("</soapenv:Header>");
soapheader.append("</soapenv:Envelope>");
StringSource HeaderSource = new StringSource(soapheader.toString());
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(HeaderSource,header.getResult());
}
}).toString();
System.out.println(response);
Please suggest how do i resolve this error.TIA!
Uhm provided you're using spring you would have to go something like this.. inside your xml for the ws you should have:
<bean id="YourWsClientBean" class="eu.europa.acer.aris.dciws.client.DciWsClient">
<constructor-arg ref="webServiceTemplate"></constructor-arg>
</bean>
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="marshaller" ref="marshaller"></property>
<property name="unmarshaller" ref="unMarshaller"></property>
<property name="messageSender">
<bean
class="org.springframework.ws.transport.http.CommonsHttpMessageSender">
</bean>
</property>
<!-- NON PROXY
<property name="messageSender" ref = "httpSender"></property> -->
<property name="defaultUri" value="https://testframework.test-acer-remit.eu/dci-ws/" />
<property name="interceptors">
<list>
<ref bean="securityConfInterceptor" />
</list>
</property>
</bean>
<bean id="securityConfInterceptor" class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor">
<property name="policyConfiguration" value="classpath:securityPolicy.xml" />
<property name="callbackHandlers">
<!-- <bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="keyStore" ref="keyStore" /> <property name="privateKeyPassword"
value="changeit" /> <property name="trustStore" ref="trustStore" /> </bean> -->
<list>
<ref bean="keyStoreHandler"/>
</list>
</property>
</bean>
marshaller and unmarshaller should be clear to you i suppose.
The most important part in your case is
inside the securityPolicy.xml you will be able to define your desirede policy for outgoing//incoming messages, be it signature, usernameandpassword, etc..
The following file for example is for signing the request with a certain certificate.
<?xml version="1.0" encoding="UTF-8"?>
<!-- <xwss:SecurityConfiguration dumpMessages="false" xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:Sign includeTimestamp="false"> <xwss:X509Token certificateAlias="ceremp
staging ca"/> </xwss:Sign> </xwss:SecurityConfiguration> -->
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<!-- <xwss:RequireTimestamp maxClockSkew="60" timestampFreshnessLimit="300"/>
<xwss:RequireUsernameToken passwordDigestRequired="false" nonceRequired="false"/>
<xwss:Timestamp /> <xwss:UsernameToken name="mojo" password="mojopass" digestPassword="true"
useNonce="true"/> -->
<xwss:Sign>
<xwss:X509Token certificateAlias="acerprivate" />
<!-- <xwss:X509Token certificateAlias="acer staging cert" /> -->
<xwss:CanonicalizationMethod algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<xwss:SignatureMethod algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<xwss:SignatureTarget type="xpath"
value="./SOAP-ENV:Envelope/SOAP-ENV:Body">
<xwss:DigestMethod algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<xwss:Transform algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
<xwss:AlgorithmParameter name="XPATH"
value="./SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/ds:Signature[1]/ds:KeyInfo/wsse:SecurityTokenReference" />
</xwss:Transform>
<xwss:Transform
algorithm="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#STR-Transform">
<xwss:AlgorithmParameter name="CanonicalizationMethod"
value="http://www.w3.org/2001/10/xml-exc-c14n#" />
</xwss:Transform>
</xwss:SignatureTarget>
</xwss:Sign>
</xwss:SecurityConfiguration>
Hope this give you an hand as a general concept.
At times I advice some colleague new with ws to take the dirty alternative, if they want to keep the altering as simple as possible.
E.g. this is from spring forum -->
public void sendAndReceiveXMLPayload(String xmlFileNamePath) throws IOException {
ClassPathResource
classPathResource =
new ClassPathResource(xmlFileNamePath);
Source
requestSource =
new ResourceSource(classPathResource);
StringResult
result =
new StringResult();
getWebServiceTemplate().
sendSourceAndReceiveToResult(
requestSource,
new WSSESecurityHeaderRequestWebServiceMessageCallback(),
result
);
}
notice WSSESecurityHeaderRequestWebServiceMessageCallback
define a
public class WSSESecurityHeaderRequestWebServiceMessageCallback implements WebServiceMessageCallback {
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
try {
// Assumption: We are using the default SAAJWebMessageFactory
SaajSoapMessage
saajSoapMessage =
(SaajSoapMessage)message;
SOAPMessage
soapMessage =
saajSoapMessage.getSaajMessage();
SOAPPart
soapPart =
soapMessage.getSOAPPart();
SOAPEnvelope
soapEnvelope =
soapPart.getEnvelope();
SOAPHeader
soapHeader =
soapEnvelope.getHeader();
Name
headerElementName =
soapEnvelope.createName(
"Security",
"wsse",
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
);
// Add "Security" soapHeaderElement to soapHeader
SOAPHeaderElement
soapHeaderElement =
soapHeader.addHeaderElement(headerElementName);
// This may be important for some portals!
soapHeaderElement.setActor(null);
// Add usernameToken to "Security" soapHeaderElement
SOAPElement
usernameTokenSOAPElement =
soapHeaderElement.addChildElement("UsernameToken");
// Add username to usernameToken
SOAPElement
userNameSOAPElement =
usernameTokenSOAPElement.addChildElement("Username");
userNameSOAPElement.addTextNode("myUserName");
// Add password to usernameToken
SOAPElement
passwordSOAPElement =
usernameTokenSOAPElement.addChildElement("Password");
passwordSOAPElement.addTextNode("myPassword");
} catch (SOAPException soapException) {
throw new RuntimeException("WSSESecurityHeaderRequestWebServiceMessageCallback", soapException);
}
}
}
in this class feel free to change what you do with your header as you see fit and you're done...
I am trying to create a listener using spring-amqp(RabbitMQ) that supports publisher returns. I couldn't find any example for this case, but I tried to do the following:
#Component
public class ImportModelHandler {
#Autowired
private ModelService modelService;
public byte[] handleMessage(byte[] file) throws Exception {
try {
if (file == null || file.length == 0) {
throw new IllegalArgumentException("File is empty");
}
return ModelService.OBJECT_MAPPER.writeValueAsBytes(
modelService.importModel(file));
} catch (Exception e) {
return ModelService.OBJECT_MAPPER.writeValueAsBytes(Response.createErrorResponse(e));
}
}
}
Xml configuration:
<bean id="importModelListener"
class="org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter">
<constructor-arg ref="importModelHandler"/>
</bean>
<rabbit:connection-factory id="connectionFactory" host="192.168.1.50" port="5672" username="guest" password="guest"
publisher-returns="true"/>
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"/>
<rabbit:admin connection-factory="connectionFactory"/>
<rabbit:queue name="import.model"/>
<rabbit:queue name="download.model"/>
<bean id="rabbitListenerContainerFactory"
class="org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="concurrentConsumers" value="3"/>
<property name="maxConcurrentConsumers" value="10"/>
</bean>
<rabbit:annotation-driven container-factory="rabbitListenerContainerFactory"/>
<rabbit:direct-exchange name="import.model.exchange">
<rabbit:bindings>
<rabbit:binding queue="import.model"/>
</rabbit:bindings>
</rabbit:direct-exchange>
<rabbit:listener-container
connection-factory="connectionFactory">
<rabbit:listener ref="importModelListener" queue-names="import.model"/>
</rabbit:listener-container>
Then I tried to create code for calling this listener:
URL resource = ImportModelTest.class.getResource("/models/model.jar");
File file = new File(resource.toURI());
byte[] bytes = IOUtils.toByteArray(new FileInputStream(file));
MessageProperties messageProperties = new MessageProperties();
messageProperties.setContentType(MessageProperties.CONTENT_TYPE_BYTES);
Message message = new Message(bytes, messageProperties);
rabbitTemplate.convertAndSend("import.model", message);
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
#Override
public void returnedMessage(Message message, int i, String s, String s1, String s2) {
System.out.println(new String(message.getBody()));
}
});
But I have got:
org.springframework.amqp.AmqpException: Cannot determine ReplyTo
message property value: Request message does not contain reply-to
property, and no default response Exchange was set.
How could I create a listener that will use Publisher Returns mechanism?
I have successfully sent simple email using this:
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setTo("someone#abc.example");
mailMessage.setSubject("This is the test message for testing gmail smtp server using spring mail");
mailMessage.setFrom("abc#gmail.com");
mailMessage.setText("This is the test message for testing gmail smtp server using spring mail. \n" +
"Thanks \n Regards \n Saurabh ");
mailSender.send(mailMessage);
What setting I need to chnage so that I can send HTML emails
import javax.mail.internet.MimeMessage;
import org.springframework.mail.javamail.MimeMessageHelper;
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, "utf-8");
String htmlMsg = "<h3>Hello World!</h3>";
//mimeMessage.setContent(htmlMsg, "text/html"); /** Use this or below line **/
helper.setText(htmlMsg, true); // Use this or above line.
helper.setTo("someone#abc.example");
helper.setSubject("This is the test message for testing gmail smtp server using spring mail");
helper.setFrom("abc#gmail.com");
mailSender.send(mimeMessage);
In Spring this should be done this way:
Your email class:
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
public class HTMLMail
{
private JavaMailSender mailSender;
public void setMailSender(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
public void sendMail(String from, String to, String subject, String msg) {
try {
MimeMessage message = mailSender.createMimeMessage();
message.setSubject(subject);
MimeMessageHelper helper;
helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setText(msg, true);
mailSender.send(message);
} catch (MessagingException ex) {
Logger.getLogger(HTMLMail.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
beans:(Spring-Mail.xml)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.gmail.com" />
<property name="port" value="587" />
<property name="username" value="youremail#gmail.com" />
<property name="password" value="yourpassword" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.starttls.enable">true</prop>
</props>
</property>
</bean>
<bean id="htmlMail" class="com.mohi.common.HTMLMail">
<property name="mailSender" ref="mailSender" />
</bean>
</beans>
Usage:
ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Mail.xml");
HTMLMail mm = (HTMLMail) context.getBean("htmlMail");
String html="<p>Hi!</p>Link text";
mm.sendMail("sender#gmail.com",
"receiver#gmail.com",
"test html email",
html);
Full example here .
I don't think that SimpleMailMessage class has such options.
I'm sure that you can do it with JavaMailSender and MimeMessagePreparator, because you need to set MIME content type for HTML.
See this link for help:
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mail.html
You might be interested in checking this article: "Rich HTML email in Spring with Thymeleaf" http://www.thymeleaf.org/doc/articles/springmail.html
It uses Thymeleaf as a templating view layer, but the concepts and Spring-specific code explained there are common to all Spring applications.
Besides, it has a companion example application which source code you can use as a base for your needs.
Regards,
Daniel.
Class Level:
public String sendEmailToUsers(String emailId,String subject, String name){
String result =null;
MimeMessage message =mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, false, "utf-8");
String htmlMsg = "<body style='border:2px solid black'>"
+"Your onetime password for registration is "
+ "Please use this OTP to complete your new user registration."+
"OTP is confidential, do not share this with anyone.</body>";
message.setContent(htmlMsg, "text/html");
helper.setTo(emailId);
helper.setSubject(subject);
result="success";
mailSender.send(message);
} catch (MessagingException e) {
throw new MailParseException(e);
}finally {
if(result !="success"){
result="fail";
}
}
return result;
}
XML Level:
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.gmail.com" />
<property name="port" value="587" />
<property name="username" value="********#gmail.com" />
<property name="password" value="********" />
<property name="javaMailProperties">
<props>
<prop key="mail.transport.protocol">smtp</prop>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.starttls.enable">true</prop>
</props>
</property>
</bean>
String emailMessage = report.toString();
Map velocityContext = new HashMap();
velocityContext.put("firstName", "messi");
velocityContext.put("Date",date );
velocityContext.put("Exception",emailMessage );
String text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, "VelocityTemplate.vm","UTF-8", velocityContext);
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper;
helper = new MimeMessageHelper(message, true);
helper.setTo("abc#gmail.com");
helper.setFrom("xyz#gmail.com");
helper.setSubject("new email");
helper.setText(text, true);
mailSender.send(message);