It's there in a few forms, but not as far as I'd like to see it go.
OpenEJB implements a lot of these things and Jeremy's bullets capture
why pretty well. I've chatted a lot about it with him and others at
Gluecode. I've been beating poor Hiram on the head with it forever.
It's essentially xinet.d, but in Java.
The idea is to have one consistent way of producing sockets which is
decoupled from the consumers of the sockets (e.g. the actual
protocols). Further, the EJBContainers themselves are not (at least
didn't used to be) dependent on any of the protocols, so you can add
addition implementations of protocols to the system without having to
change the container.
Despite it being in the org.openejb namespace, the code is already
generic. So what we have in OpenEJB and soon to move into ActiveIO
is this:
A Socket Producer: Contains a stack of QoSs for producing the socket,
essentially as interceptors that can be stacked up anyway you like.
Implemented now are:
- Simple thread-pool (not used since work manager support was added)
- Geronimo Work manager (e.g. better thread pool)
- Host Based Authorization (for example, saying only localhost
can use this IP:PORT)
- Request Logging (doesn't do much now)
To be implemented:
- SSL support
- Support for ActiveIO abstractions so more than just TCP/IP can
be used.
- Better request logger
To be integrated:
- Hiram's One-port functionality is high on the slate.
A Socket Consumer: The thing that actually reads/writes data from
the socket.
Implemented now are:
- EJBd (the custom OpenEJB ejb/jndi protocol)
- Telnet (a cheap telnet implementation I wrote)
- HTTP (a cheap HTTP implementation I wrote, Jetty's or Tomcat's
would be better)
- Admin (a small protocol to do administrative stuff with the
server like starting/stopping things)
Could be implemented:
- One to wrap jetty's stuff
- A network-based deployer
- An Admin protocol specifically for Geronimo
- Any code that allows you to pass in a socket could just be
wrapped and plugged in
- A VM-level Socket producer so "legacy" code could be supported
as well (code we don't control that insists on creating it's own
ServerSocket)
- A proxy to reroute calls to another IP:PORT
Right now in a plan you can, for example, have two producers for the
EJB protocol. One only for local traffic and one for internal traffic.
<!-- Public, smaller thread pool and restricted access to a set
of specific hosts -->
<gbean gbeanName="geronimo:type=NetworkService,name=EJB1"
class="org.openejb.server.StandardServiceStackGBean">
<attribute name="name">EJB</attribute>
<attribute name="port">2401</attribute>
<attribute name="host">209.237.227.195</attribute>
<attribute
name="allowHosts">209.98.98.9,207.171.163.90,216.239.39.99</attribute>
<attribute name="logOnSuccess">HOST,NAME,THREADID,USERID</
attribute>
<attribute name="logOnFailure">HOST,NAME</attribute>
<reference name="Executor"><name>DefaultThreadPool</name></
reference>
<reference name="Server"><gbean-
name>openejb:type=Server,name=EJB</gbean-name></reference>
</gbean>
<gbean name="DefaultThreadPool"
class="org.apache.geronimo.pool.ThreadPool">
<attribute name="keepAliveTime">5000</attribute>
<attribute name="poolSize">30</attribute>
<attribute name="poolName">DefaultThreadPool</attribute>
</gbean>
<!-- Private IP bound, bigger thread pool, access to just the
local subnet -->
<gbean gbeanName="geronimo:type=NetworkService,name=EJB2"
class="org.openejb.server.StandardServiceStackGBean">
<attribute name="name">EJB</attribute>
<attribute name="port">2402</attribute>
<attribute name="host">192.168.10.12</attribute>
<attribute name="allowHosts">255.255.255.0</attribute>
<attribute name="logOnSuccess">HOST,NAME,THREADID,USERID</
attribute>
<attribute name="logOnFailure">HOST,NAME</attribute>
<reference name="Executor"><name>HighThreadPool</name></
reference>
<reference name="Server"><gbean-
name>openejb:type=Server,name=EJB</gbean-name></reference>
</gbean>
<gbean name="HighThreadPool"
class="org.apache.geronimo.pool.ThreadPool">
<attribute name="keepAliveTime">1000</attribute>
<attribute name="poolSize">100</attribute>
<attribute name="poolName">HighThreadPool</attribute>
</gbean>
<gbean gbeanName="openejb:type=Server,name=EJB"
class="org.openejb.server.ejbd.EjbServerGBean">
<!-- blah blah blah -->
</gbean>
In this setup we have two different pools. It would be nice to use
the same pool for both, but partition them differently so we could
guarantee no one is dominating the pool.
The StandardServiceStackGBean is just one collection of QoSs. You
could create another gbean that had the ones you want or you could
declare them individually in a plan (a little hard to manage though).
<gbean
gbeanName="geronimo:type=NetworkService,interceptor=Daemon"
class="org.openejb.server.ServiceDaemon">
<attribute name="port">2402</attribute>
<attribute name="inetAddress">192.168.10.12</attribute>
<reference name="SocketService"><gbean-
name>geronimo:type=NetworkService,interceptor=Logger</gbean-name></
reference>
</gbean>
<gbean
gbeanName="geronimo:type=NetworkService,interceptor=Logger"
class="org.openejb.server.ServiceLogger">
<attribute name="logOnSuccess">HOST,THREADID</attribute>
<attribute name="logOnFailure">HOST</attribute>
<reference name="SocketService"><gbean-
name>geronimo:type=NetworkService,interceptor=AccessController</
gbean-name></reference>
</gbean>
<gbean gbeanName="geronimo:type=NetworkService,interceptor=Pool"
class="org.openejb.server.ServicePool">
<attribute name="keepAliveTime">5000</attribute>
<attribute name="poolSize">30</attribute>
<attribute name="poolName">EjbRequestThreadPool</attribute>
<reference name="SocketService"><gbean-
name>openejb:type=Server,name=EJB</gbean-name></reference>
</gbean>
<gbean gbeanName="openejb:type=Server,name=EJB"
class="org.openejb.server.ejbd.EjbServerGBean">
<!-- blah blah blah -->
</gbean>
This is more or less same as the above except we;
- explicitly declared all the interceptors in the stack
- left out the Host-based authorization QoS
- Constructed the ServicePool in away that makes it
create it's own pool instead of passing one in.
Anyway, that's just what is there now. It gets a lot more fun when
you add SSL and have support for a remote deployer. Then you could
could still have a remote deployer, but enforce it over SSL and
restrict the hosts that can access it. Much more is possible if you
get creative. For example, HBA is still really a naive way to
prevent a denial of service attack. You could implement something
that did clever things to thwart those kind of attacks, but only use
that for publicly bound socket producers.
This is a big long email, but by no means complete. There are really
a lot of things you can do with having a more robust way that sockets
are dished out in the system and ensuring the whole server is using
it. I consider what we have to be a good prototype and plan to
rewrite it all in ActiveIO to be more transport agnostic. I know
Greg Wilkins has some great code in Jetty that is related and would
like to get him contributing to it was well if he's up for it.
-David
On Aug 13, 2005, at 6:24 PM, Dain Sundstrom wrote:
Isn't this something that ActiveIO already does? Hiram? David?
-dain
On Aug 13, 2005, at 5:24 PM, [EMAIL PROTECTED] wrote:
Jeremy Boynes <[EMAIL PROTECTED]> wrote on 14/08/2005 02:44:40 AM:
> Aaron's recent thread on SSL has made we wonder if we should
consider
> providing our own socket listeners for HTTP(S) and other protocols
> rather than using the ones supplied by the containers we are
embedding.
>
> Reasons for doing it include:
> * ability to integrate with custom work managers (thread pools) and
> SSL infrastructure
> * consistency across all embedded containers
> * potential for multi-protocol support on one end-point
> (i.e. multiplexing everything over one port like WebLogic does
which
> can make life easier when firewalls are involved)
> * potential for integrating with custom QoS frameworks e.g. allowing
> custom negotiation with load-balancers in a clustered environment
> * potential for hi-av version upgrades where we can version in a
> upgraded component and hand off the physical socket resulting in
> no loss of availability
>
> Note that none of those features are HTTP specific.
>
> The downside of course is that it may weaken integration between the
> listener and the container being embedded; for some containers
they may
> be so closely coupled that doing this will actually make things
> difficult. For example, I think doing this would be fairly easy for
> Jetty, I don't know how easy it would be for Tomcat, OpenEJB, JMX,
> ActiveMQ etc.
This sounds like a good idea. I assume we aren't forcing
containers to use this mechanism, so if someone want to integrate
container X but doesn't initially want to go to this much effort,
they can use X's socket listener and change to use Geronimo's in
the future (although this migration will impact their configuration).
If we do end up going down this path, it would be worthwhile
talking with the Derby project about SSL and authentication for the
network server. AFAIK, this work hasn't been started yet, so it
would probably be a good time to talk with them. See the mail
thread from the links in http://issues.apache.org/jira/browse/
GERONIMO-842 .
John
>
> --
> Jeremy
This e-mail message and any attachments may contain confidential,
proprietary or non-public information. This information is
intended solely for the designated recipient(s). If an addressing
or transmission error has misdirected this e-mail, please notify
the sender immediately and destroy this e-mail. Any review,
dissemination, use or reliance upon this information by unintended
recipients is prohibited. Any opinions expressed in this e-mail
are those of the author personally.