views:

88

answers:

2

I have been mocking out some seam components using the following signature:

@Name("myService")
@Install(debug = true, precedence = Install.MOCK)
public class MyServiceMock implements MyService

I enable my mocks by changing this line in my components.xml

<core:init transaction-management-enabled="false"  />

to this:

<core:init transaction-management-enabled="false" debug="true" />

This was fine when I wanted to mock out all of the classes. I just had my ant script replace my normal components.xml with a debug version.

Is there any way to conditionally mock out one or more components? An ideal solution would allow me to specify which components to mock out in an external file such as components.properties or another properties file.


My Solution


Here's what I settled on based on germanescobar's answer.

I changed my mock component signatures to match this:

@Name("myService")
@Install(false)
public class MyServiceMock implements MyService

Then I added a line for each component I want to mock out to components.xml that looks like this:

<component name="myService" installed="false" precedence="40"
               class="com.foo.bar.baz.service.MyServiceMock" />

To enable a mock, I set installed=true.

A: 

You can Either rely on org.jboss.seam.postInitialization Event

Called when Seam has initialized and started up all components

Or org.jboss.seam.postAuthenticate.<username>

Called after a user is authenticated such as devMode

So create your ConditionallyEventComponent and define its @Observer Event

@Name("conditionallyEventComponent")
@Scope(ScopeType.APPLICATION)
public class ConditionallyEvent {

    @Observer("org.jboss.seam.postInitialization", create=true)
    /*
     * or @Observer("org.jboss.seam.postAuthenticate.devMode", create=true)
     */
    public void postInitialization() {
        /**
          * An ideal solution would allow me to specify which components to mock out in an external file
          */

        /**
          * Here i am overriding ApplicationScoped components
          *
          * Maybe you want something like
          * applicationContext.properties
          * sessionContext.properties
          */

        Context context = Contexts.getApplicationContext();

        ResourceBundle resourceBundle = ResourceBundle.getBundle("applicationContext");
        Enumeration<String> keyEnumeration = resourceBundle.getKeys();
        while(keyEnumeration.hasMoreElements()) {
            String key = keyEnumeration.nextElement();
            /**
              * Keep in mind newInstance method needs no-arg constructor
              */
            context.set(key, Class.forName(resourceBundle.getString(key)).newInstance());
        }

    }

}

By supplying the create attribute, you can also specify whether to have the observer component created if it does not exist at the time the event is raised

You can also supply a system property as follows

-Dprofile=development

Check out your Application Server documentation how To set up system property. And inside your postInitialization (or postAuthenticate) Event

@Observer("org.jboss.seam.postInitialization", create=true)
public void postInitialization() {
    Properties properties = System.getProperties();

    String profile = properties.getProperty("profile");
    if(profile != null && profile.equals("development")) {
        // do as shown above
    }
}
Arthur Ronald F D Garcia
@braveterry Maybe you want To iterate over all The components. See here: http://stackoverflow.com/questions/2838787/seam-list-all-components/2856848#2856848 how To
Arthur Ronald F D Garcia
@braveterry See also http://stackoverflow.com/questions/3140804/how-do-you-create-components-xml-for-debug-development-in-seam
Arthur Ronald F D Garcia
I tried the procedure described http://stackoverflow.com/questions/3140804/how-do-you-create-components-xml-for-debug-development-in-seam before I posted. It works for conditionally installing a component, but not for overriding one. There's probably a way to do it, but no matter what I tried both components always ended up with the same priority.
braveterry
+1  A: 

What I usually do when I want to override only certain components is to use the components.xml file. So, for example, if I have a MyService interface with a default implementation like this:

@Name("myService")
public class DefaultMyService implements MyService 

And I want to override only that specific class, I add the following to components.xml:

<component name="myService" class="org.gescobar.MockMyService" precedence="30" />

Just take a look at the precedence. By default, every component has a precedence of 20, so 30 will override that component. You can think of components.xml as your external file (or you application-context.xml for Spring users) where you can override any component you want.

germanescobar