These are my notes I took before taking the
Enterprise Integration with Spring Certification exam.
I passed the exam. At the second attempt, after actually taking those notes. The fist attempt was after 1-2 weeks of preparation and it was unnecessarily rushed (I knew it’s too early, if you think it’s too early it’s probably too early), The most difficult thing in preparation for this exam was keeping all those different new things separate in my head and not mixing them up. As soon as I knew where I am in the imaginary table of contents, everything was clear. What helped in organising the knowledge was reading
this book.
There is some overlap of this exam with the first Spring Core exam. There is also some stuff that logically would belong to Spring Integration but is actually not part of the exam - the amount of material is simply too big to squeeze everything. That is why it is essential to read the official study guide and study according to it. Or to my notes below (which follow the guide) :P
Server side | Client side | |
RMI |
<bean class="RmiServiceExporter">
<p:service-name value="myServiceNameInRegistry"/>
<p:service-interface value="...TheService"/>
<p:service ref="myService"/>
<p:registry-port="1099"/>
</bean>
|
<bean id, class="RmiProxyFactoryBean">
<p:service-interface value="myService"/>
<p:service-url value="rmi://foo:1099/myServiceName
InRegistry"/> </bean>
|
Http
Invoker |
<bean name="/transfer" class="HttpInvokerServiceExporter">
<p:service-interface value="...TheService"/>
<p:service ref="myService"/>
</bean>
+ DispatcherServlet or HttpRequestHandlerServlet with name ”transfer”
|
<bean id, class="HttpInvokerProxyFactoryBean">
<p:service-interface value="myService"/>
<p:service-url value="rmi://foo:8080/services/transfer"/>
</bean>
|
Hessian / Burlap
|
same as above, replace “HttpInvoker” with “Hessian” / “Burlap”
|
SOAP / POX (Spring WS)
|
||
web.xml
|
<servlet>
<servlet-name>si-ws-gateway</servlet-name>
<servlet-class>
MessageDispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>si-ws-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>si-ws-gateway</servlet-name>
<url-pattern>/quoteservice</url-pattern>
</servlet-mapping>
* also add contextConfigLocation as context-param and ContextLoaderListener for app context
|
|
web infrastr. config
|
<bean class="....UriEndpointMapping">
<p:name="defaultEndpoint" ref="ws-inbound-gateway"/>
</bean>
|
|
app config
|
<context:component-scan base-package=”transfers.ws”/>
<ws:annotation-driven/>
|
|
Endpoint implementation
|
@Endpoint
public class TransferServiceEndpoint {
...
public @ResponsePayload TransferResponse newTransfer(@RequestPayload TransferRequest request){
...
}
}
|
<int-ws:inbound-gateway id="ws-inbound-gateway"
request-channel="ws-requests"
extract-payload="false"
[marshaller/unmarshaller=”jaxb2”]/>
<oxm:jaxb2-marshaller
id=”marshaller”
contextPath=”reward.ws.types:someotherpackage”/>
, or just simply
<ws:annotation-driven/> <!-- registers all infrastructure beans needed for annotation-based endpoints, like JAXB2 (un)marshalling-->
<SOAP-ENV::Header>
...
<wsa:To S:mustUnderstand="true">http://example/com/fabrikam</wsa:To>
<wsa:Action>http://example.com/fabrikam/mail/Delete</wsa:Action>
</SOAP-ENV:Header>
@Action("http://samples/RequestOrder")
public Order getOrder(OrderRequest orderRequest) {
return orderService.getOrder(orderRequest.getId());
}
@PayloadRoot(localPart = "orderRequest", namespace = "http://samples")
@Namespace(prefix = "s", uri="http://samples")
public Order getOrder(@XPathParam("/s:orderRequest/@id") int orderId) {
Order order = orderService.getOrder(orderId);
// create Source from order and return it
}
<bean class=”...WebServiceTemplate”>
<property name=”defaultUri” value=”http://mybank.com/transfer”/>
<property name=”marshaller” ref=”marshallerAndUnmarshaller”/>
<property name=”unmarshaller” ref=”marshallerAndUnmarshaller”/>
<property name=”faultMessageResolver” ref=”myCustomFaultMessageResolver”/>
</bean>
<bean id=”marshallerAndUnmarshaller” class=”...CastorMarshaller”>
<property name=”mappingLocation” value=”classpath:castor-mapping.xml”/>
</bean>
template.marshallSendAndReceive(new TransferRequest(“S123”));
template.sendSourceAndReceiveToResult(source, result);
full definition, e.g.:
doSendAndReceive(MessageContext messageContext, WebServiceConnection connection, WebServiceMessageCallback requestCallback, WebServiceMessageExtractor<T> responseExtractor)
<ws:interceptors>
<bean class=”blabla.SoapEnvelopeLoggingInterceptor”
</ws:interceptors>
or
<ws:interceptors>
<ws:payloadRoot localPart=”MyRequest” namespaceUri=”htpp://blabla.com/namespace”>
<bean class=”blabla.SoapEnvelopeLoggingInterceptor”
</ws:payloadRoot>
</ws:interceptors>
client-side:
<bean class=”org...WebServiceTemplate”>
<property name=”interceptors”>
<bean class=”blablabalInterceptor”
</property>
</bean>
<bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="password" value="password"/>
<property name="location" value="classpath:org/springframework/ws/soap/security/xwss/test-keystore.jks"/>
</bean>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="keyStore" ref="keyStore"/>
<property name="privateKeyPassword" value="changeit"/>
</bean>
<bean id="wsSecurityInterceptor"
class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor">
<property name="policyConfiguration" value="classpath:securityPolicy.xml"/>
<property name="callbackHandlers">
<list>
<ref bean="keyStoreHandler"/>
<ref bean="...
</list>
</property>
</bean>
Method
|
Safe (no side effects)
|
Indepotent
|
Comments
|
GET
|
y
|
y
|
Is cacheable (ETag) or Last-Modified, 304
|
HEAD
|
y
|
y
|
|
POST
|
n
|
n
|
Location header in response
|
PUT
|
n
|
y
|
Create OR update
|
DELETE
|
n
|
y
|
SOAP / POX (Spring WS)
|
||
web.xml
|
<servlet>
<servlet-name>http-ws-gateway</servlet-name>
<servlet-class>HttpRequestHandlerServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param- name>
<param-value>http-ws-gateway.xml</param-value>
</servlet>
<servlet-mapping>
<servlet-name>http-ws-gateway</servlet-name>
<url-pattern>/httpquote</url-pattern>
</servlet-mapping>
|
|
web infrastr. config
|
<int-http:inbound-gateway
id="http-inbound-gateway"
request-channel="http-request"
reply-channel="http-response"
extract-reply-payload="false"
view-name="about"
reply-key, reply-timeout,message-converters,
supported-methods, convert-exceptions,
request-payload-type, error-code, errors-key,
header-mapper, name/>
|
|
app config
|
N/A
|
|
Endpoint implementation
|
@Controller
@RequestMapping(“/rewards”)
public class Blabla{
@RequestMapping(value=”/{number}”, method=GET)
public String Reward blabla(@RequestBody someObject / Model model, @PathVariable(“number”) String number){
// ...
// return view name
}
@RequestMapping(method=POST)
@ResponseStatus(HttpStatus.CREATED)
public @ResponseBody Reward blabla(@RequestBody someObject, HttpServletResponse res){
// ...
res.addHeader(“Location”, getMeUrl(order.getId()));
// return the object, will be mapped because of @ResponseBody, by converter based on Accept header
}
}
|
<int-http:outbound-gateway
url="http://blblah"
request-channel="requests"
http-method="GET"
expected-response-type="java.lang.String">
<int-http:uri-variable
name="location"
expression="payload"/>
</int:http:outbound-gateway>
<T> T getForObject(URIurl, Class<T>responseType) throws RestClientException; ← returns the object from GET
<T> T getForObject(Stringurl, Class<T>responseType, Object... uriVariables)throwsRestClientException;
<T> T getForObject(Stringurl, Class<T>responseType, Map<String, ?>uriVariables)throwsRestClientException;
<T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType)
throws RestClientException; ← returns the whole response from GET (with headers)
void put(String url, Object request, Object...uriVariables) throws RestClientException;
void delete(String url, Map<String, ?>uriVariables) throws RestClientException;
<T> T postForObject(String url,Object request,Class<T> responseType, Object… uriVariables) throws RestClientException;
<T> ResponseEntity <T> postForEntity(String url, Object request, Class<T> resType, Object...uriVariables)
throws RestClientException;
* URI url=response.getHeaders().getLocation(); ← to get location of the new resource!
<T> T execute()
<T> ResponseEntity <T> exchange(String url, HttpMethod method, HttpEntity<?> reqEntity, Class<T> resType, Object... uriVariables)
throws RestClientException;
Destination
|
<bean id=”orderQueue” class=”org.apache.activemq...ActiveMQQueue”>
<constructor-arg value=”queue.orders”/> </bean> |
<jee:jndi-lookup id=”orderQueue” jndi-name=”jms/OrderQueue”/>
|
|
ConnectionFactory
|
<bean id=”cf” class=”org.apache.activemq.ActiveMQConnectionFactory”>
<property name=”brokerURL” value=”tc[://localhost:61616”/> </bean> |
<jee:jndi lookup id=”cf” jndi-name=”jms/ConnectionFactory”/>
|
|
Connection
|
connectionFactory.createConnection();
|
Session
|
created from the Connection
|
JMS Message
|
created from Session
session.createProducer(destination);
|
MessageProducer
|
|
MessageConsumer
|
<jms:listener-container connection-factory=”cf”>
<jms:listener destination=”queue.orders”
ref=”myListener
(method=”order”)
(response-destination=”queue.confirmation”)/>
</jms:listener-container>
void convertAndSend([String/Destination d,] Object m)
void convertAndSend(Object m, MessagePostProcessor mpp) // to do stuff to the message after it has been converted
void send(MessageCreator mc) // is used inside convertAndSend()
Object execute(ProducerCallback<T> action)
Object execute(SessionCallback<T> action)
Message receive([String/Destination d,])
Object receiveAndConvert(destination)
<jms:listener-container acknowledge=”auto|client|dups_ok|transacted”/>
or
<jms:listener-container transaction-manager=”tm”/>
connection.createSession(transacted=true, acknowledgeMode);
session.commit();
session.rollback();
<bean class=”..JmsTemplate>
(<property name=”sessionAcknowledgeMode” value=”...”/>)
<property name=”sessionTransacted” value=”true”/>
</bean>
<jms:listener-container transaction-manager=”transactionManager” ../>
<tx:jta-transaction-manager/>
<jee:jndi-lookup id=”dataSource” jndi-name=”java:comp/env/jdbc/myDS”/>
<jee:jndi-lookup id=”connectionFactory” jndi-name=”java:comp/env/jdbc/myConnFac”/>
<bean id=”transactionManager” class=”org….JtaTransactionManager”>
<property name=”transactionManager” ref=”jtaTxMgr”/>
<property name=”userTransaction” ref=”userTx”/>
</bean>
<job id="resendUnprocessedDinings">
<step id="processConfirmationsStep" next="sendUnprocessedDiningsStep">
<tasklet>
<chunk reader="confirmationReader"
writer="confirmationUpdater"
commit-interval="${chunk.size}"
reader-transactional-queue="true"/>
</tasklet>
</step>
</job>
<bean id="itemReader" class="....FlatFileItemReader" scope="step">
<property name="resource" value="file://#{jobParameters['filena']}"/>
<property name="lineMapper">
<bean class="....DefaultLineMapper">
<property name="lineTokenizer">
<bean class="....DelimitedLineTokenizer">
<property name="names" value="source,dest,amount,date"/>
</bean>
</property>
<property name="fieldSetMapper" ref=”myMapper”/>
</bean>
</property>
</bean>
<bean id="itemWriter" class="....FlatFileItemWriter" scope="step">
<property name=”fieldSetCreator” ref=”customCreator”/>
...
</bean>
<batch:job-repository id=”jobRepository”/>
, or
<batch:job-repository
data-source="dataSource"
id="jobRepository"
transaction-manager="transactionManager"
table-prefix="BATCH_"/>
<bean id="jobLauncher" class="....SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository"/>
</bean>
JobParametersBuilder jpb = new JobParametersBuilder();
jpb.addString('filena', 'payment.xml');
JobExecution execution = jobLauncher.run(job, jpb.toJobParameters());
Date date = fs.readDate(0,"dd/MM/yyyy");
Long number = fs.readLong(1);
String value = fs.readString("city");
String[] values = fs.getValues();
public class MyMapper implements FieldSetMapper<Payment>{
@Override
public Payment mapFieldSet(FieldSet fieldSet)
throws BindException {
... = fieldSet.readString("source");
... = fieldSet.readBigDecimal("amount");
... = fieldSet.readDate("date");
}
}
Comments: