Once you have configured the system as described in the installation document you can start using the new scope.
One more prerequisite: instead of configuring your beans in the faces-config.xml configuration do this in your spring configuration now. You can take over all your beans into the Spring configuration, Spring also provides a session and a request scope.
With this in place, we'll start evaluating the Orchestra-relevant use-cases now - so we'll together look at what you will want to do with Orchestra.
<bean name="userInfo"
class="my.app.pck.backings.UserInfo"
scope="conversation.flash"
autowire="byName">
<aop:scoped-proxy />
</bean>
We've learned about this syntax in the small example in the introduction - a short repetition:
First, the scope-attribute of the bean-element will be defining the name of the scope; the
names can be whatever you like but we recommend "conversation.flash" and "conversation.manual".
Second, it is very important to use the
<aop:scoped-proxy />
child-element. Bear with us - we'll explain to you why that is right now.
Using the <aop:scoped-proxy />
ensures that you will never have a reference to
the real instance of your bean, but to a proxy to it. There is no difference
in the way how you work with this instance in your code, but if you
end a conversation and restart it, you'll appreciate the difference: the proxy will make
sure that your application will see the new instance.
The
autowire="byName"
Setting this property is fully optional. However, it
lowers the amount of configuration required. With this property set, Spring will scan your
bean configuration. Whenever it finds a bean with the same name as the property, it
will inject an instance of this bean configuration into this property.
For example, if you configure a bean named
userInfoDao
and your bean has a
setUserInfoDao()
method Spring will inject an instance of this DAO into your bean.
Alternatively you could provide a custom conversation name:
<bean name="bean1"
class="my.app.pck.backings.bean1"
scope="conversation.manual"
orchestra:conversationName="multibean"
autowire="byName">
<aop:scoped-proxy />
</bean>
<bean name="bean2"
class="my.app.pck.backings.bean2"
scope="conversation.manual"
orchestra:conversationName="multibean"
autowire="byName">
<aop:scoped-proxy />
</bean>
As you can see in the above example we put two beans into the same conversation, which
means they share the same persistence context.
This opens the possibility to keep the "one class per page" paradigm and still
allows you to pass entities between these two pages (e.g. Master/Detail scenarios).
Closing a conversation is straightforward as well. If the bean is in a scope that has been marked with lifetime=flash then the conversation terminates when a request is processed without referring to anything in that conversation. If you've using a "manual" conversation instead, then you need to call:
Conversation.getCurrentInstance().invalidate()
from within the conversation-scoped bean. With this call, the conversation will cease to exist
and the bean will be cleared from the conversation.
At times, you do not only want to close a conversation, but you also want to restart it immediately. For this, use the following call:
public void invalidateAndRestart() { YouBean bean = (YourBean) ConversationUtils.invalidateAndRestart(Conversation.getCurrentInstance()); bean.setUser(createdUser.getId()); }With the returned object, you can do configuration and initialization work.
If you have a conversation running over a multitude of pages,
you might want to check if the conversation has been initialized before you reach the page.
For doing this, you can call the method:
ConversationUtils.ensureConversationRedirect(conversationName, redirectToJsp)
before the conversation is first accessed on this page, as in an initialization or
prerender-method.
ConversationUtils.invalidateIfExists(conversationName)
Every method in your conversation bean is able to issue a database request or to call e.g. a DAO which will do it. Its ensured that during the whole lifetime of this conversation bean all database code will see the same entity manager.
Methods
which change data has to be annotated with the
@Transactional
annotation.
Which means, that every changed/inserted/deleted entity will be flushed to the database and committed.
Thats an important thing to understand. You can change an entity whenever you want, but it will only be flushed after such an annotated method has been invoked.
From within a conversation scoped bean you can use
Conversation.getCurrentInstance()
or the ConversationManager API if you are outside of a conversation or would like to access another
conversation
ConversationManager.getConversation(conversationName)
Once you have access to the conversation object you can do:
ConversationBindingListener
interface
will receive the valueBound()/valueUnbound()
.
removeAttribute(key)
or if the
conversation ends, either manually or automatically due to a timeout.
valueUnbound()
you can't assume that a faces context
will be available.