Transfer Java object between JSF pages - jsf

I tried to implement flash in JSF. It's working well if I have to transfer Java object between pages in one session. But I have a spacial case which I need to solve.
I have a submit form where user enters personal data. Then he opens second page which is used to open payment gateway(paypal) page. When the payment is applied Paypal redirects the user back to the web site in a new web page.
I need some way to transfer the Java object data between the first and the last page. Is there any solution?
I'm using JSF 2.2.6 with Tomcat 8.

I guess the redirect of paypal to your site create a new session, if this is the case all you have to do is create a DTO object and store into BD with session ID using serialization Java Serializable Object to Byte Array
But if paypal call on same session all you got to do is get the object from the session like this
FacesContext facesContext = getFaceContext();
Application app = facesContext.getApplication();
ExpressionFactory elFactory = app.getExpressionFactory();
ELContext elContext = facesContext.getELContext();
ExternalContext externalContext = facesContext.getExternalContext();
HttpSession session = (HttpSession) externalContext.getSession(true);
session.setMaxInactiveInterval(-1);
ValueExpression valueExp = elFactory.createValueExpression(elContext, expression, Object.class);
YourBean yourBean = (YourBean) valueExp.getValue("#{yourBean}");
The scope of this bean it must be #SessionScoped

Related

How close the gab between websocket server endpoint and session scoped backing beans

In short, I don't know how I notify a session scoped bean from a application scoped bean. I found a dirty hack that work, but I'm not sure there is a better way to solve this problem (or my dirty hack is not dirty :-D ).
Every websocket in java ee has a sessionid. But this sessionid is not the same like in jsf, and there is no way for a easy mapping. In my environment I have a jsf webpage, an underlying sessionscoped backing bean and a websocket, that is connected to an external service via jms. When the jsf page is loaded, and the websocket is also connected to the browser, the backing bean sends a request to the external service. When I got a async answer message via jms I dont know which websocket is connected with the jsf page/backing bean that send the request.
To solve this problem with a partly dirty hack, I wrote an application scoped mediator class.
#Named
#ApplicationScoped
public class WebsocketMediator {
#Inject
private Event<UUID> notifyBackingBeans;
private Integer newSequenceId=0;
// I need this map for the dirty hack
private Map<UUID, BackingBean> registrationIdBackingBeanMap;
private Map<Integer, UUID> sequenceIdRegistrationIdMap;
registrationIdWebSocketMap = new ConcurrentHashMap<>();
public UUID register(BackingBean backingBean) {
UUID registrationId = UUID.randomUUID();
registrationIdSequenceMap.put(registrationId, new HashSet<>());
registrationIdBackinBeanMap.put(registrationId, backingBean);
}
public Integer getSequenceId(UUID registrationId) {
sequenceId++;
sequenceIdRegistrationIdMap.put(sequenceId, registrationId);
registrationIdSequenceMap.get(registrationId).add(sequenceId);
return sequenceId;
}
// this is called from the ws server enpoint
public void registerWebsocket(UUID registrationId, Session wsSession) {
registrationIdWebSocketMap.put(registrationId, wsSession);
websocketRegistrationIdMap.put(wsSession.getId(), registrationId);
notifyBackingBeans.fire(registrationId); // This does not work
SwitchDataModel switchDataModel = registrationIdSwitchDataModelMap.get(registrationId);
if (backingBean != null) {
backingBean.dirtyHackTrigger();
}
}
public void unregisterWebsocket(String wsSessionId) {
...
}
}
The backing bean calls a registration method and gets a uniq random registration id (uuid) . The registration id is placed in a jsf table as a hidden data attribute (f:passTrough). When the websocket is connected, the ws.open function is called in the browser and send the registration id via the websocket to the websocket server endpoint class. The Server endpoint class call the public void registerWebsocket(UUID registrationId, Session wsSession) method in the mediator and the registration id is mapped. When the backing bean is timed out, I call a unregister method from an #PreDestroyed annotated method. Every time, when the external system is called via jms, I put a sequence id into the payload. The Sequence Id is registered in the Mediator class. Every time when the external system sends a message I can lookup the correct websocket in the mediator to bypass the message via the websocket to the correct browser.
Now the system is able to receive async events via the external system, but the backing bean doesn't know that. I tried to send the registration id in a cdi event to the session scoped backing bean, but the event never reach an observer in a session scoped backing bean. So I realized this gab with a dirty hack. I put the instance of every backing bean with the registration id as key into a map in the mediator in the registration method. I placed in the public void registerWebsocket(UUID registrationId, Session wsSession) a dirty hack trigger call of the backing bean. Is there a better solution?
I use Wildfly 13 with CDI 1.2.
Thanks in advance!
I found a solution. When the webpage is called, the #SessionScoped bean is created. I calculate a unique registration id and put it as attribute in the HttpSession:
#PostConstruct
public void register() {
registrationId = switchPortMediator.register(this);
HttpSession session = (HttpSession) facesContext.getExternalContext().getSession(true);
session.setAttribute("switchRegistrationId", registrationId);
log.debug("Registered at mediator - ID=" + registrationId + " http session = "+ session.getId());
}
At the #ServerEndpoint annotated web socket endpoint, is the #OnOpen annotated method. This method is called when the webpage is loaded and the websocket is established. The websocket endpoint class is #ApplicationScoped. The attribute map, from the #SessionScoped bean, where the registration id is stored, is accessable in the EndpointConfig of the websocket endpoint. Here is the #OnOpen annotated method:
#OnOpen
public void onOpen(Session wsSession, EndpointConfig config) {
UUID registrationId = (UUID) config.getUserProperties().get("switchRegistrationId");
websocketRegistrationIdMap.put(registrationId, wsSession);
}
When the JSF page is loaded, the #SessionScoped bean calculate the registration id, put it in the attribute map and sent an async message via jms to an external system. The external system send an answer message, with the registration id inside and a payload. When the external message arrives via JMS in the websocket endpoint class, the resulting wsSession can be retrived from the websocketRegistrationIdMap and the payload can be send via the websocket to the browser, who initiate the async message. The dom updates in the website are processed by javascript.

HttpSession is null (randomly) when retrieved from HttpServletRequest using ExternalContext

I have following code to retrieve HttpSession from HttpServletRequest using ExternalContext in our Icefaces(1.8.2) & JSF(1.2) based Liferay environment :
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
HttpServletRequest httpServletRequest = (HttpServletRequest) (externalContext.getRequestMap().get("com.liferay.portal.kernel.servlet.PortletServletRequest");
HttpSession httpSession = httpServletRequest.getSession();
The above code snippet is working fluently for Liferay 6_1_0_CE_GA1 as httpSession is always populated.
But, the same code in Liferay 6_2_1_CE_GA2, I am randomly getting httpSession as null. Couldn't figure out, what the difference can be!
I have also, tried to get httpServletRequest using PortalUtil.getOriginalServletRequest and then getting httpSession from it, but that doesn't resolve the issue.
When I need access to HttpServletRequest from a Liferay portlet, I have to use this:
HttpServletRequest httpServletRequest = PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(renderRequest));
renderRequest is an object extended from the PortletRequest class. From your code, you can get the PortletRequest object this way:
PortletRequest portletRequest = (PortletRequest) externalContext.getRequest();
So, the resulting code should be:
PortletRequest portletRequest = (PortletRequest) externalContext.getRequest();
HttpServletRequest httpServletRequest = PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(portletRequest));
Hope this helps. Regards!
First of all: Please also try this on 6.2 GA6, which is out for a month now. In case this is a bug it might already be fixed during one of the later versions - the version you're using is almost 2 years old now.
Further, there's nothing that I'm aware of in the specification that allows access to the underlying HttpServletRequest. That's not to say that this is impossible (because it obviously is possible) but to say that behaviour might change, because you're outside of the specs.
I'd recommend to inspect the objects you get with a debugger and check if they're wrappers around the original servlet container's request or the actual container's objects. Also, compare if these requests are directed to the portal (check the URL) or to the portlet itself - as they're deployed in different contexts, they'll have different sessions (or one might have sessions while the other doesn't)

Injecting a session-scoped bean in JSF2

I'm having some difficulty interacting with a Session-scoped managed bean after a user programmatically logs into my web application.
BACKGROUND:
I have a [javax.enterprise.context.]Session-scoped bean named "SessionHelper" where I place a lot of information gathered from the user as he/she uses the application. In my logon page (which is NOT SessionScoped), Here's a sample of what I'm doing:
#Inject SessionHelper theHelper;
....
FacesContext theContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = theContext.getExternalContext();
HttpServletRequest theRequest = (HttpServletRequest) externalContext.getRequest();
....
theRequest.login(username, password);
....
theSession.method(dostuff);
After this section of code is executed, my application redirects into a protected directory and allows the user (based on roles) to perform their job functions.
When I attempt to "#Inject SessionHelper" into any of my protected resources, my understanding is that I should get the specific SessionScoped instance of SessionHelper that has the data set right after the call to login. This should be available to me for as long as the session (for that specific user) is valid. Unfortunately, the instance I'm getting has none of my "theSession.method(dostuff)" in it.
Am I fundamentally misunderstanding the scope here?
The only thing I could potentially see is that the initial #Inject into my login page is not carried over after the session has been created. If this is the case, is there a way to force a re-injection after the session is created?
As always, thank you very much for your help!!

FacesContext and what is ClientId

Can you explain me why we need in String clientId in the method
void addMessage(String ClientId, FacesMessage msg);?
Is it true that when client sent an initial request to server then server assign to this client a specific String ClientId. As i understand FacesContext created when aplication deployed and runnig the first time and this FacesContext is unique for application. Is it true?
Client id in FacesContext#addMessage(String clientId, FacesMessage message) is needed to be able to add a specific message to a specific component. You can either specify a client id of the component you'd like to assign the message to, or null to add the message to the messages stack not tied to a specific component. The latter will be updated in e.g. <h:message for="clientId>, while the latter in e.g. <h:messages globalonly="true">. You can add a message to global messages in case it is not component-specific, for instance, when database operation failed.

JSF PhaseListener viewId always one behind

Im trying to prevent users to access special pages with a phaselistener. for that reason im trying to figure out on which page they try to access.
but my problem is, i only get the page they where before. not the actual page.
public void afterPhase(PhaseEvent event)
{
FacesContext fc = event.getFacesContext();
System.out.println("test1" + fc.getViewRoot().getViewId());
}
and same here
public void afterPhase(PhaseEvent event)
{
FacesContext fc = event.getFacesContext();
HttpServletRequest request = (HttpServletRequest) fc.getExternalContext().getRequest();
String uri = request.getRequestURI();
System.out.println("uri: " + uri);
}
why is that, and how do i get the pagename the user is trying to access? Not that one that they required one step before, or better the page they are coming from.
It is one step behind because that is the way sequence of HTTP POST request behaves. When you are navigating in JSF application via command buttons each request goes as a post request.
Since you are protecting some resources make sure they are accessed via HTTP GET than you will get exact view id, this can be achieved as
User directly hits the url from address bar of browser.
After a post of jsf app redirect it to the resource instead of simple JSF navigation. POST-REDIRECT-GET pattern falls into this have a look here.
If you are showing some messages after each POST, you might need Flash map for that, which is new feature in JSF2, if you are on JSF1.x hard luck, you can implement flash if you want to.
To conclude catch the view ids on HTTP GET request.
Hope this helps...

Resources