How can I override a specific Seam component?
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
.
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.
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
}
}
精彩评论