Home » Eclipse Projects » Eclipse Scout » [neon] Replacing proxied beans and service tunnel in Stubbed Client
[neon] Replacing proxied beans and service tunnel in Stubbed Client [message #1752062] |
Wed, 18 January 2017 12:32 |
Urs Beeli Messages: 573 Registered: October 2012 Location: Bern, Switzerland |
Senior Member |
|
|
In one of the applications that I am migrating from Mars to Neon the developers added the possibility of running the client in "stubbed mode". This mode is triggered by passing a specific system property when starting the client.
In addition to the Service-Interfaces (defined in shared) and their normal implementations (in server), this project also has stubbed implementations of all these services, that are not registered in the plugin.xml file but are manually registered to replace the serivce-proxies created by scout when the client is started. At the same time, the normal service tunnel is replaced with an empty implementation of the service tunnel interface. The stubbed service implementations then contain mocked functionality. They used this to be able to start the client without needing to start a server for fast and simple client development and testing.
I am now trying to migrate this "on the fly replacement" of the service proxies with the stubbed service implementations and am not sure how to do this correctly.
Here is a rough code skeletton of my setup, the service-classes already in their migrated (neon) form, the registration code still in the unmigrated (mars) form:
shared:
@ApplicationScoped
@TunnelToServer
public interface IMyService {
public MyDto someAction();
}
server:
public class MyService implements IMyService {
public MyDto someAction() {
return getDtoFromBackendOrEvenDatabase();
}
}
client:
public class MyServiceStub implements IMyService {
public MyDto someAction() {
// mock implementation without going to server
return new MyDtoBuilder().withValueA(a).withValueB(b).build();
}
}
public class MyClientSession extends AbstractClientSession {
@Override
public void execLoadSession() throws ProcessingException {
if (isClientOnlyMode()) {
registerStubbedServices();
} else {
super.execLoadSession();
}
}
//
// all code below has not yet been (fully) migrated to Neon
//
private void registerStubbedServices() throws ProcessingException {
Object[] stubedServices = StubbedServiceRegistry.getStubbedServices();
registerServices(getBundle(), 500, stubedServices); // I guess I can get rid of getBundle() here
setServiceTunnel(new StubbedServiceTunnel()); // how do I best replace the service tunnel bean?
setDesktop(new Desktop());
}
public static List<ServiceRegistration<?>> registerServices(Bundle bundle, int ranking, Object... services) {
ArrayList<ServiceRegistration<?>> result = new ArrayList<>();
Hashtable<String, Object> initParams = new Hashtable<>();
initParams.put(Constants.SERVICE_RANKING, ranking); // how do I dynamically set the ranking on my services when I register them?
for (Object service : services) {
ServiceRegistration<?> reg = bundle.getBundleContext().registerService(computeServiceNames(service), service, initParams); // I guess I do this using BEANS.getBeanManager().registerClass(), but how do I make sure no proxy is created or if it was already created, how do I replace it?
result.add(reg);
if (Proxy.isProxyClass(service.getClass())) {
// nop
} else if (service instanceof IService) {
((IService) service).initializeService(reg); // I guess I can just skip this, as the services no longer have this method by default
}
}
SERVICES.clearCache(); // is something similar needed on BEANS?
return result;
}
}
/**
* NOP service tunnel
*/
public final class StubbedServiceTunnel implements IClientServiceTunnel {
@Override
public void setServerURL(URL url) {
}
@Override
public Object invokeService(Class<?> serviceInterfaceClass, Method operation, Object[] args) throws ProcessingException {
return null;
}
@Override
public URL getServerURL() {
return null;
}
@Override
public void setClientNotificationPollInterval(long intervallMillis) {
}
@Override
public void setAnalyzeNetworkLatency(boolean b) {
}
@Override
public boolean isAnalyzeNetworkLatency() {
return false;
}
@Override
public long getClientNotificationPollInterval() {
return 0;
}
}
I've read up on Bean-Management but some questions still remain. In Mars the service proxies were created using the ClientProxyServiceFactory registered for each interface in the plugin.xml. How is this done in Neon? Or rather, how can I stop this from happening in stubbed mode? If I cannot stop it from happening, I see two possibilities:
- either I can register the stubbed service in addition to the service proxy, but then I must make sure that the stubbed service has a higher ranking/lower order than the proxy, how do I do that?
- or I can replace the proxy with the stubbed service. Using the @Replace annotation is probably not an option because in "standard mode" the proxy must not be replaced. There is BEANS.getBeanManager().unregisterClass/unregisterBean, but will this work for the proxies? If so, which argument do I need to use? The service interface? Or do I need to use the proxy class? If so, how do I get this class?
- or is there a more elegant way that I am missing?
Once I have solved this I should be able to also replace the normal service tunnel with my NOP-service tunnel implementation.
|
|
| | | |
Re: [neon] Replacing proxied beans and service tunnel in Stubbed Client [message #1752155 is a reply to message #1752130] |
Thu, 19 January 2017 09:50 |
Urs Beeli Messages: 573 Registered: October 2012 Location: Bern, Switzerland |
Senior Member |
|
|
OK, I've done some experimentation and there still are some issues.
ServiceTunnel
I *do* need to replace the service tunnel with a dummy implementation that has isActive() return false. If I don't do this, the ClientNotification mechanism tries to connect to the server which is not running and when I try to log in, the same happens and the login fails.
I am doing this during startup in the PlatformListener during the BeanManagerPrepared phase. I noticed that my dummy service tunnel *cannot* be an inner class, otherwise the bean manager cannot instantiate it.
public class MyPlattformListener implements IPlattformListener {
@Override
public void stateChanged(PlatformEvent event) {
if (event.getState() == State.BeanManagerPrepared) {
System.out.println("Registering stubbed service tunnel");
if (isClientOnlyMode()) {
BeanMetaData beanData = new BeanMetaData(StubbedServiceTunnel.class).withApplicationScoped(true).withOrder(500);
BEANS.getBeanManager().registerBean(beanData);
}
System.out.println("Stubbed service tunnel registered");
}
}
}
This let's me start the ui server without any error messages and the login mechanism works. However, for some strange reason this only works when launching the ui server using Tomcat (in that case I see the two sysouts telling me about registration of the stubbed tunnel *and* I also see the sysout I have placed in the constructor of the stubbed service tunnel). When launching my ui server using Jetyy I see the two sysouts telling me that the stubbed service tunnel was registered but I never see the constructor-sysout of the stubbed tunnel and then the application throws exceptions about "connection refused" both in the client notification mechanism as well as when trying to log in. [see quote at the very bottom]
--> is there any reason why the jetty based approach would not instantiate the stubbed tunnel that I am missing?
Replacing the services
As with the replacement of the service tunnel, I had to move the stubbing point from MyClientSession.execLoadSession() to the PlattformListener (if I didn't do that, BEANS.all() returned a list containing both the stubbed service *and* the proxy, BEANS.get() returned the proxy).
private void registerStubbedServices() throws ProcessingException {
Object[] services = StubbedServiceRegistry.getStubbedServices();
for (Object service : services) {
BeanMetaData beanData = new BeanMetaData(service.getClass()).withApplicationScoped(true).withOrder(500).withReplace(true);
BEANS.getBeanManager().registerBean(beanData);
}
}
So, for the time being it looks like the replacement works using tomcat but not jetty....
[quote name="Output when run in Jetty"][2017-01-19 10:37:03,758] [Thread-9] INFO org.eclipse.scout.rt.platform.inventory.ClassInventory <clinit> - Finished preparation of jandex class inventory in 1632.409027 ms
Registering stubbed service tunnel
Stubbed service tunnel registered
[2017-01-19 10:37:04,177] [Thread-9] INFO org.eclipse.scout.rt.platform.job.internal.DevelopmentThreadNameDecorator stateChanged - +++ Development thread name decoration
[2017-01-19 10:37:04,183] [Thread-9] INFO org.eclipse.scout.rt.platform.logger.LoggerPlatformListener registerLoggerSupportBean - registered logger support [org.eclipse.scout.rt.platform.logger.Log4jLoggerSupport]
[2017-01-19 10:37:04,206] [Thread-9] INFO org.eclipse.scout.rt.shared.services.common.code.CodeTypeRegistrator stateChanged - 29 code type classes registered.
[2017-01-19 10:37:04,243] [Thread-9] INFO org.eclipse.scout.rt.shared.servicetunnel.RegisterTunnelToServerPlatformListener registerTunnelToServerProxies - Tunnel to server proxies registered.
[2017-01-19 10:37:04,248] [Thread-9] INFO org.eclipse.scout.rt.shared.servicetunnel.http.MultiSessionCookieStoreInstaller install - Successfully installed java.net.CookieManager@43badb7c (Cookie store: org.eclipse.scout.rt.shared.servicetunnel.http.MultiSessionCookieStore@38a138e3)
[2017-01-19 10:37:04,348] [main] INFO org.eclipse.jetty.server.handler.ContextHandler doStart - Started o.e.s.d.j.P_WebAppContext@6500df86{/fos,file:/D:/dev/workspaces/cisi-neon/fos.scout.ui.html.dev/src/main/webapp/,AVAILABLE}
[2017-01-19 10:37:04,417] [main] INFO org.eclipse.jetty.server.ServerConnector doStart - Started ServerConnector@4abdb505{HTTP/1.1}{0.0.0.0:8083}
[2017-01-19 10:37:04,417] [main] INFO org.eclipse.jetty.server.Server doStart - Started @3179ms
[2017-01-19 10:37:04,423] [main] INFO org.eclipse.scout.dev.jetty.JettyServer start - Server ready. To run the application, open one of the following addresses in a web browser:
---------------------------------------------------------------------
http://localhost:8083/fos
http://k18270:8083/fos
http://192.168.56.1:8083/fos
---------------------------------------------------------------------
To shut the server down, type "shutdown" in the console.
[2017-01-19 10:37:05,341] [scout-thread-2 ClientNotificationPoller] ERROR org.eclipse.scout.rt.client.clientnotification.ClientNotificationPoller run - Error receiving client notifications
org.eclipse.scout.rt.platform.exception.PlatformException: Connection refused: connect [translator=org.eclipse.scout.rt.platform.exception.DefaultRuntimeExceptionTranslator, user=notification-authenticator, calling-thread=scout-thread-2 ClientNotificationPoller, job=Tunneling service request [seq=1, submitter=ClientNotificationPoller]]
at org.eclipse.scout.rt.platform.exception.DefaultRuntimeExceptionTranslator.translateInternal(DefaultRuntimeExceptionTranslator.java:54)
at org.eclipse.scout.rt.platform.exception.DefaultRuntimeExceptionTranslator.translate(DefaultRuntimeExceptionTranslator.java:37)
at org.eclipse.scout.rt.platform.exception.DefaultRuntimeExceptionTranslator.translate(DefaultRuntimeExceptionTranslator.java:1)
at org.eclipse.scout.rt.platform.job.internal.JobExceptionTranslator.translateExecutionException(JobExceptionTranslator.java:63)
at org.eclipse.scout.rt.platform.job.internal.JobFutureTask.awaitDoneAndGet(JobFutureTask.java:392)
at org.eclipse.scout.rt.platform.job.internal.JobFutureTask.awaitDoneAndGet(JobFutureTask.java:381)
at org.eclipse.scout.rt.shared.servicetunnel.http.HttpServiceTunnel.tunnel(HttpServiceTunnel.java:230)
at org.eclipse.scout.rt.shared.servicetunnel.AbstractServiceTunnel.invokeService(AbstractServiceTunnel.java:55)
at org.eclipse.scout.rt.shared.servicetunnel.AbstractServiceTunnel.invokeService(AbstractServiceTunnel.java:44)
at org.eclipse.scout.rt.shared.servicetunnel.http.HttpServiceTunnel.invokeService(HttpServiceTunnel.java:191)
at org.eclipse.scout.rt.shared.servicetunnel.ServiceTunnelProxyProducer.invoke(ServiceTunnelProxyProducer.java:43)
at org.eclipse.scout.rt.platform.interceptor.DecoratingProxy.invokeImpl(DecoratingProxy.java:134)
at org.eclipse.scout.rt.platform.interceptor.DecoratingProxy$P_InvocationHandler.invoke(DecoratingProxy.java:172)
at com.sun.proxy.$Proxy18.getNotifications(Unknown Source)
at org.eclipse.scout.rt.client.clientnotification.ClientNotificationPoller$P_NotificationPoller.run(ClientNotificationPoller.java:84)
at org.eclipse.scout.rt.platform.util.concurrent.Callables$1.call(Callables.java:37)
at org.eclipse.scout.rt.platform.util.concurrent.Callables$1.call(Callables.java:1)
at org.eclipse.scout.rt.platform.chain.callable.CallableChain$Chain.continueChain(CallableChain.java:185)
at org.eclipse.scout.rt.platform.job.internal.ExceptionProcessor.intercept(ExceptionProcessor.java:41)
at org.eclipse.scout.rt.platform.chain.callable.CallableChain$Chain.continueChain(CallableChain.java:180)
at org.eclipse.scout.rt.platform.context.RunContextRunner$1.call(RunContextRunner.java:42)
at org.eclipse.scout.rt.platform.chain.callable.CallableChain$Chain.continueChain(CallableChain.java:185)
at org.eclipse.scout.rt.platform.security.SubjectProcessor$1.run(SubjectProcessor.java:47)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:422)
at org.eclipse.scout.rt.platform.security.SubjectProcessor.intercept(SubjectProcessor.java:43)
at org.eclipse.scout.rt.platform.chain.callable.CallableChain$Chain.continueChain(CallableChain.java:180)
at org.eclipse.scout.rt.platform.chain.callable.CallableChain.call(CallableChain.java:135)
at org.eclipse.scout.rt.platform.context.RunContext.call(RunContext.java:121)
at org.eclipse.scout.rt.platform.context.RunContextRunner.intercept(RunContextRunner.java:38)
at org.eclipse.scout.rt.platform.chain.callable.CallableChain$Chain.continueChain(CallableChain.java:180)
at org.eclipse.scout.rt.platform.chain.callable.CallableChain.call(CallableChain.java:135)
at org.eclipse.scout.rt.platform.job.internal.JobFutureTask$1.call(JobFutureTask.java:100)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at org.eclipse.scout.rt.platform.job.internal.JobFutureTask.run(JobFutureTask.java:160)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
at org.eclipse.scout.rt.platform.job.internal.NamedThreadFactory$1.run(NamedThreadFactory.java:54)
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:345)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at java.net.Socket.connect(Socket.java:538)
at sun.net.NetworkClient.doConnect(NetworkClient.java:180)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:432)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:527)
at sun.net.www.http.HttpClient.<init>(HttpClient.java:211)
at sun.net.www.http.HttpClient.New(HttpClient.java:308)
at sun.net.www.http.HttpClient.New(HttpClient.java:326)
at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1168)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1104)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:998)
at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:932)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1282)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1257)
at org.eclipse.scout.rt.shared.servicetunnel.http.HttpServiceTunnel.createURLConnection(HttpServiceTunnel.java:114)
at org.eclipse.scout.rt.shared.servicetunnel.http.RemoteServiceInvocationCallable.call(RemoteServiceInvocationCallable.java:73)
at org.eclipse.scout.rt.shared.servicetunnel.http.RemoteServiceInvocationCallable.call(RemoteServiceInvocationCallable.java:1)
at org.eclipse.scout.rt.platform.chain.callable.CallableChain$Chain.continueChain(CallableChain.java:185)
at org.eclipse.scout.rt.platform.context.RunContextRunner$1.call(RunContextRunner.java:42)
at org.eclipse.scout.rt.platform.chain.callable.CallableChain$Chain.continueChain(CallableChain.java:185)
... 12 more
[/quote]
[Updated on: Thu, 19 January 2017 09:53] Report message to a moderator
|
|
|
Goto Forum:
Current Time: Fri Apr 26 09:01:28 GMT 2024
Powered by FUDForum. Page generated in 0.03240 seconds
|