list+org.o...@io7m.com a écrit le 07/08/2016 14:01 : > Hello. Hi,
> As a learning exercise, I've put together a very contrived example of a > "reverse" service (like an echo service, except that each returned line > comes back reversed). Mostly, I'm using it as a learning example of how > to build a small TCP/IP client/server in OSGi. You hit a limitation in DS, and a very common one because often components might need to run blocking code (e.g some SQL queries to make sure a database is ready/with the right model) and make sure the services it provides are not exposed before that. It is indeed part of the spec that a component should avoid blocking in activate/deactivate callbacks: a DS implementation might actually skip and/or blacklist a component that takes too much time to activate or deactivate. Felix SCR does it, and we have run into this before. A bad workaround for us was to increase the time limit in SCR, which can be set using a framework property. A better workaround is not to block at all, but avoid using DS for these blocking calls. You can for instance define a DatabaseReady or TCPServerReady service and have it as a reference in your DS component. You then go on to programatically register that service. Your problem with port reuse would remain, because activate() can be called before an async task called by deactivate() has finished. A solution would be to make sure the same thread is reused for all TCPServer binding and closing. You then have a Setup DS component (it could be in the activator as well, but would make it difficult to depend on other services): @Component public final class TCPSetup { private BundleContext context; private ServiceRegistration reg; private TCPServer tcpServer; @Reference private TCPServerManager srvManager; @Activate public void activate(BundleContext context) { this.context = context; Promise<TCPServer> tcpServerPms = srvManager.newServer(port); tcpServerPms.onResolve(() -> register(tcpServerPms.getValue())); } @Deactivate public void deactivate() { if (tcpServer != null) { Promise<Void> tcpServerClosed = srvManager .close(tcpServer); tcpServerClosed.onResolve(() -> reg.unregister()); } tcpServer = null; } public void register(TCPServer tcpServer) { this.tcpServer = tcpServer; // blocking code. reg = context.registerService(TCPServer.class, tcpServer, null); // this thread will potentially activate components depending // on the service. } } TCPServerManager holds a single thread executor that is used for creating TCPServer instances. This way, whatever happens with the lifecycle of your components, you are sure the bind/close method runs sequentially. There might still be a problem with the sequence close / restart manager component / bind, but you get the kind of trickery required to deal with these issues... Ideally, TCPServerManager's thread dealing with binding/closing sockets should not be held statically, but it's a bit tricky to deal with the restarting of TCPServerManager instances otherwise. You'll notice I use the OSGi Promise API rather than callbacks in my example. It's similar, but I suggest you explore it (if you haven't done so yet) in your experiments because it gets very handy when dealing with state, IO and blocking code. Things would be much better if DS provided adequate support, for instance for controlling whether we expose or not services (using the component context). Other OSGi component frameworks provide this, so I hope this will eventually get included in DS 1.4. Hope this helps, Simon _______________________________________________ OSGi Developer Mail List osgi-dev@mail.osgi.org https://mail.osgi.org/mailman/listinfo/osgi-dev