> On 14 Sep 2017, at 10:46, Guillaume Nodet <gno...@apache.org> wrote: > > > > 2017-09-14 11:40 GMT+02:00 Timothy Ward <tim.w...@paremus.com > <mailto:tim.w...@paremus.com>>: > Hi Alexander, > > As has been discussed on the Aries lists before, I have no problem with > someone creating a separate implementation of the Transaction Control service > which leverages the OSGi JTA Service Specification. The reason that the > current implementation doesn’t do this is twofold: > > By embedding a transaction manager the current Tx Control implementation can > avoid the javax.transaction split package from the JVM. This makes the > implementation easier to use and deploy because the user doesn’t need to mess > around with the boot class path, or worry about what JTA version is available > By embedding a transaction manager the current Tx control implementation can > rely on specific behaviours of the transaction manager that it uses. This > means that the Tx control implementation can support the last resource gambit > and XA recovery. > Fwiw, as I already indicated, the pax-transx project provides a layer solving > those problems, in addition of providing additional features and pluggability. > > Would you be interested to incorporate it in Tx Control ?
This is not something that I have the time to do, but another implementation of a transaction control service with a pluggable transaction manager would be a great addition. > > Guillaume > > > If this is a proof of concept project then are you able to share it somewhere > (e.g. GitHub)? I’d like to help you get to the bottom of the NPE that you’re > seeing as I don’t think it should be possible for that to be happening! > > Finally - yes the Aries user list is the best place to talk about this, but I > don’t want to move the conversation myself as I don’t know whether you’re > registered for that list, and don’t want you to miss my replies. > > Regards, > > Tim > > >> On 14 Sep 2017, at 07:53, <alexander.sah...@brodos.de >> <mailto:alexander.sah...@brodos.de>> <alexander.sah...@brodos.de >> <mailto:alexander.sah...@brodos.de>> wrote: >> >> Hi Tim. >> >> I'm using the 2.6.1 version of aries jpa support already. Normal transaction >> control with blueprint and @Transactional annotation was working fine. >> >> To have better control over startup dependencies and cope with disappearing >> and appearing services during runtime we invest some time in a >> Proof-Of-Concept for switching over to declarative services (DS). Everything >> works fine so far - even restful services for DS with cxf-dosgi works fine. >> Last bit to get it working is transaction management. With DS, the >> @Transactional annotation is not working anymore due to the lack of >> interceptors with DS. >> >> What do you think of the idea that tx-control should pick up a JTS >> Transaction manager from the service registry instead of creating an own one >> with new operator which is in fact tightly coupled. To implement loose >> coupling here we should add a factory that may be configurable in the >> factory config file. >> >> BTW, should we switch the discussion to aries group still? >> >> Best, Alexander. >> >> >> >> Hi Alexander, >> >> That looks like it should be fine - what version of Aries JPA are you using? >> There were some fixes made to Aries JPA in 2.4.0 to add support for JPA 2.1 >> configuration properties which are needed by the transaction control >> implementation, and I think that there were then more fixes in 2.5.0 which >> are needed to get XA working with Hibernate. 2.6.1 is the latest release >> version. >> >> Regards, >> >> Tim >> >> >>> On 13 Sep 2017, at 15:42, alexander.sah...@brodos.de >>> <mailto:alexander.sah...@brodos.de> wrote: >>> >>> Thanks Tim for the update. >>> >>> I tried the approach with providing a factory config in >>> karaf.dir/etc/org.apache.aries.tx.control.jpa.xa.cfg with config as: >>> osgi.unit.name <http://osgi.unit.name/>=DSContext2 >>> osgi.jdbc.driver.class=org.h2.Driver >>> url=jdbc:h2:mem:article >>> user=sa >>> password= >>> >>> whilst having a mininmal persistence.xml like: >>> <persistence-unit name="DSContext" > >>> <properties> >>> <property name="hibernate.dialect" >>> value="org.hibernate.dialect.H2Dialect" /> >>> </properties> >>> </persistence-unit> >>> >>> (without the dialect I see another exception; Access to >>> DialectResolutionInfo cannot be null when 'hibernate.dialect' not set). >>> >>> Now I get further in the process (transaction enlistment works) but when >>> actually accessing the database, the entity manager throws a NPE while >>> trying to open the connection. In >>> JPAEntityManagerProviderFactoryImpl.EnlistingDataSource.enlistedConnection() >>> while calling supplier.call, the supplier.delegate member is null: >>> >>> org.osgi.service.transaction.control.TransactionException: There was a >>> problem getting hold of a database connection >>> at >>> org.apache.aries.tx.control.jpa.xa.impl.JPAEntityManagerProviderFactoryImpl$EnlistingDataSource.enlistedConnection(JPAEntityManagerProviderFactoryImpl.java:241) >>> ~[?:?] >>> at >>> org.apache.aries.tx.control.jpa.xa.impl.JPAEntityManagerProviderFactoryImpl$EnlistingDataSource.getConnection(JPAEntityManagerProviderFactoryImpl.java:193) >>> ~[?:?] >>> at >>> org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) >>> ~[?:?] >>> at >>> org.hibernate.internal.NonContextualJdbcConnectionAccess.obtainConnection(NonContextualJdbcConnectionAccess.java:35) >>> ~[?:?] >>> at >>> org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:99) >>> ~[?:?] >>> at >>> org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:129) >>> ~[?:?] >>> at >>> org.hibernate.engine.jdbc.internal.StatementPreparerImpl.connection(StatementPreparerImpl.java:47) >>> ~[?:?] >>> at >>> org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:146) >>> ~[?:?] >>> at >>> org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:172) >>> ~[?:?] >>> at >>> org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:148) >>> ~[?:?] >>> at >>> org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1940) ~[?:?] >>> at >>> org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1909) ~[?:?] >>> at >>> org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1887) ~[?:?] >>> at org.hibernate.loader.Loader.doQuery(Loader.java:932) ~[?:?] >>> at >>> org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:349) >>> ~[?:?] >>> at org.hibernate.loader.Loader.doList(Loader.java:2615) ~[?:?] >>> at org.hibernate.loader.Loader.doList(Loader.java:2598) ~[?:?] >>> at >>> org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2430) ~[?:?] >>> at org.hibernate.loader.Loader.list(Loader.java:2425) ~[?:?] >>> at >>> org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:335) ~[?:?] >>> at >>> org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:2153) >>> ~[?:?] >>> at >>> org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:991) >>> ~[?:?] >>> at >>> org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:147) >>> ~[?:?] >>> at >>> org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1410) >>> ~[?:?] >>> at >>> org.hibernate.query.internal.AbstractProducedQuery.getSingleResult(AbstractProducedQuery.java:1459) >>> ~[?:?] >>> at >>> com.brodos.ds.persistence.h2.TestRepositoryImpl.lambda$checkHealth$0(TestRepositoryImpl.java:47) >>> ~[?:?] >>> at >>> org.apache.aries.tx.control.service.common.impl.AbstractTransactionControlImpl$TransactionBuilderImpl.doWork(AbstractTransactionControlImpl.java:161) >>> [241:tx-control-service-xa:0.0.3] >>> at >>> org.apache.aries.tx.control.service.common.impl.AbstractTransactionControlImpl$TransactionBuilderImpl.required(AbstractTransactionControlImpl.java:84) >>> [241:tx >>> <https://maps.google.com/?q=84)+%5B241:tx&entry=gmail&source=g>-control-service-xa:0.0.3] >>> at >>> org.apache.aries.tx.control.service.common.impl.AbstractTransactionControlImpl.required(AbstractTransactionControlImpl.java:263) >>> [241:tx-control-service-xa:0.0.3] >>> at >>> com.brodos.ds.persistence.h2.TestRepositoryImpl.checkHealth(TestRepositoryImpl.java:44) >>> [160:com.brodos.example.ds.DSContext-infrastructure:1.0.0.SNAPSHOT] >>> at >>> com.brodos.ds.service.impl.MainHealthCheck.checkHealth(MainHealthCheck.java:29) >>> [209:com.brodos.example.ds.DSContext-service:1.0.0.SNAPSHOT] >>> at >>> com.brodos.ds.application.boundary.impl.HealthCheckImpl.checkHealth(HealthCheckImpl.java:37) >>> [212:com.brodos.example.ds.DSContext-application:1.0.0.SNAPSHOT] >>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) >>> ~[?:?] >>> at >>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) >>> ~[?:?] >>> at >>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) >>> ~[?:?] >>> at java.lang.reflect.Method.invoke(Method.java:497) ~[?:?] >>> at >>> org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:180) >>> [84:org.apache.cxf.cxf-core:3.1.12] >>> at >>> org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96) >>> [84:org.apache.cxf.cxf-core:3.1.12] >>> at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:189) >>> [85:org.apache.cxf.cxf-rt-frontend-jaxrs:3.1.12] >>> at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:99) >>> [85:org.apache.cxf.cxf-rt-frontend-jaxrs:3.1.12] >>> at >>> org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:59) >>> [84:org.apache.cxf.cxf-core:3.1.12] >>> at >>> org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:96) >>> [84:org.apache.cxf.cxf-core:3.1.12] >>> at >>> org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) >>> [84:org.apache.cxf.cxf-core:3.1.12] >>> at >>> org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) >>> [84:org.apache.cxf.cxf-core:3.1.12] >>> at >>> org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:263) >>> [92:org.apache.cxf.cxf-rt-transports-http:3.1.12] >>> at >>> org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234) >>> [92:org.apache.cxf.cxf-rt-transports-http:3.1.12] >>> at >>> org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208) >>> [92:org.apache.cxf.cxf-rt-transports-http:3.1.12] >>> at >>> org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160) >>> [92:org.apache.cxf.cxf-rt-transports-http:3.1.12] >>> at >>> org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:189) >>> [92:org.apache.cxf.cxf-rt-transports-http:3.1.12] >>> at >>> org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:299) >>> [92:org.apache.cxf.cxf-rt-transports-http:3.1.12] >>> at >>> org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:223) >>> [92:org.apache.cxf.cxf-rt-transports-http:3.1.12] >>> at javax.servlet.http.HttpServlet.service(HttpServlet.java:687) >>> [69:javax.servlet-api:3.1.0] >>> at >>> org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:274) >>> [92:org.apache.cxf.cxf-rt-transports-http:3.1.12] >>> at >>> org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:845) >>> [128:org.eclipse.jetty.servlet:9.3.14.v20161028] >>> at >>> org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:584) >>> [128:org.eclipse.jetty.servlet:9.3.14.v20161028] >>> at >>> org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71) >>> [150:org.ops4j.pax.web.pax-web-jetty:6.0.6] >>> at >>> org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) >>> [127:org.eclipse.jetty.server:9.3.14.v20161028] >>> at >>> org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548) >>> [125:org.eclipse.jetty.security:9.3.14.v20161028] >>> at >>> org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:226) >>> [127:org.eclipse.jetty.server:9.3.14.v20161028] >>> at >>> org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1180) >>> [127:org.eclipse.jetty.server:9.3.14.v20161028] >>> at >>> org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:284) >>> [150:org.ops4j.pax.web.pax-web-jetty:6.0.6] >>> at >>> org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:512) >>> [128:org.eclipse.jetty.servlet:9.3.14.v20161028] >>> at >>> org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185) >>> [127:org.eclipse.jetty.server:9.3.14.v20161028] >>> at >>> org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1112) >>> [127:org.eclipse.jetty.server:9.3.14.v20161028] >>> at >>> org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) >>> [127:org.eclipse.jetty.server:9.3.14.v20161028] >>> at >>> org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:80) >>> [150:org.ops4j.pax.web.pax-web-jetty:6.0.6] >>> at >>> org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134) >>> [127:org.eclipse.jetty.server:9.3.14.v20161028] >>> at org.eclipse.jetty.server.Server.handle(Server.java:534) >>> [127:org.eclipse.jetty.server:9.3.14.v20161028] >>> at >>> org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:320) >>> [127:org.eclipse.jetty.server:9.3.14.v20161028] >>> at >>> org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251) >>> [127:org.eclipse.jetty.server:9.3.14.v20161028] >>> at org.eclipse.jetty.io >>> <http://org.eclipse.jetty.io/>.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:273) >>> [119:org.eclipse.jetty.io <http://org.eclipse.jetty.io/>:9.3.14.v20161028] >>> at org.eclipse.jetty.io >>> <http://org.eclipse.jetty.io/>.FillInterest.fillable(FillInterest.java:95) >>> [119:org.eclipse.jetty.io <http://org.eclipse.jetty.io/>:9.3.14.v20161028] >>> at org.eclipse.jetty.io >>> <http://org.eclipse.jetty.io/>.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:93) >>> [119:org.eclipse.jetty.io <http://org.eclipse.jetty.io/>:9.3.14.v20161028] >>> at >>> org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.executeProduceConsume(ExecuteProduceConsume.java:303) >>> [130:org.eclipse.jetty.util:9.3.14.v20161028] >>> at >>> org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceConsume(ExecuteProduceConsume.java:148) >>> [130:org.eclipse.jetty.util:9.3.14.v20161028] >>> at >>> org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:136) >>> [130:org.eclipse.jetty.util:9.3.14.v20161028] >>> at >>> org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:671) >>> [130:org.eclipse.jetty.util:9.3.14.v20161028] >>> at >>> org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:589) >>> [130:org.eclipse.jetty.util:9.3.14.v20161028] >>> at java.lang.Thread.run(Thread.java:745) [?:?] >>> Caused by: java.lang.NullPointerException >>> at >>> org.apache.aries.tx.control.jpa.xa.impl.JPAEntityManagerProviderFactoryImpl$EnlistingDataSource.lambda$getConnection$4(JPAEntityManagerProviderFactoryImpl.java:193) >>> ~[?:?] >>> at >>> org.apache.aries.tx.control.jpa.xa.impl.JPAEntityManagerProviderFactoryImpl$EnlistingDataSource.enlistedConnection(JPAEntityManagerProviderFactoryImpl.java:230) >>> ~[?:?] >>> ... 78 more >>> >>> Best, Alexander >>> >>> >>> >>> Hi Alexander, >>> >>> So what you’re doing is passing a fully configured EntityManagerFactory to >>> the resource provider factory. If you create the provider this way then you >>> are responsible for setting up all of the EntityManagerFactory’s >>> configuration, including how it’s going to integrate with transaction >>> control. For local transactions there is nothing to integrate with , but in >>> the general case this is actually quite hard to do, and I would advise not >>> trying to do it. >>> >>> As you can see the EntityManagerFactory version of the provider factory >>> <https://github.com/apache/aries/blob/ed8dbc79758766081203056cff27eb0bcbd7efb3/tx-control/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/JPAEntityManagerProviderFactoryImpl.java#L122> >>> does quite a bit less setup on your behalf than the configuration-driven >>> version does >>> <https://github.com/apache/aries/blob/ed8dbc79758766081203056cff27eb0bcbd7efb3/tx-control/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPAEMFLocator.java#L72>. >>> If you were to >>> provide a factory configuration for the >>> “org.apache.aries.tx.control.jpa.xa” pid containing “osgi.unit.name >>> <http://osgi.unit.name/>=<your persistence unit’s name>” and any necessary >>> datasource configuration (i.e. that’s not coming from the persistence xml) >>> then you could inject the JPAEntityManagerProvider directly as a service. >>> >>> More documentation about configuration-driven resources for Aries >>> Tx-Control is available at >>> http://aries.apache.org/modules/tx-control/xaJPA.html#creating-a-resource-using-a-factory-configuration >>> >>> <http://aries.apache.org/modules/tx-control/xaJPA.html#creating-a-resource-using-a-factory-configuration> >>> >>> Another thing that probably could be done would be to look at dynamically >>> installing the plugin when using the EntityManagerFactoryBuilder version of >>> the factory method. This, however, would need a patch to Aries Transaction >>> Control, and would still not make your existing code work. >>> >>> Regards, >>> >>> Tim >>> >>> >>>> On 13 Sep 2017, at 10:59, <alexander.sah...@brodos.de >>>> <mailto:alexander.sah...@brodos.de>> <alexander.sah...@brodos.de >>>> <mailto:alexander.sah...@brodos.de>> wrote: >>>> >>>> Hi Tim, >>>> >>>> I use a JPAEntityManagerProviderFactory (providerFactory) which I inject >>>> as a service reference into my repository class. >>>> Furthermore, I inject a EntityManagerFactory (emf) into the repository >>>> class as well as the TransactionControl (txControl). >>>> >>>> The provider Factory is created by pax-jdbc (I use hibernate). >>>> >>>> This provider factory is then used to get the Entity manager like this: >>>> >>>> EntityManager em = providerFactory.getProviderFor(emf, >>>> null).getResource(txControl); >>>> >>>> It fails giving an exception telling that transaction cannot be joined, >>>> because it's not open. >>>> >>>> The wrapping call is like this: >>>> txControl.build() >>>> .required( >>>> () -> repo.store(article)); >>>> >>>> Best, Alexander. >>>> >>>> >>>> >>>> Hi Alexander, >>>> >>>> Do you have a code example of how you’re obtaining and using the >>>> EntityManager? There should be no usage of the OSGiJtaPlatform from the >>>> tx-control XA JPA resource provider, which means that there’s either a bug >>>> in the resource provider, or something is misconfigured. If you are a >>>> member of the Aries user mailing list then that would be a better place to >>>> continue this discussion. >>>> >>>> Regards, >>>> >>>> Tim >>>> >>>>> On 13 Sep 2017, at 09:21, Guillaume Nodet <gno...@apache.org >>>>> <mailto:gno...@apache.org>> wrote: >>>>> >>>>> Fwiw, you should ask on the Aries mailing list, where tx-control is >>>>> developed. >>>>> >>>>> I've recently worked on a new project called pax-transx which provides an >>>>> abstraction layer on top of transaction managers so that some features >>>>> can be accessed in a common way. I think this should be used in >>>>> tx-control instead of wrapping the tm again and not being flexible. >>>>> Right now, tx-control uses its own instance of transaction manager and >>>>> there's no way around afaik, so you can't use the karaf transaction >>>>> feature if you want to use it. >>>>> Anyway, I'd gladly support you if you go to the aries mailing list to >>>>> raise this point ! >>>>> >>>>> 2017-09-13 9:52 GMT+02:00 <alexander.sah...@brodos.de >>>>> <mailto:alexander.sah...@brodos.de>>: >>>>> Hello. >>>>> >>>>> I'm trying to get tx-control with XA transactions running (local is >>>>> working). >>>>> I found that tx-control opens a JTA transaction using >>>>> RecoveryWorkAroundTransactionManager (derived from geronimo's >>>>> TransactionManager Implementation) explicitly instead of using the >>>>> registered TransactionManager (aries in my case for karaf 4.0.9). When >>>>> hibernate EntityManager implementation tries to join the transaction it >>>>> fails because it uses the TransactionManager provided by OsgiJtaPlatform >>>>> (from hibernate-osgi) which is of course the one registered in osgi >>>>> ecosystem. >>>>> >>>>> I think that the tx-control implementation has to use the >>>>> TransactionManager registered with OSGi. >>>>> >>>>> Has anyone got that thing ever running? >>>>> >>>>> Best Alexander. >>>>> >>>>> >>>>> >>>>> -- >>>>> ------------------------ >>>>> Guillaume Nodet >>>>> >>>> >>> >> > > > > > -- > ------------------------ > Guillaume Nodet