Home Help Center

Design patterns for using CCM (related to IceBox)

SteveWamplerSteveWampler Member ✭✭
I'm new to both Ice and CCM and asking if someone here can point me to some sources
where I can learn of approaches to using CCM (with the specific aim of working with
IceBox (or subclasses of it). While I describe a specific problem here, it's more so
you can see the type of issue I'm struggling with than to get a specific response (not
that I'd turn down a specific response, mind you...).
The 'applications' that are candidates for becoming components held in a Java IceBox
need access to common services; some Ice services, some not. My initial thinking
was to have the servicemanager construct a 'Toolbox' of these services for each
new component and assign the Toolbox to the component. However, I don't
know how to make it easy for class instances referenced by the base component
class to get access to the Toolbox. (The Toolbox knows about the component,
so the services it offers can automatically identify the source of a service request.
[E.g. an event posting gets timestamped and has the source component 'name'
attached by the Toolbox event service, so the class requesting the event post
doesn't have to worry about either - the Toolbox, in effect, knows who owns it.]

In the (pre-Ice, pre-CCM) past, I've done this by making the Toolbox a class
of static methods offering the services. But this won't work (from what I
know) in a CCM implemented on a shared JVM because *all* components
in the IceBox would see the exact same Toolbox - so the Toolbox no longer
could have an 'owner'. (And it may be the case that the servicemanager
might be smart enough to want to put different tools into each component's
Toolbox, based on some criteria - a static class nicely defeats this.)

Has someone here come across a source of information that addresses such
issues when developing components for a CCM? (IceBox specific would
be, of course, perfect, but I'll take any pointers at all.)

Thanks!
Steve

Comments

  • marcmarc FloridaAdministrators, ZeroC Staff Marc LaukienOrganization: ZeroC, Inc.Project: The Internet Communications Engine ZeroC Staff
    I'm not sure I understand the question. Ice and CCM have nothing to do with each other. CCM is CORBA stuff, not Ice.
  • SteveWamplerSteveWampler Member ✭✭
    Sorry, I was using 'Container/Component Model' in a more general sense not as a
    brand id. (I think I've seen .NET and JavaEnterprise Beans also referened to
    as examples of this model, and IceBox appears to me to exhibit similar
    functionality).

    Does my question make sense viewed in this generic fashion? Briefly,
    there are things that can be done in standalone applications (such as the
    use of a 'static' class to give all objects quick access to common services)
    that appear difficult to replicate when these applications are replaced
    by Java IceBox 'services'. This is also a problem with (as I understand)
    the other shared-JVM systems that I've (apparently mistakenly) collectively
    called CCM, so I'm assuming solutions to any one of these would be
    adaptable to IceBox as well
  • marcmarc FloridaAdministrators, ZeroC Staff Marc LaukienOrganization: ZeroC, Inc.Project: The Internet Communications Engine ZeroC Staff
    All that IceBox does is to put several Ice servers (then called services) into one physical process. How many there are, and whether or not they are shared by clients, has nothing to do with IceBox, but with how you design your application.
  • SteveWamplerSteveWampler Member ✭✭
    Thanks Marc.

    Actually I knew that - it is the application design part that I'm struggling with,
    and why I was asking for pointers on how to approach this type of
    design issue. (I wasn't intending to address this to the Ice development
    team since it's not a flaw in IceBox; but rather to the wider audience of Ice users in hope
    that someone has looked into this issue before and found an approach that would work
    with IceBox - or can point at a place where such issues are dealt with.

    If no else replies I'll take that as a 'no'...

    Thanks again!
    Steve
  • michimichi Member Michi HenningOrganization: Triodia TechnologiesProject: I have a passing interest in Ice :-) ✭✭✭
    Hmmm... The usual answer to this kind of problem is to add a level of indirection. In your case, instead of having a single static class with the toolbox functionality, you would have a single static map instead. The key would be the component ID, and the value the toolbox instance for that component.

    Would that get you off the hook?

    Cheers,

    Michi.
  • SteveWamplerSteveWampler Member ✭✭
    Yes, I believe so. If it's possible to identify the component ID automagically (as I said,
    I'm new to Ice). I had thought of using a map with the component 'name' (external application
    name) but couldn't figure out how to get to the component name from anywhere without passing
    it around everywhere (which isn't acceptable).

    Thanks, Michi!
  • michimichi Member Michi HenningOrganization: Triodia TechnologiesProject: I have a passing interest in Ice :-) ✭✭✭
    Hi Steve,

    The start() operation of each service ("component" in your terminology) is passed the service name. So, you can remember the service name in start() and then use it later to identify the correct toolbox. I think that should fit your requirements?

    Cheers,

    Michi.
  • SteveWamplerSteveWampler Member ✭✭
    I would think so, but I don't see how. The place where start() saves off the component id
    has to be unique for each component, but accessible from any object referenced by that
    component's execution. That is, I may have a generic class containing code (kinda, sorta)
    like:

    Event.post("filter_wheel_position","five");

    where the Event.post method would consist of something like:

    ...
    component_id = getCurrentComponentID();
    toolbox = ToolboxMap.getToolbox(component_id);
    toolbox.sendEvent(eventName, eventText);
    ...

    and sendEvent would tack a timestamp and the current component name onto an IceStorm
    message for the eventName/eventText information.

    It's the implementation of getCurrentComponentID() that has me stuck, since the above
    code might be executed from any of the components in the IceBox.
  • michimichi Member Michi HenningOrganization: Triodia TechnologiesProject: I have a passing interest in Ice :-) ✭✭✭
    Originally posted by SteveWampler

    Event.post("filter_wheel_position","five");

    where the Event.post method would consist of something like:

    ...
    component_id = getCurrentComponentID();
    toolbox = ToolboxMap.getToolbox(component_id);
    toolbox.sendEvent(eventName, eventText);
    ...

    and sendEvent would tack a timestamp and the current component name onto an IceStorm
    message for the eventName/eventText information.

    It's the implementation of getCurrentComponentID() that has me stuck, since the above
    code might be executed from any of the components in the IceBox.

    Hmmm... I see what you mean. I guess one way is to pass the component ID (or a component handle) to the Event.post method, instead of retrieving it inside the method with something like getCurrentComponentID().

    The only other thing I can think of is to use something that's available as part of the Ice::Current object. The current object provides access to the object adapter and, via that, to the communicator for the operation that is currently being invoked. Possibly, the adapter name could be used as a sufficiently unique ID for your purposes? (I don't know enough about what you are doing to be sure whether this is feasible.)

    Another option would be to deposit the component ID in some global variable, but that is neither thread safe nor pretty...

    Cheers,

    Michi.
  • SteveWamplerSteveWampler Member ✭✭
    Hmmm... I see what you mean. I guess one way is to pass the component ID (or a component handle) to the Event.post method, instead of retrieving it inside the method with something like getCurrentComponentID().

    Yes, but that means I have to pass component ID through every method call/constructor reachable
    from the call to start(), which isn't going to be acceptable to other developers.
    Another option would be to deposit the component ID in some global variable, but that is neither thread safe nor pretty...

    But the only global variables available in Java are static class variables, and those would been
    seen by all components in the (shared JVM icebox), which puts me back to square one (if I could
    put the component ID there, then I could just as easily stash the Toolbox there to begin with, I
    suspect).
    The only other thing I can think of is to use something that's available as part of the Ice::Current object. The current object provides access to the object adapter and, via that, to the communicator for the operation that is currently being invoked. Possibly, the adapter name could be used as a sufficiently unique ID for your purposes? (I don't know enough about what you are doing to be sure whether this is feasible.)

    This sounds promising, but maybe because I don't understand yet. I'll have to learn more abuot
    IceBox and Ice in general to understand if this is possible/would help. The problem I'm having
    seems to me to be one that would be an issue with any group of Java apps sharing the same JVM
    (ala IceBox) - there's no "component-locally global" storage available in Java. I was hoping
    someone on this list would know of a generic solution.

    Sorry to have taken up so much of your time for what isn't really an issue specific to Ice!
  • michimichi Member Michi HenningOrganization: Triodia TechnologiesProject: I have a passing interest in Ice :-) ✭✭✭
    Yet another option would be to use Ice configuration parameters. You can configure each component with a property that provides the ID of the component. Then, via the Current object, you can get at the adapter and the communicator and, via that, at the properties for the communicator and read the property value.

    This will work provided that, for a given invocation thread, the invocation from the client is made to an operation on the component (because the Current object is available only to Ice operation invocations). This may give you what you need. Possibly, you won't get away without passing the component ID everywhere but, depending on how the code is structured, you may be able to avoid passing it explictly most of the time.

    Cheers,

    Michi.
  • SteveWamplerSteveWampler Member ✭✭
    Thanks Michi,

    I'll look into that. My instinct is that this is the type of issue that Sun is addressing
    in their multi-tasking support [to be added to JDK 1.6 JVMs]. In some sense, a shared-JVM
    is a shared-memory environment, which complicates its use as a multitasking
    system. At least I hope 1.6 helps here...the problem could definitely be solved at the
    JVM level.

    On reflection, an approach I can take for now (we're some years away from 'deployment')
    is to simply limit each IceBox to running a single component. It's not much worse than
    running each component as a standalone application and at least holds some promise for
    taking advantage of any future solution. If I can't figure out how to make your recent
    suggestion work I'll probably just take this route.

    Thanks again for all your suggestions - I realize I've taken you pretty far off-topic
    and consumed quite a bit of your time doing so!
  • michimichi Member Michi HenningOrganization: Triodia TechnologiesProject: I have a passing interest in Ice :-) ✭✭✭
    No problem. Please let us know how you go. Once Java matures a bit more, we might be able to modify Ice to take advantage of new features. Unfortunately, we have to keep compatibility with older Java versions for quite some time, so we can't do this too quickly.

    Cheers,

    Michi.
  • ganzuoniganzuoni Member Guido AnzuoniOrganization: IndividualProject: No specific project ✭✭
    Just my 2 cent (maybe 1).

    It looks like a typical (!) multiplexing problem.
    In this sense, the getCurrentComponentID() could
    be better invoked by Toolbox implementation itsef.
    In particular, you could have a
    ToolboxMux implements Toolbox {


    ....
    component_id = getCurrentComponentID();
    Toolbox realtoolbox = toolboxMap.getToolbox(component_id);
    realtoolbox.sendEvent(eventName, eventText);

    ....

    Let's come to getCurrentComponentID().
    I had a similar pb when I implemented an asynchronous
    PublishSubscribeRegistry where I had the need to propagate
    the "context" available in the thread of publisher to become
    the "context" of the subscriber when the registry dispatched the
    event.
    I wanna be honest. I cannibalized (!) a lot of ideas from CORBA
    PI way of work. (Yes, I know Michi will read !!!).
    Well, it works, but keep in mind that it's a solution for this particular
    problem, where the "getCurrent" can be viewed as a ThreadLocal
    object.
    Let's go back to the example.
    So the component invokes sendEvent on the Toolbox interface
    that is a multiplexer.
    But there should be someone that makes the "context" as the
    "current" context.
    This can be done in 2 ways (o maybe more):
    1. you have a ContextualToolbox implementation of Toolbox that
    is held by the component that will "push" its context, so
    that it can be retrieved by ToolboxMux.
    2. you can let the ToolboxMux behave a-la-CORBA and allow
    the registration of (request) interceptors that transfer the thread
    context in the request context (especially useful in case of
    async dispatching).

    In the first case, ContextualToolbox will have:

    class ContextualToolbox {

    ToolboxMux toolbox;

    sendEvent(..) {

    try {
    ContexService.push(myContext);
    toolbox.sendEvent(...);
    } finally {
    ContexService.pop();
    }

    }

    }


    That stacked approach allows nesting.
    Oops, I forget getCurrentComponentID().
    It will be a method of the context, so that

    getCurrentComponentID() {
    Context ctx = getCurrentContext();
    return ctx.getComponentID();
    }

    Hope it helps,

    Guido
  • SteveWamplerSteveWampler Member ✭✭
    Thanks, Guido!

    I'll look into your proposal if I don't get something else (suggested on the comp.java.programming
    newsgroup) to work. The suggestion posted there is to use a separate classloader for
    each component (service) loaded into the IceBox. I like that approach conceptually because
    of its generality - I should be able to load arbitrary 'applications' that way and not have to
    worry about collisions of singleton classes and static variables/methods between the
    applications. (I would still create the Toolbox instances in a common environment, so
    they can share resources among themselves. But each 'component' would now be able to
    retain its own separate context.

    It'll take me a while to work this out, as I'm officially supposed to be doing design, not
    coding, at this point. But if I get it work I'll report back here, since it sounds like something
    that might be generally useful in IceBoxen. [The comment on the c.j.p posting was
    "this is how application servers do it".]

    Of course, if someone want to beat me to writing an extended IceBox with this property...

    Thanks again!
  • SteveWamplerSteveWampler Member ✭✭
    I've solved my problem (isolating services from each other) by
    writing a new classloader for use with an IceBox ServiceManager.
    (The ServiceManager uses separate instances of this new classloader
    to load each service.)

    Each service's classes are independent of classes in other services,
    even if they have the same name (so static and singleton classes
    can be used safely within a single service).

    For example, I took the IceBox hello example and extended it to
    load two (nearly identical) services: a "hello" service that would
    output on demand the string "Hello:"+Memory.get() and a "goodbye"
    service that outputs "Goodbye:"+Memory.get(). The hello service
    initializes Memory with Memory.set("Hello World!") while the
    goodbye service does Memory.set("Goodbye World!").

    The class Memory uses static variables and methods to remember
    a string:

    public class Memory {
    public static void set(String s) {
    memory = s;
    }
    public static String get() {
    return memory;
    }
    private static String memory = "";
    }

    (In my 'real-world' case, the above technique can be adapted
    to construct a Toolbox class that 'remembers' its owner.)


    The new demo is run with the server loading both the hello service
    and the goodbye service. Two clients are started, one connecting
    to the hello service, the other to the goodbye service. Each asks
    its service to print a string.

    With the original ServierManager, the server's output is:

    ->java IceBox.Server --Ice.Config=config
    Hello: Hello World!
    Goodbye: Hello World!

    That is, both services are sharing the *same* Memory class (apparently
    the hello service got loaded last...)

    Using a ServiceManager modified to load new services with new
    instances of the new classloader, the output becomes:

    ->java IceBox.Server --Ice.Config=config
    Hello: Hello World!
    Goodbye: Goodbye World!

    And each server is now using a unique copy of the Memory class!

    Classes loaded by the 'parent' classloader would still be shared
    by both classes, so it's possible to extend the ServiceManager to
    share some classes and not others.

    The particular classloader I wrote only locates classes on the
    CLASSPATH and so system classes (e.g. java.*) are still share
    (unless you've got $JAVA_HOME/jre/lib/rt.jar on your CLASSPATH).
    And it's primitive in its operation (sufficient for my needs, but
    highly insecure and incomplete for a true general-purpose loader...).
Sign In or Register to comment.