Usage
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 you have to 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.
Starting a conversation
In the beginning, we'll want to start a conversation. Doing that is a no-brainer in Orchestra - if you've declared the relevant managed beans as in the following example:<bean name="userInfo" class="my.app.pck.backings.UserInfo" scope="conversation.access" autowire="byName"/> </bean>
We've learned about this syntax in the small example in the introduction - a short repetition:
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.access" and "conversation.manual".
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"/> <bean name="bean2" class="my.app.pck.backings.bean2" scope="conversation.manual" orchestra:conversationName="multibean" autowire="byName"/>
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
Closing a conversation is straightforward as well. If the bean is in a scope that has been marked with lifetime=access 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()
Restart a 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()); }
Ensure a conversation is running
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.
JPA Transaction
Note : Once again we would like to stress that Apache MyFaces Orchestra does not rely on annotations, the JPA thing was just the one we build the examples with, thats why we describe it at first.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.
Access a conversation
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)
Add beans to a conversation
As e.g a http session or the request map, internally the conversation is also just a map of beans.Using the spring configuration you're able to add just one bean, the conversation scoped bean to the conversation with the same name as the bean.
But there are ways to add other objects using the Conversation API.
Once you have access to the conversation object you can do:
- conversation.setAttribute(key, value)
- conversation.hasAttribute(key)
- conversation.getAttribute(key)
- conversation.removeAttribute(key)
Any bean implementing the ConversationBindingListener interface will receive the valueBound()/valueUnbound().
- valueBound()
Will be invoked AFTER the bean has been added to the conversation map. - valueUnbound()
Will be invoked AFTER the bean has been removed from the conversation map.
This will happen if you call removeAttribute(key) or if the conversation ends, either manually or automatically due to a timeout.
Using older Orchestra Releases
The documentation above applies to the most recent Orchestra code. When using older releases, the following information is useful.
Using aop:scoped-proxy
For Orchestra 1.0, you should add an <aop:scoped-proxy /> within the declaration of each bean that is of conversation scope. This 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.
This is automatically done for you with Orchestra 1.1 and later.