Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java EE: Creating and deleting socket listeners dynamically from the domain model

I am creating a Java EE application that allows users to add/remove "socketinfo" tables (stored in a database) from a web interface. If the user enables a "socketinfo" from the web interface, the application server must create a socket listener for the incoming packets and process the data. If the user disables or deletes the "socketinfo" the socket listener must be removed. The entire product must be contained in a single ear, and preferrably compliant. Some approaches I have considered but ran into problems with are:

  1. Create a JCA resource adaptor for sockets and use MDBs as the listeners. The problem I ran into here was that I cannot figure out how to programmatically deploy MDBs for different sockets when the user adds them.

  2. Create a @Singleton/@Service ejb that manages the daemon threads with careful synchronization. The singleton ejb can be injected into the business layer so that CRUD operations and socket manipulation happen in the right workflow. The problem here was that supposedly creating threads from EJBs is considered a bad practice and is not spec compliant (even if the singleton life cycle is correctly handled and proper synchronization mechanisms are in place?).

  3. Put the threads in the domain model (another singleton?) and have the EJBs use the model. This was the worst of all of them since application servers tend to have multiple classloaders, less container support in general, plus this suffers from everything 2. suffers from.

Any idea how to correctly handle this situation in Java EE?

EDIT: An extension to this question: Assuming I decide to approach this problem like ewernli suggests in his solution 3, what do I gain by doing this in JCA (with a custom interface to add internal threads) that I would not get from a (well-designed) singleton? While creating a resource adapter does not look like a monstrous task, it does not seem entirely trivial and could be a little time consuming (and maybe even harder to follow for other developers).

like image 273
insipid Avatar asked Nov 05 '22 21:11

insipid


1 Answers

Your analysis seems reasonable, and you're right when you say that you can not deploy MDB dynamically to fit with JCA.

Few more design ideas:

  • You could write a JCA connector that returns SocketConnections (in the spirit of JMS), that you could use to read from a socket. To continue with the JMS analogy, MDB represent MessageListener, while what you would expose is MessageConsumer.

  • You could use a periodic timer to simulate a thread. Instead of a thread with a while loop, you have a timer that rescheduled itself. I used that for one app to have a background process, and that worked fine. Note that I also spawned threads right from EJBs to do some concurrent computation in another app, and that worked fine as well. But the threads where short-lived and the business method in the bean would wait until the all complete, so that was not a major violation of the spec.

  • Yet another design would to have the JCA connector handle threads, etc. and deliver all messages to MDB. The MDB would receive the data, along with information about the "channel" the data correspond to, e.g. the Socket port. It's like multiplexing all in one MDB, that then demultiplexes the data. Your connector can provide extra API to control the creation of threads, etc, and this interface could be injected in your EJB (similar to ConnectionFactory). Your connector can provide extra API to control the creation of threads, etc. Not crystal clear, but I hope you get the idea. If I'm right, the JCA connector can make sure to deliver the data synchronously to MDB, at least per socket, so that MDB process the data in the righ order.

I would go for #3, if development time permits.

EDIT

This choice is indeed partly a question of design purity. One problem though with user-spawened threads is that you can obviously not use declarative transactions for them. You can maybe use a UserTransaction to demarcate transaction yourself though. I don't know how well you can use an EntityManager also in such thread. If you mostly process data and don't use much features of the middleware, you can spwawn threads yourself. See another answer of me: How can an EJB parallelize a long, CPU intensive process?. Other things that comes to my mind (don't know whether they are problematic or not): security manager might prevent creating thread (?), not creating them as deamon threads might prevent the app. server from properly shut down (?). Note that I spawned threads from ServeletContextListener at startup and that worked just nice. This is a trick employed frequently even if it violates the spec. The same might become true for "newly" introduced singleton beans. So, if you are short on time you can of course try your proposition with a singleton bean and see what works/doesn't.

like image 159
ewernli Avatar answered Nov 12 '22 15:11

ewernli