projectodd / wunderboss

The next-generation polyglot platform for TorqueBox and Immutant
Apache License 2.0
17 stars 11 forks source link

Abstractions #2

Closed jcrossley3 closed 10 years ago

jcrossley3 commented 10 years ago

I know you guys have given a lot of thought (at least, more than me) to the wboss model, and I'm sorry for taking a dump on it, but I'm uncomfortable with Applications, Components, and Containers. I would like to consider Languages/Runtimes implementation details and hide them for the common case, which I expect to involve ONE language.

Because it's only fair that you get to dump on something I suggest, here goes: an application becomes a stack (some sort of sorted map) of configured components where insertion order defines dependency relationships, e.g. you must insert a WebComponent before a RingComponent, because the components will be started in insertion order, and stopped in reverse.

So whatever stack you define is what you start and stop. No need for ComponentInstances.

There needs to be some way to discover and reflect what components are available for stacking. I'm not sure what that looks like, but I'd prefer not to call it a container. :)

Dump away!

qmx commented 10 years ago

does this stack idea allows stuff to be added in parallel?

jcrossley3 commented 10 years ago

I don't know. What kind of stuff? I guess I was thinking of a single stack as synchronously started/stopped, but I suppose you could get clever about parallelizing them. At that point, you've kinda implemented jboss-msc though.

I was drunk when I submitted this, btw.

bbrowning commented 10 years ago

I could buy into hiding Languages and Runtimes, since you're right that the common case (and perhaps the only case we support outside of running in WildFly) is a single language / runtime. I don't see how that relates to your later ideas about getting rid of ComponentInstances and a stack of configured components.

With the changes @tobias made to locating Components / Languages from the classpath, I wouldn't want to depend on the order these are registered for anything. With his changes, users don't have to explicitly register any Component - instead they just make sure they're available on the classpath (via clojure project deps, bundler entries in Ruby, etc) and use them.

I'm not entirely happen with the ComponentInstance abstraction and very open to changing that. However, I think we need some object that represents the thing that was started, whether that thing is a web context, a messaging queue, a scheduled job, etc. That's what ComponentInstance currently does.

bobmcwhirter commented 10 years ago

I hear ComponentInstance and possibly parallelization and yes I think you're building MSC Service.

Sent from my iPhone

On Mar 5, 2014, at 8:40 AM, Ben Browning notifications@github.com wrote:

I could buy into hiding Languages and Runtimes, since you're right that the common case (and perhaps the only case we support outside of running in WildFly) is a single language / runtime. I don't see how that relates to your later ideas about getting rid of ComponentInstances and a stack of configured components.

With the changes @tobias made to locating Components / Languages from the classpath, I wouldn't want to depend on the order these are registered for anything. With his changes, users don't have to explicitly register any Component - instead they just make sure they're available on the classpath (via clojure project deps, bundler entries in Ruby, etc) and use them.

I'm not entirely happen with the ComponentInstance abstraction and very open to changing that. However, I think we need some object that represents the thing that was started, whether that thing is a web context, a messaging queue, a scheduled job, etc. That's what ComponentInstance currently does.

— Reply to this email directly or view it on GitHub.

jcrossley3 commented 10 years ago

Good point about the auto-discovery of components. That leans me toward wanting each module (messaging, web, scheduling, caching) to have a single Java interface through which representations of "the thing that was started" are obtained.

That would obviate both the string keys and the ComponentInstances, I think.

tobias commented 10 years ago

Ben, Jim, and I had a discussion about this, and this is my attempt at capturing/distilling what we covered.

Given that the requirements have evolved from what we originally assumed, we can greatly simplify our model. We can drop the concept of containers and applications, and use something like what's outlined below.

But first, the current assumed requirements:

The API outlined here is generally for consumption by TB/Immutant devs, and not generally for end-user usage (though that wouldn't be prevented).

Now, examples of usage from ruby:

web = WunderBoss.component('web')
web.configure(port: 8080, host: 'biscuit')

The returned web object implements two interfaces:

(apparently I need a line here to keep markdown happy)

# start may be optional for some components if they start lazily
web.start 

web.name # => 'default'

web.startServlet('/', servlet_object) # may call start if not started

web.configure(a_hash) # throws IllegalStateException: component already started

web.stopServlet('/')

# stop stops all servlets for you
web.stop

# stop stops all components for you
WunderBoss.stop 

You can break through the API and get access to the underlying impl if need be:

undertow = web.backingObject

undertow.whateverDeploysAHandler(some_args)

You can create additional components of the same 'type', just by giving a name:

# web2 will be the same instance as web, the 'default'
web2 = WunderBoss.component('web')

# a new component
web3 = WunderBoss.component('web', 'some-name')

web3.name # => 'some-name'

On the java side, we have:

A WunderBoss class. Static methods for global component lookup, component provider registration. Languages hang here as well, but may not be relevant to this design atm.

ComponentProviders can be be auto-discovered via wunderboss.properties files on the classpath.

WunderBoss has a registry that is used to store whatever, including created components. This can be used to pre-load WunderBoss with the proper components inside WildFly.

Components are stored under "#{type}:#{name}", so the default web component is "web:default".

class WunderBoss {
  static Component component(String type);
  static Component component(String type, String name);
  static void registerComponentProvider(String type, ComponentProvider cp);
  static void put(String name, Object obj);
  static Object get(String name);
}

The ComponentProvider interface. Knows how to create components of a single type. There would be a CP for web, a CP for scheduling, etc.

interface ComponentProvider {
  Component newComponent();
}

The Component interface.

interface Component {
  Component configure(Map opts);
  // start, stop may return booleans?
  Component start(); 
  Component stop();
  String name();
  Object backingObject();
}

Various interfaces specific to each component type: web, scheduling, etc.