Service availability is handled at assembly time (i.e. before the instantiation of any components). If you want dynamic service selection at runtime then you need to be accessing a service that provides support for this (e.g. component X provides brokerage service S - component Y declares dependency on X).
:/. That's effectively back to the phoenix world then. These things don't fly that imo nicely, but a 'mixin' provides for an adaptable setup still.... anyways, for my particular highly dynamic usecase, I need (and think will use):
/**
* An abstract class which expects a fortress container and will
* try and look up dependencies from that container instance before
* trying the 'regular' ServiceManager. Useful for applications that
* embed fortress as a 'subcontainer'.
*/
public class AbstractFortressServicable extends AbstractLogEnabled
implements Servicable
{
private ServiceManager m_parent; private Container m_c; // fortress container
private Map m_refs = new HashMap();
private List m_parentRefs = new ArrayList();private ServiceManager m_sm;
/**
* Note: if your metadata parser tool does not parse
* dependencies for base classes, you will have
* to add a dependency on
* org.apache.avalon.fortress.Container
* in some other way
*
* @avalon.dependency
* type="org.apache.avalon.fortress.Container"
* @avalon.meta.dependency
* type="org.apache.avalon.fortress.Container"
* @phoenix.dependency
* name="org.apache.avalon.fortress.Container"
*/
public void service( final ServiceManager sm )
{
m_parent = sm;
m_c = sm.lookup( c.ROLE );
m_sm = new MyServiceManager();
} /** get access to the servicemanager. Warning:
* the provided ServiceManager is *not* threadsafe! */
protected final ServiceManager getServiceManager()
{
return m_sm;
} private class MyServiceManager implements ServiceManager
{ public Object lookup( final String role )
throws ServiceException
{
if( !hasService( role ) )
throw new ServiceException(
role ); if( m_c.has( role, null ) )
{
final ComponentHandler h = m_c.get(
role, null );
final Object comp = h.get();
m_refs.put( comp, h );
return comp;
}
else
{
final Object comp =
m_parent.get( role );
m_parentRefs.add( comp );
return comp;
}
} public boolean hasService( final String role )
{
return m_c.has( role, null ) ||
m_parent.hasService( role );
} public void release( final Object comp )
{
if( refs.containsKey( comp ) )
{
final ComponentHandler h =
m_refs.remove( comp );
h.put( comp );
}
else if( m_parentRefs.contains( comp ) )
{
m_parentRefs.remove( comp );
m_parent.release( comp );
}
}
} // end of MyServiceManager
}public class MyClient extends AbstractFortressServicable
implements MyService
{
protected FortressProvidedService getFPS()
ServiceException
{
return getServiceManager().lookup( FortressProvidedService.ROLE );
}
protected void releaseFPS( FortressProvidedService fps );
{
getServiceManager().release( fps );
}
}while this is certainly workable (as its been working in phoenix+fortress-based apps for a long time now), it's not totally clean:
1) al your components actually depend on Container
2) the meta generation tool has to be able to parse dependencies declared by base classes
3) you need a 'utility jar' with AbstractServicable
4) you really need to use an inner class to do this cleanly
the advantages:
5) it has a potential to easily work in any container, ensuring component portability
6) nastiness is isolated in AbstractServicable
>> I want to tell it how to takewell, I don't want [merlin to autoresolve all deps]! Or really,
care of that: I want to be able to configure at deployment time (perhaps even runtime) that for some services that MyGraphicalClient asks for, merlin will defer the call to MyFortressContainer.
http://avalon.apache.org/sandbox/merlin/starting/advanced/selectors.html
IIUC, that would mean I'd have to have
<type>
<!-- ... -->
<dependencies>
<dependency key="(...)" type="(...)">
<attributes>
<attribute key="urn:avalon:profile.selector" value="(...)"/>
</attributes>
</dependency>
</dependencies>
</type>for all the dependency declarations of all my components! No thanks!
Maybe the contract on a <container/> implementation is a bit heavy then?
It's not too heavy for what Merlin does but its probably too heavy for what you have in mind. Keep in mind that the "block" notion is all about defintion of new components using other components as the logical implementation.
yeah, I understand how the current setup makes sense as long as you just want to use the containment/container scenarios merlin supports out of the box. I think this thread shows advanced customization is currently harder than potentially possible.
preliminary conclusion: Merlin is not a fully "profilable" container at this point in time, and some work is neccessary to make it into one :D
[neat example] is what the block concept is all about.
agreed. The problem I've found here is that setting up a merlin block that is completely different in implementation and internal organisation but still is completely usable by other (more standard) merlin blocks is far from trivial. Which imo is one of our goals with the bundle API stuff :D
hmm. COP-wise, I want merlin to provide a sandbox containment environment containing my fortress instance, and I want it to route some component lookup calls to this instance, where the "some" is to be dynamically configurable. So from merlin's view, I am talking about computations on both the container and the component sides. Indeed, I am wanting to modify the containment environment.
Yep. No problem. 1. component invokes lookup on its service manager 2. the service manager implementation holds a reference to the appliance managing the component 3. the managing appliance has already been assembles with references to multiple provider appliance instances that are capable of handling respective service dependencies (a) you can influence the selection process by supplying a custom profile selector
step 3 is the nontrivial part, because you need to write your own appliance, which is a heavy contract.
5. the service manager implementation invokes resolve on the fortress appliance (assuming lookup was for a service that the fortress appliance has been assigned to provide) 6. the fortress appliance gets hit with a resolve() request and does its stuff and returns a service reference to the service manager implementation 7. service manager implementation returns reference to component implementation
yep. It's possible :D
ServiceDescriptor[] getServices(); Object resolve( Object source, String ref );
sounds like sort-of what I need. But isn't this a functional contract identified here, something which deserves to be marked with an interface rather than an abstract base class?
Its defined by the Appliance interface.
yeah, but Appliance also defines lots of other stuff. The fact that it is feasible and desirable to seperate that interface into a common base and an implementation seems to indicate that it also possible to split it into two interfaces, IOW, it might be a good idea to replace the inheritance you suggest here with composition resulting in less coupling. OOP 201 ;D
I'm currently working on the appliance implementation (making the contextualization patterns for appliance instances easier to work with). As a result I have some uncommitted code which I want to get into CVS as soon as I'm done.
In that case, I'm not going to write a FortressAppliance at this point.
I think I've given you some ideas of possible needs you might want to incorporate or just let simmer. In the meantime, I'll use AbstractServicable and a fortress block like you've explained works well for james.
It should be possible to switch to using a custom appliance just by changing AbstractServicable and some config files later.
this stuff is fun :D
g'night,
- Leo
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
