I am developing a REST API which is a #POST and #Consumes both MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON . I need to implement validations for the incoming request. I don't want to have Bean Level validation JSR-303. I need to have a Validation class which handles all the validations and i need to configure interceptor for the incoming XML request before Unmarshalling. I looked into Apache cxf interceptors and it is mainly if you are enabling the Bean Validations. How shall i do it?
I have found the way how to do this without the usage of BeanValidationFeature.
public class YourFilter implements ContainerRequestFilter{
#Override
public void filter(ContainerRequestContext request){
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
final InputStream inputStream = request.getEntityStream();
final StringBuilder builder = new StringBuilder();
try
{
IOUtils.copy(inputStream, outStream);
byte[] requestEntity = outStream.toByteArray();
if (requestEntity.length == 0) {
builder.append("");
} else {
builder.append(new String(requestEntity,"UTF-8"));
request.setEntityStream(new ByteArrayInputStream(requestEntity));
setRequest(builder.toString());
validateYourRequest(builder.toString());
}
}catch (Exception ex) {
logger.log(Level.TRACE,"Error occured while converting the request into Stream",ex.getCause());
}
}
}
And in application.context.xml
<bean id="YourFilter" class="com.test.YourFilter"/>
<jaxrs:server id="restContainer" address="/">
<jaxrs:serviceBeans>
<bean class="com.test.YourController" />
</jaxrs:serviceBeans>
<jaxrs:extensionMappings>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</jaxrs:extensionMappings>
<jaxrs:providers>
<ref bean="jsonProvider" />
<ref bean="jaxbXmlProvider" />
<ref bean="YourFilter"/>
</jaxrs:providers>
</jaxrs:server>
Related
I am using Spring Batch.Following is the jobContext.xml file, JdbcCursorItemReader is reading data from MySQL Database.
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<import resource="infrastructureContext.xml"/>
<batch:job id="readProcessWriteProducts">
<batch:step id="readWriteProducts">
<tasklet>
<chunk reader="reader" processor="processer" writer="writer" commit-interval="5"> </chunk>
</tasklet>
</batch:step>
</batch:job>
<bean id="reader" class="org.springframework.batch.item.database.JdbcCursorItemReader">
<property name="dataSource" ref="dataSource"></property>
<property name="sql" value="SELECT id, name, description, price FROM product"></property>
<property name="rowMapper" ref="productItemReader"></property>
</bean>
<bean id="productItemReader" class="com.itl.readprocesswrite.reader.ProductItemReader"></bean>
<bean id="processer" class="com.itl.readprocesswrite.processor.ProductItemProcessor">
<constructor-arg ref="jdbcTemplate"></constructor-arg>
</bean>
<bean id="writer" class="com.itl.readprocesswrite.writer.ProductJdbcItemWriter">
<constructor-arg ref="jdbcTemplate"></constructor-arg>
</bean>
</beans>
Now, I want to read data from Apache Solr.
I tried following code to read data from Apache Solr.
public class SolrJDrive {
public static void main(String[] args) throws MalformedURLException, SolrServerException {
System.out.println("SolrJDrive::main");
SolrServer solr = new CommonsHttpSolrServer("http://localhost:8983/solr");
ModifiableSolrParams params = new ModifiableSolrParams();
params.set("qt", "/select");
params.set("q", "*:*");
params.set("spellcheck", "on");
params.set("spellcheck.build", "true");
QueryResponse response = solr.query(params);
SolrDocumentList results = response.getResults();
for (int i = 0; i < results.size(); ++i) {
System.out.println(results.get(i));
}
}//end of method main
}//end of class SolrJDrive
Now how do I integrate this with Spring Batch?
In addition to what I said on your other question (Is it possible to integrate Apache Solr with Spring Batch?), here's an example of your Solr custom ItemReader :
public class SolrReader implements ItemReader<SolrDocumentList> {
#Override
public SolrDocumentList read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
SolrServer solr = new CommonsHttpSolrServer("http://localhost:8983/solr");
ModifiableSolrParams params = new ModifiableSolrParams();
params.set("qt", "/select");
params.set("q", "*:*");
params.set("spellcheck", "on");
params.set("spellcheck.build", "true");
QueryResponse response = solr.query(params);
SolrDocumentList results = response.getResults();
return results;
}
}
You would then need an ItemProcessor to convert your SolrDocumentList to something you can work with (ie. a POJO).
I have the following setup connected as follows:
1) response & request channel
2) transformer for ws response/request to a system value object
3) WS request/response channel
4) Outbound gateway
<!-- ~~~~~~~~~~~~~~~~~ -->
<!-- integration layer -->
<!-- ~~~~~~~~~~~~~~~~~ -->
<int:channel id="getStatusRequestChannel"/>
<int:channel id="getStatusResponseChannel"/>
<int:channel id="getStatusWSRequestChannel"/>
<int:channel id="getStatusWSResponseChannel"/>
<!-- ~~~~~~~~~~~~~~~~~~ -->
<!-- gateway definition -->
<!-- ~~~~~~~~~~~~~~~~~~ -->
<int:gateway id="mnpGateway" service-interface="com.iquest.play.integration.mnp.MNPGateway">
<int:method name="getMNPStatus" request-channel="getStatusRequestChannel" reply-channel="getStatusResponseChannel"/>
</int:gateway>
<!-- ~~~~~~~~~~~~~~ -->
<!-- channel chains -->
<!-- ~~~~~~~~~~~~~~ -->
<int:chain input-channel="getStatusRequestChannel" output-channel="getStatusWSRequestChannel">
<int:transformer ref="getStatusTransformer" method="transformMNPStatusRequest"/>
</int:chain>
<int:chain input-channel="getStatusWSResponseChannel" output-channel="getStatusResponseChannel">
<int:transformer ref="getStatusTransformer" method="transformMNPStatusResponse"/>
</int:chain>
<!-- ~~~~~~~~~~~~~~~~ -->
<!-- outbound gateway -->
<!-- ~~~~~~~~~~~~~~~~ -->
<int-ws:outbound-gateway id="getStatusOutboundGW"
request-channel="getStatusWSRequestChannel"
reply-channel="getStatusWSResponseChannel"
marshaller="marshaller"
unmarshaller="marshaller"
destination-provider="mnpUriProvider"/>
This is the WSDL :
<wsdl:operation name="getCaseInfo">
<wsdl:documentation>Message</wsdl:documentation>
<wsdl:input message="tns:GetCaseInfoRequest">
</wsdl:input>
<wsdl:output message="tns:GetCaseInfoResponse">
</wsdl:output>
<wsdl:fault message="tns:GetCaseInfoError" name="getCaseInfoError">
</wsdl:fault>
</wsdl:operation>
How can I catch the Soap Fault?
AFTER EDIT :
I've tried extending a SoapFaultMessageResolver and to overide the method public void resolveFault(WebServiceMessage message) throws IOException
from there I'm trying to throw a custom IntegrationException (that extends IOException) that I will catch in the method that calls the gateway interface. This is the calling method:
try {
gateway.MethodA();
} catch (Exception e) {
/// I was trying to catch IntegrationException
}
The problem is that the caught exception is of type WebServiceIOException that has the root cause IntegrationException, and it triggers a huge error log. So I think this approach isn't right.
The <int-ws:outbound-gateway> is fully based on WebServiceTemplate from Spring WS, so there is no any stops to do the same with Soap Fault in Spring Integration.
By default it will be a WebServiceException, which is thrown from WebServiceTemplate.sendAndReceive and propagated to the MessageHandler, which, in turn, throws it to the caller or send to the error-channel as a Message payload.
As soon as you use <int:gateway> that Exception might be catched on the method invocation.
If you want to do some logic with that Fault before rethrow you can inject fault-message-resolver as an implementation of FaultMessageResolver to the <int-ws:outbound-gateway>.
We can handle soap fault message during unmarshel and throw the appropriate message to error handler.
This article explains clearly how to handle soap fault message. Hope this might be helpful
http://blog.hostmasterzone.com/how-to-unmarshal-soap-fault-in-spring-integration-web-service/
<bean id="hmzJaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPaths">
<list>
<value>org.hmz.request.types</value>
</list>
</property>
</bean>
<bean id="custJaxbUnMarshaller" class="com.jay.hmz.util.CustJaxbUnMarshaller" >
<property name="contextPaths">
<list>
<value>org.hmz.request.types</value>
</list>
</property>
</bean>
<int:chain input-channel="channel.in" output-channel="channel.out">
<int:transformer method="transformParentRequestById"><bean class="org.jay.hmz.api.transformers.OrderTransformer"/></int:transformer>
<int-ws:header-enricher><int-ws:soap-action value="${order.request.uri}"/></int-ws:header-enricher> <int-ws:outbound-gateway interceptors="hmzSecurityInterceptor" mapped-request-headers="GUID, USER_REF" request-callback="hmzWebServiceMessageCallback" unmarshaller="custJaxbUnMarshaller" marshaller="hmzJaxbMarshaller" uri="${order.request.uri}"/>
<int:transformer method="transformRetrieveParentOrderResponse"><bean class="org.jay.hmz.api.transformers.OrderTransformer"/></int:transformer>
</int:chain>
<int:service-activator input-channel="requestErrorChannel" output-channel="response.out" ref="requestErrorHandler" method="handleFailedOrderRequest"/>
<bean id="requestErrorHandler" class="org.jay.hmz.api.errorhandler.RequestErrorHandler"/>
public class CustJaxbUnMarshaller extends Jaxb2Marshaller {
#Override
public Object unmarshal(Source source, MimeContainer mimeContainer)
throws XmlMappingException {
LOGGER.debug("Inside Custom JaxbWrapper unmarshal");
Object mimeMessage = new DirectFieldAccessor(mimeContainer)
.getPropertyValue("mimeMessage");
Object unmarshalObject = null;
if (mimeMessage instanceof SaajSoapMessage) {
SaajSoapMessage soapMessage = (SaajSoapMessage) mimeMessage;
String faultReason = soapMessage.getFaultReason();
if (faultReason != null) {
throw convertJaxbException(new JAXBException(faultReason));
} else {
unmarshalObject = super.unmarshal(source, mimeContainer);
}
}
return unmarshalObject;
}
}
I created a file upload service using Spring MVC with apache commons multipart resolver support which specifies that a file should be attached as part of a multipart HTTP Post request. The request also contains a parameter containing an XML string with meta-data about the object. The XML can be marshalled using JAXB.
Other services that are not multipart handle the marshalling transparently, e.g.:
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public ModelAndView createUser(#RequestBody CreateUserDTO createUserDTO) throws Exception {
UserDTO user = userService.createUser(createUserDTO);
return createModelAndView(user);
}
Here CreateUserDTO is a JAXB annotated object which is automatically marshalled.
In the multipart case I'd like to have the same transparency. Ideally I would like to do the following:
RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public ModelAndView createAttachment(#RequestParam AttachmentDTO attachment,
HttpServletRequest request) throws Exception {
final MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
AttachmentDTO attachment = null;
final MultipartFile dataFile = multipartRequest.getFile("data");
AttachmentDTO createdAttachment = attachmentService.createAttachment(attachment,
dataFile);
return createModelAndView(createdAttachment);
}
Unfortunately this does not work. I am able to bind the attachment parameter as String, but the automatic marshalling does not work. My work around is to manually do the marshalling like the following, but I don't like this approach (especially since the parameter may be specified both in JSON and XML form):
#Autowired
private Jaxb2Marshaller jaxb2Marshaller;
#Autowired
private ObjectMapper jacksonMapper;
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public ModelAndView createAttachment(#RequestParam(ATTACHMENT_PARAMETER) String attachmentString,
final HttpServletRequest request) throws Exception {
final MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
AttachmentDTO attachment = null;
try {
attachment = (AttachmentDTO)jaxb2Marshaller.unmarshal(new StreamSource(new StringReader(attachmentString)));
} catch (XmlMappingException e) {
//Try JSON
try {
attachment = jacksonMapper.readValue(attachmentString, AttachmentDTO.class);
} catch (IOException e1) {
throw new BadRequestException("Could not interpret attachment parameter, both JSON and XML parsing failed");
}
}
Does anyone have a better suggestion for resolving this issue?
For completeness I also specify the relevant Spring config here:
<bean id="viewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1"/>
<property name="favorPathExtension" value="true"/>
<property name="ignoreAcceptHeader" value="false"/>
<property name="mediaTypes">
<map>
<entry key="xml" value="application/xml"/>
<entry key="json" value="application/json"/>
</map>
</property>
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="modelKey" value="object"/>
<property name="marshaller" ref="jaxbMarshaller"/>
</bean>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="objectMapper" ref="jaxbJacksonObjectMapper"/>
</bean>
</list>
</property>
</bean>
<!--Use JAXB OXM marshaller to marshall/unmarshall following class-->
<bean id="jaxbMarshaller"
class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPath" value="com.behindmedia.btfd.model.dto"/>
</bean>
<bean id="jaxbJacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper"/>
<!-- allows for integration of file upload functionality -->
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
<property name="maxUploadSize" value="100000000"/>
</bean>
I would just like to ask how can i setup a simple mail server and be able to send an email. Im using apache tomcat 6.0 as my localhost server and spring framework+jsp as well. I'm quite new on this. So if someone can give a nice tutorial, it will be of great help. thanks
Below is how you would get the spring configuration. probably applicationContext-mail.xml. Import that into applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"autowire="byName">
default-autowire="byName">
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${mail.host}" />
<property name="port" value="${mail.port}" />
<property name="username" value="${mail.username}" />
<property name="password" value="${mail.password}" />
</bean>
<bean id="freemarkerConfiguration"
class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean">
<property name="templateLoaderPath" value="/WEB-INF/templates" />
</bean>
<!-- KINDLY MAINTAIN ALPHABETICAL ORDER THIS LINE ONWARDS -->
<bean id="notificationService" class="com.isavera.service.NotificationServiceImpl"
scope="prototype">
<property name="mailSender" ref="mailSender" />
<property name="freemarkerConfiguration" ref="freemarkerConfiguration" />
<property name="freemarkerTemplate" value="accountInformation.ftl" />
<property name="fromAddress" value="info#apnagenie.com" />
<property name="subject" value="Your account information" />
</bean>
Below is the NotificationServiceImpl
public class NotificationServiceImpl implements NotificationService, Runnable {
private boolean asynchronous = true;
private JavaMailSender mailSender;
private Configuration freemarkerConfiguration;
private String freemarkerTemplate;
private Map<String, Object> attributes;
private String deliveryAddress;
private String[] deliveryAddresses;
private String fromAddress;
private String subject;
private SimpleMailMessage message;
private MimeMessage mimeMessage;
public void deliver() {
message = new SimpleMailMessage();
if (getDeliveryAddresses() == null) {
message.setTo(getDeliveryAddress());
} else {
message.setTo(getDeliveryAddresses());
}
message.setSubject(subject);
message.setFrom(fromAddress);
// Merge the model into the template
final String result;
try {
result = FreeMarkerTemplateUtils.processTemplateIntoString(freemarkerConfiguration.getTemplate(appendApplicationName(freemarkerTemplate)), attributes);
message.setText(result);
if (asynchronous) {
Thread emailThread = new Thread(this);
emailThread.start();
} else {
run();
}
} catch (IOException e) {
e.printStackTrace();
} catch (TemplateException e) {
e.printStackTrace();
}
}
}
I have updated my libraries, and now e-mails are sent without subject. I don't know where this happened...
Mail API is 1.4.3., Spring 2.5.6. and Spring Integration Mail 1.0.3.RELEASE.
<!-- Definitions for SMTP server -->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${mail.host}" />
<property name="username" value="${mail.username}" />
<property name="password" value="${mail.password}" />
</bean>
<bean id="adminMailTemplate" class="org.springframework.mail.SimpleMailMessage" >
<property name="from" value="${mail.admin.from}" />
<property name="to" value="${mail.admin.to}" />
<property name="cc">
<list>
<value>${mail.admin.cc1}</value>
</list>
</property>
</bean>
<!-- Mail service definition -->
<bean id="mailService" class="net.bbb.core.service.impl.MailServiceImpl">
<property name="sender" ref="mailSender"/>
<property name="mail" ref="adminMailTemplate"/>
</bean>
And properties mail.host,mail.username,mail.password,mail.admin.from,mail.admin.to,
mail.admin.cc1.
Java class:
/** The sender. */
private MailSender sender;
/** The mail. */
private SimpleMailMessage mail;
public void sendMail() {
this.mail.setSubject("Subject");
this.mail.setText("msg body");
try {
getSender().send(this.mail);
} catch (MailException e) {
log.error("Error sending mail!",e);
}
}
public SimpleMailMessage getMail() {
return this.mail;
}
public void setMail(SimpleMailMessage mail) {
this.mail = mail;
}
public MailSender getSender() {
return this.sender;
}
public void setSender(MailSender mailSender1) {
this.sender = mailSender1;
}
Everything worked before, I am wondering if there may be any conflicts with new libraries.
Finally - I had the time to resolve this.
In pom.xml, I have added java mail dependency and remove exclusion for geronimo javamail in apache axis transport http dependency.
I expect it's something to do with the way that you're injecting a singleton SimpleMailMessage into your bean. This is not thread-safe, since every call to your sendMail method will be using the same underlying SimpleMailmessage object. It's quite possible that some implementation change in the new libraries now means this is broken.
SimpleMailMessage has a copy constructor, so you should do it like this:
<bean id="mailService" class="net.bbb.core.service.impl.MailServiceImpl">
<property name="sender" ref="mailSender"/>
<property name="template" ref="adminMailTemplate"/>
</bean>
and
private SimpleMailMessage template;
public void setTemplate(SimpleMailMessage template) {
this.template = template;
}
public void sendMail() {
SimpleMailMessage message = new SimpleMailMessage(template);
message.setSubject("Subject");
message.setText("msg body");
try {
getSender().send(message);
} catch (MailException e) {
log.error("Error sending mail!",e);
}
}