Hi Daniel,

 thanks for your reply.

  If I look for the string "policy" inside the wsdl, I find nothing, so I
guess no security policy is defined in the WSDL right ?
(if you want to have a look:
https://docs.tibco.com/pub//activematrix_bpm/2.1.0_february_2013/doc/html/BPM%20Developers%20Guide/public_api/public_api.zip)

  For support consideration, I can't modify the WSDL.

  For now, I've been able to convert the Client initialization to a spring
configuration (see below) and it works as expected for a single user.


Do you think it is possible to set dynamically username & password from
this kind of configuration, or it's hopeless?
If you can point me to some sample, would help a lot.
If I remember well, I've been told that it's possible to implement an
interceptor to set the username. (any doc ?  which interface to implement ?)
And also, would it be thread safe?


Regards,
Thomas.








<?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:jaxws=*
"http://cxf.apache.org/jaxws"*



       xmlns:cxf=*"http://cxf.apache.org/core"* xmlns:p=*"
http://cxf.apache.org/policy"*



       xsi:schemaLocation=*"*

*      http://www.springframework.org/schema/beans*

*      http://www.springframework.org/schema/beans/spring-beans-2.0.xsd*

*      http://cxf.apache.org/jaxws*

*      http://cxf.apache.org/schemas/jaxws.xsd*

*      http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd*

*      "*>







       <cxf:bus>

              <cxf:features>

                      <p:policies />

                      <cxf:logging />

              </cxf:features>

       </cxf:bus>



       <bean class=*"org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor"*

              id=*"outbound-security"*>

              <constructor-arg>

                      <map>

                             <entry key=*"action"* value=*"UsernameToken"*
/>

                             <entry key=*"user"* value=*"tibco-admin"* />

                             <entry key=*"passwordType"* value=*
"PasswordText"* />

                             <entry key=*"passwordCallbackClass"*

                                    value=*
"com.tibco.cts.amxbpm.fwk.security.PasswordCallbackHandler"* />

                      </map>

              </constructor-arg>

       </bean>











       <jaxws:client id=*"WorkListServiceProxyFactory"*

              name=*"{http://services.brm.n2.tibco.com}WorkListService_EP"*

              serviceClass=*"com.tibco.n2.brm.services.WorkListService"*
address=*"http://192.168.2.213:8080/amxbpm/WorkListService"*>



              <jaxws:outInterceptors>

                      <ref bean=*"outbound-security"* />

              </jaxws:outInterceptors>



       </jaxws:client>







On Tue, Oct 15, 2013 at 4:39 PM, Daniel Kulp <[email protected]> wrote:

>
> >
> >  <jaxws:client id="WorkListServiceProxyFactory"
> >
> >    name="{http://services.brm.n2.tibco.com}WorkListService_EP";
> >
> >    serviceClass="com.tibco.n2.brm.services.WorkListService" address="
> > http://192.168.2.213:8080/amxbpm/WorkListService";>
> >
> >
> >    <jaxws:properties>
> >
> >
> >      <entry key="ws-security.username" value="tibco-admin" />
> >
> >      <entry key="ws-security.callback-handler"
> >
> >        value=
> >
> "com.mansonthomas.amxbpm.customwebapp.services.amxbpm.security.PasswordCallbackHandler"
> > />
> >
> >    </jaxws:properties>
> >
> >  </jaxws:client>
> >
> > </beans>
> >
> > and no soap headers:
>
>
> This configuration will ONLY work if your WSDL contains a ws-security
> policy fragment that defines a username token policy in it.   In addition,
> you would NEED to add a wsdlLocation item onto the jaxws:client for the
> wsdl to be picked up.  Right now, with that configuration, it doesn't know
> to even apply any security stuff at all.
>
>
>
>
> Dan
>
>
>
>
>
> On Oct 15, 2013, at 5:17 AM, Thomas Manson <[email protected]>
> wrote:
>
> > Colm,
> >
> > honestly i'm really getting mad and sick of this security stuff.
> > I'm blocked on this for sooo long now  and don't work on the actual
> stuff I
> > should do.
> >
> > I was pushing CXF as I did had good experience on it before, but I'm now
> > considering to move to something else... I really need to get the thing
> > done, anyhow.
> >
> >
> >> If you have a WS-SecurityPolicy in operation
> > I don't understand this.
> > if you mean that the wsdl should contain some stuff, I don't think so,
> > maybe beacuse it allow username token, SAML (sendervoucher) and X509 and
> > that all samples I've tried do not work.
> >
> > the only actual code that did send the SOAP header is
> >
> > this code :
> >
> >
> ###############################################################################################
> >
> > JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
> >
> >    factory.setServiceClass(WorkListService.class);
> >
> >    factory.setAddress(this.endpoint);
> >
> >    //
> >
> factory.setWsdlLocation("D:/ARTIC/SOURCE/artic/trunk/webapp/src/main/webapp/WSDL/brm.wsdl");
> >
> >    factory.setServiceName(new QName("http://services.brm.n2.tibco.com";,
> > "WorkListService"));
> >
> >    this.workListService = (WorkListService) factory.create();
> >
> >
> >    Client client = ClientProxy.getClient(this.workListService);
> >
> >
> >    Map<String, Object> properties = new HashMap<String, Object>();
> >
> >    properties.put(WSHandlerConstants.ACTION          ,
> WSHandlerConstants.
> > USERNAME_TOKEN);
> >
> >    properties.put(WSHandlerConstants.USER            , this.username);
> >
> >    properties.put(WSHandlerConstants.PASSWORD_TYPE   ,
> WSConstants.PW_TEXT
> > );// "PasswordDigest"
> >
> >    properties.put(WSHandlerConstants.PW_CALLBACK_REF ,
> > newPasswordCallbackHandler(
> > "secret"));
> >
> >
> >    client.getOutInterceptors().add(new WSS4JOutInterceptor(properties));
> >
> >
> >    HTTPConduit conduit = (HTTPConduit) client.getConduit();
> >
> >
> >    long timeoutMillis = this.timeout * 1000;
> >
> >
> >    HTTPClientPolicy policy = new HTTPClientPolicy();
> >
> >    policy.setConnectionTimeout(timeoutMillis);
> >
> >    policy.setReceiveTimeout(timeoutMillis);
> >
> >
> >    conduit.setClient(policy);
> >
> ###############################################################################################
> >
> >
> > I'm just trying to get the basic thing to work :
> >
> > Configure the client with spring, inject it into another bean and use it
> > and even that do not work.
> >
> >
> > I'm just having the same spring code in all samples, I can't get why it
> > doesn't send the security headers.
> >
> >
> >
> >
> >
> >
> >
> > <?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:jaxws="
> > http://cxf.apache.org/jaxws";
> >
> >
> >  xmlns:cxf="http://cxf.apache.org/core"; xmlns:p="
> > http://cxf.apache.org/policy";
> >
> >
> >  xsi:schemaLocation="
> >
> >      http://www.springframework.org/schema/beans
> >
> >      http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
> >
> >      http://cxf.apache.org/jaxws
> >
> >      http://cxf.apache.org/schemas/jaxws.xsd
> >
> >      http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
> >
> >      ">
> >
> >
> >
> >
> >  <cxf:bus>
> >
> >    <cxf:features>
> >
> >      <p:policies />
> >
> >      <cxf:logging />
> >
> >    </cxf:features>
> >
> >  </cxf:bus>
> >
> >
> >
> >
> >  <jaxws:client id="WorkListServiceProxyFactory"
> >
> >    name="{http://services.brm.n2.tibco.com}WorkListService_EP";
> >
> >    serviceClass="com.tibco.n2.brm.services.WorkListService" address="
> > http://192.168.2.213:8080/amxbpm/WorkListService";>
> >
> >
> >    <jaxws:properties>
> >
> >
> >      <entry key="ws-security.username" value="tibco-admin" />
> >
> >      <entry key="ws-security.callback-handler"
> >
> >        value=
> >
> "com.mansonthomas.amxbpm.customwebapp.services.amxbpm.security.PasswordCallbackHandler"
> > />
> >
> >    </jaxws:properties>
> >
> >  </jaxws:client>
> >
> > </beans>
> >
> > and no soap headers:
> >
> >
> > INFO: Creating Service {http://services.brm.n2.tibco.com
> }WorkListServiceService
> > from class com.tibco.n2.brm.services.WorkListService
> >
> > oct. 15, 2013 10:52:41 AM
> >
> org.apache.cxf.services.WorkListServiceService.WorkListServicePort.WorkListService
> >
> > INFO: Outbound Message
> >
> > ---------------------------
> >
> > ID: 1
> >
> > Address: http://192.168.2.213:8080/amxbpm/WorkListService
> >
> > Encoding: UTF-8
> >
> > Http-Method: POST
> >
> > Content-Type: text/xml
> >
> > Headers: {Accept=[*/*], SOAPAction=["getWorkListItems"]}
> >
> > Payload: <soap:Envelope xmlns:soap="
> > http://schemas.xmlsoap.org/soap/envelope/
> "><soap:Body><ns2:getWorkListItems
> > xmlns:ns2="http://api.brm.n2.tibco.com"; xmlns:ns3="
> > http://exception.api.brm.n2.tibco.com"; xmlns:ns4="
> > http://exception.api.common.n2.tibco.com"; xmlns:ns5="
> > http://exception.api.de.n2.tibco.com"; xmlns:ns6="
> > http://www.tibco.com/XPD/ScriptDescriptor/"; startPosition="0"
> > numberOfItems="10" getTotalCount="true"><entityID entity-type="RESOURCE"
> > guid="tibco-admin"
> >
> model-version="-1"/><orderFilterCriteria/></ns2:getWorkListItems></soap:Body></soap:Envelope>
> >
> > --------------------------------------
> >
> > oct. 15, 2013 10:52:41 AM
> >
> org.apache.cxf.services.WorkListServiceService.WorkListServicePort.WorkListService
> >
> > INFO: Inbound Message
> >
> > ----------------------------
> >
> > ID: 1
> >
> > Response-Code: 500
> >
> > Encoding: UTF-8
> >
> > Content-Type: text/xml; charset=utf-8
> >
> > Headers: {Content-Length=[605], content-type=[text/xml; charset=utf-8],
> > Date=[Tue, 15 Oct 2013 14:50:18 GMT], Expires=[Thu, 01 Jan 1970 00:00:00
> > GMT],
> Set-Cookie=[JSESSIONID=eflukkvn7glfvw8s53n2228;Path=/amxbpm;HttpOnly]}
> >
> > Payload: <?xml version="1.0" encoding="UTF-8"?>
> >
> > <SOAP-ENV:Envelope
> > xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/
> "><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>Authentication
> > Failed. AuthNSAML20Principal set in Subject is null or
> >
> empty.</faultstring><faultactor>DefaultRole</faultactor><detail><tibco:myFaultDetail
> > xmlns:tibco="http://tibcouri/
> > ">com.tibco.amf.spline.api.context.SplineMessagingException:
> Authentication
> > Failed. AuthNSAML20Principal set in Subject is null or empty.
> >
> >
> </tibco:myFaultDetail></detail></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
> >
> > --------------------------------------
> >
> > 2013-10-15 10:52:41,915 - ERROR - localhost-startStop-1 (
> > WorkListServiceImpl4.java:81) - Error while getting worklistItems for
> > WorkListItemQuery [username=tibco-admin, userGUID=tibco-admin, start=0,
> > numberOfItems=10, filter=null, order=null]
> >
> > javax.xml.ws.soap.SOAPFaultException: Authentication Failed.
> > AuthNSAML20Principal set in Subject is null or empty.
> >
> > at
> org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:156)
> >
> > at com.sun.proxy.$Proxy57.getWorkListItems(Unknown Source)
> >
> >
> >
> >
> >
> >
> >
> >
> >
> > On Tue, Oct 15, 2013 at 11:04 AM, Colm O hEigeartaigh
> > <[email protected]>wrote:
> >
> >> If you have a WS-SecurityPolicy in operation, it will take care of
> adding
> >> the correct headers, once you supply it with the correct information
> >> (username, password, etc.). Please take a look at the
> ws-security-examples
> >> systests to see how it all works.
> >>
> >> Colm.
> >>
> >>
> >> On Mon, Oct 14, 2013 at 10:27 PM, Thomas Manson <
> >> [email protected]> wrote:
> >>
> >>> Hi Colm,
> >>>
> >>> I will resume work on this subject tomorrow.
> >>>
> >>> So I'm in a situation where there's no soap header setted, and the
> >>> spring configuraiton seems to be ignored (which would be quite logical
> as
> >>> we don't use it in the java code, just rebuiling all ourselves.)
> >>>
> >>> So how can I make sure the soap header is setted in my request? How
> can I
> >>> set the authentication type (username/password plain) ?
> >>>
> >>> Thanks,
> >>> Thomas.
> >>>
> >>>
> >>> On Mon, Oct 7, 2013 at 11:23 AM, Thomas Manson <
> >>> [email protected]> wrote:
> >>>
> >>>> Hi Colm,
> >>>>
> >>>> If I remove the <jaxws:client  element, it still work as before, so I
> >>>> guess this client xml declaration is not taken into account as we're
> just
> >>>> programmatically re-doing what the spring configuration does...
> >>>>
> >>>> As I stated earlier, I'm already in a spring context (J2EE Spring MVC
> >>>> application), that's why I don't understand the BusFactory need to be
> given
> >>>> the spring xml file.
> >>>>
> >>>> I've understood that while seeing that the endpoint was not taken into
> >>>> account (thanks to my Virtual machine that changes of IP each time I
> resume
> >>>> my mac).
> >>>>
> >>>> So I'll focus to make it work programmatically first, then figure out
> >>>> how to use the spring XML configurations files and finally try to use
> my
> >>>> own generated WS Client instead of generating it on the fly.
> >>>>
> >>>>
> >>>> For now, I'm still blocked on enabling a security policy on the client
> >>>> side programmatically.
> >>>> For instance, my password callback handler is not taken into account,
> >>>> as it's not called at all.
> >>>>
> >>>> (the method  public void handle(Callback[] callbacks)
> throwsIOException, UnsupportedCallbackException  is not called)
> >>>>
> >>>>
> >>>>  I programmatically specify it as follow (full code at the end of the
> >>>> mail):
> >>>>
> >>>> *this*.workListService = service.getPort(portQName, WorkListService.*
> >>>> class*);
> >>>>
> >>>> ((BindingProvider)*this*.workListService
> >>>>
> ).getRequestContext().put(BindingProvider.*ENDPOINT_ADDRESS_PROPERTY*, "
> >>>> http://192.168.2.213:8080/amxbpm/WorkListService";);
> >>>>
> >>>> //I've also tryed by just specificying a class name, but don't work
> >>>> either.
> >>>>
> >>>> PasswordCallbackHandler passwordCallbackHandler =
> *new*PasswordCallbackHandler(
> >>>> "secret");
> >>>> ((BindingProvider)*this*.workListService
> >>>> ).getRequestContext().put(SecurityConstants.*CALLBACK_HANDLER*,
> >>>> passwordCallbackHandler);
> >>>>
> >>>>
> >>>>
> >>>>
> >>>> In the CXF samples, it's done like this:
> >>>>
> >>>>  <jaxws:client name=*"{
> >>>>
> http://www.example.org/contract/DoubleIt}DoubleItPlaintextPrincipalPort";
> >>>> *
> >>>>                  createdFromAPI=*"true"*>
> >>>>       <jaxws:properties>
> >>>>           <entry key=*"ws-security.callback-handler"
> >>>> *
> >>>>                  value=*
> >>>> "org.apache.cxf.systest.ws.wssec10.client.UTPasswordCallback"*/>
> >>>>       </jaxws:properties>
> >>>>    </jaxws:client>
> >>>>
> >>>>
> >>>> So I wonder what I miss...
> >>>>
> >>>> Thomas.
> >>>>
> >>>>
> >>>> package com.mansonthomas.amxbpm.customwebapp.services.amxbpm;
> >>>>
> >>>> import java.net.URL;
> >>>> import java.util.ArrayList;
> >>>> import java.util.List;
> >>>>
> >>>> import javax.xml.namespace.QName;
> >>>> import javax.xml.transform.Source;
> >>>> import javax.xml.ws.BindingProvider;
> >>>> import javax.xml.ws.EndpointReference;
> >>>> import javax.xml.ws.Service;
> >>>> import javax.xml.ws.WebServiceFeature;
> >>>> import javax.xml.ws.wsaddressing.W3CEndpointReference;
> >>>> import javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder;
> >>>>
> >>>> import org.apache.commons.logging.Log;
> >>>> import org.apache.commons.logging.LogFactory;
> >>>> import org.apache.cxf.Bus;
> >>>> import org.apache.cxf.bus.spring.SpringBusFactory;
> >>>> import org.apache.cxf.endpoint.Client;
> >>>> import org.apache.cxf.ws.security.SecurityConstants;
> >>>> import org.springframework.beans.factory.InitializingBean;
> >>>>
> >>>> import com.mansonthomas.amxbpm.customwebapp.model.WorkItemFwk;
> >>>> import com.mansonthomas.amxbpm.customwebapp.model.WorkListItemQuery;
> >>>> import
> >>>>
> com.mansonthomas.amxbpm.customwebapp.services.amxbpm.context.ContextService;
> >>>> import
> >>>>
> com.mansonthomas.amxbpm.customwebapp.services.amxbpm.mapper.WorkItemMapper;
> >>>> import
> >>>>
> com.mansonthomas.amxbpm.customwebapp.services.amxbpm.security.PasswordCallbackHandler;
> >>>> import com.tibco.n2.brm.api.GetWorkListItems;
> >>>> import com.tibco.n2.brm.api.GetWorkListItemsResponse;
> >>>> import com.tibco.n2.brm.api.OrderFilterCriteria;
> >>>> import com.tibco.n2.brm.api.WorkItem;
> >>>> import com.tibco.n2.brm.services.WorkListService;
> >>>> import com.tibco.n2.common.organisation.api.OrganisationalEntityType;
> >>>> import com.tibco.n2.common.organisation.api.XmlModelEntityId;
> >>>>
> >>>> public class WorkListServiceImpl2 implements WorkListFwkService,
> >>>> InitializingBean
> >>>> {
> >>>>
> >>>>  private static final Log           logger       =
> >>>> LogFactory.getLog(WorkListServiceImpl2.class);
> >>>>
> >>>>
> >>>>
> >>>>  private WorkListService workListService = null;
> >>>>  private  ContextService contextService = null;
> >>>>
> >>>>  public WorkListServiceImpl2( ContextService contextService) throws
> >>>> Exception
> >>>>  {
> >>>>    this.contextService = contextService;
> >>>>
> >>>>    SpringBusFactory bf = new SpringBusFactory();
> >>>>    URL busFile =
> >>>> this.contextService.getResource("/WEB-INF/spring/webservices2.xml");
> >>>>
> >>>>    Bus bus = bf.createBus(busFile.toString());
> >>>>    SpringBusFactory.setDefaultBus(bus);
> >>>>    SpringBusFactory.setThreadDefaultBus(bus);
> >>>>
> >>>>    URL     wsdl      =
> >>>> this.contextService.getResource("/wsdl/brm.wsdl");
> >>>>
> >>>>    Service service   = Service.create(wsdl, new QName("
> >>>> http://services.brm.n2.tibco.com","WorkListService";));
> >>>>
> >>>>    QName   portQName = new QName("http://services.brm.n2.tibco.com";,
> >>>> "WorkListService_EP");
> >>>>
> >>>>    this.workListService = service.getPort(portQName,
> >>>> WorkListService.class);
> >>>>
> >>>>
> >>>>
> ((BindingProvider)this.workListService).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
> >>>> "http://192.168.2.213:8080/amxbpm/WorkListService";);
> >>>>
> >>>>    PasswordCallbackHandler passwordCallbackHandler = new
> >>>> PasswordCallbackHandler("secret");
> >>>>
> >>>>
> >>>>
> ((BindingProvider)this.workListService).getRequestContext().put(SecurityConstants.CALLBACK_HANDLER,
> >>>> passwordCallbackHandler);
> >>>>
> >>>>
> >>>>  }
> >>>>
> >>>>  public List<WorkItemFwk> getWorkListItems(String username,
> >>>> WorkListItemQuery workListItemQuery)
> >>>>  {
> >>>>    XmlModelEntityId entityId = new XmlModelEntityId();
> >>>>    entityId.setGuid(workListItemQuery.getUserGUID());
> >>>>    entityId.setEntityType(OrganisationalEntityType.RESOURCE);
> >>>>    entityId.setModelVersion(-1);
> >>>>
> >>>>    GetWorkListItems getWorkListItems = new GetWorkListItems();
> >>>>
> >>>>    getWorkListItems.setGetTotalCount       (true);
> >>>>    getWorkListItems.setEntityID            (entityId);
> >>>>    getWorkListItems.setStartPosition
> >>>> (workListItemQuery.getStart());
> >>>>    getWorkListItems.setNumberOfItems
> >>>> (workListItemQuery.getNumberOfItems());
> >>>>    getWorkListItems.setOrderFilterCriteria (new
> OrderFilterCriteria());
> >>>>
> >>>>    GetWorkListItemsResponse getWorkListItemsResponse = null;
> >>>>
> >>>>     try
> >>>>    {
> >>>>
> >>>>
> ((BindingProvider)this.workListService).getRequestContext().put("thread.local.request.context",
> >>>> "true");
> >>>>
> >>>>
> ((BindingProvider)this.workListService).getRequestContext().put(SecurityConstants.USERNAME,
> >>>> username);
> >>>>
> >>>>      getWorkListItemsResponse =
> >>>> this.workListService.getWorkListItems(getWorkListItems);
> >>>>    }
> >>>>    catch(Exception e)
> >>>>    {
> >>>>      logger.error("Error while getting worklistItems for
> >>>> "+workListItemQuery.toString(),e);
> >>>>    }
> >>>>
> >>>>
> >>>>
> >>>>    if(getWorkListItemsResponse == null)
> >>>>    {
> >>>>      logger.error("recieve a null response while getting worklistItems
> >>>> for "+workListItemQuery.toString());
> >>>>      return new ArrayList<WorkItemFwk>(0);
> >>>>    }
> >>>>
> >>>>    List<WorkItem>    workitems       =
> >>>> getWorkListItemsResponse.getWorkItems();
> >>>>    List<WorkItemFwk> workListItemFwk = new
> >>>> ArrayList<WorkItemFwk>(workitems.size());
> >>>>
> >>>>
> >>>>    int i = 0;
> >>>>    for (WorkItem workItem : workitems)
> >>>>    {
> >>>>      workListItemFwk.add(WorkItemMapper.map(workItem, i++));
> >>>>    }
> >>>>    return workListItemFwk;
> >>>>  }
> >>>>
> >>>>  @Override
> >>>>  public void afterPropertiesSet() throws Exception
> >>>>  {
> >>>>
> >>>>    WorkListItemQuery workListItemQuery = new WorkListItemQuery();
> >>>>
> >>>>    workListItemQuery.setStart(0l);
> >>>>    workListItemQuery.setNumberOfItems(10l);
> >>>>    workListItemQuery.setUsername("tibco-admin");
> >>>>    workListItemQuery.setUserGUID("tibco-admin");
> >>>>
> >>>>    this.getWorkListItems("tibc-admin", workListItemQuery);
> >>>>
> >>>>  }
> >>>>
> >>>> }
> >>>>
> >>>>
> >>>>
> >>>>
> >>>
> >>
> >>
> >> --
> >> Colm O hEigeartaigh
> >>
> >> Talend Community Coder
> >> http://coders.talend.com
> >>
>
> --
> Daniel Kulp
> [email protected] - http://dankulp.com/blog
> Talend Community Coder - http://coders.talend.com
>
>

Reply via email to