Primefaces Theme change to user specific - spring-boot

When I use the below code it's working fine and change the theme, but the problem is if one of the user logged and change the theme it effects to the every user in the system. what I want is to effect the theme only for the particular user but not for every one.
Web.xml
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>#{settingsController.userTheme}</param-value>
</context-param>
primeface (.xhtml)
<h:outputLabel for="userTheme" value="Theme Name *:" style="width: 300px"/>
<p:selectOneMenu id="userTheme" value="#{settingsController.userTheme}" style="width:200px"
required="true" requiredMessage="Theme Name is Required" >
<f:selectItems value="#{settingsController.themeMap}"/>
</p:selectOneMenu>
SettingsController.java class
#ManagedBean(name = "settingsController")
#SessionScoped
#Controller
public class SettingsController {
private String userTheme = "start" ;
private Map<String , String> themeMap ;
#PostConstruct
public void init (){
setThemeMapInit( );
}
public String getUserTheme() {
return userTheme;
}
public void setUserTheme(String userTheme) {
this.userTheme = userTheme;
}
public Map<String, String> getThemeMap() {
return themeMap;
}
public void setThemeMapInit() {
themeMap = new LinkedHashMap<String, String>();
themeMap.put("Aristo", "aristo");
themeMap.put("After-noon", "afternoon");
themeMap.put("After-Work", "afterwork");
themeMap.put("Black-Tie", "black-tie");
themeMap.put("Blitzer", "blitzer");
themeMap.put("Bluesky", "bluesky");
themeMap.put("Bootstrap", "bootstrap");
themeMap.put("Casablanca", "casablanca");
themeMap.put("Cupertino", "cupertino");
themeMap.put("Dark-Hive", "dark-hive");
themeMap.put("Delta", "delta");
themeMap.put("Excite-Bike", "excite-bike");
themeMap.put("Flick", "flick");
themeMap.put("Glass-X", "glass-x");
themeMap.put("Home", "home");
themeMap.put("Hot-Sneaks", "hot-sneaks");
themeMap.put("Humanity", "humanity");
themeMap.put("Overcast", "overcast");
themeMap.put("Pepper-Grinder", "pepper-grinder");
themeMap.put("Redmond", "redmond");
themeMap.put("Rocket", "rocket");
themeMap.put("Sam", "sam");
themeMap.put("Smoothness", "smoothness");
themeMap.put("South-Street", "south-street");
themeMap.put("Start", "start");
themeMap.put("Sunny", "sunny");
themeMap.put("Swanky-Purse", "swanky-purse");
themeMap.put("UI-Lightness", "ui-lightness");
}
public void setThemeMap(Map<String, String> themeMap) {
this.themeMap =themeMap;
}
public void sumbitUserSettings (){
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
try {
ec.redirect(((HttpServletRequest) ec.getRequest()).getRequestURI());
} catch (IOException ex) {
Logger.getLogger(SettingsController.class.getName()).log(Level.SEVERE, null, ex);
}
}
}

Every Spring bean is a Singletone by default, that's why all users are affected, despite of #SessionScoped.
You can't use #ManagedBean and #Controller at the same time, see why.
The best way to combine Spring and JSF in the same app, is to use Joinfaces.
With Joinfaces your bean will end up looking like this
#Named
#SessionScoped
public class SettingsController {
Related:
JSF vs. Spring MVC

Related

Spring webflow binder not binding collection object

I'm using spring webflow v2.4.8 in my app, and trying to bind the model properties using <binder></binder>. But my collection objects (list1, list2 both ArrayList) never get bound. If I remove the <binder></binder> altogether, all properties are getting correctly bound, but in my case that is not an option.
Do I need to use some custom converter here? Any help greatly appreciated
<view-state id="myId" model="myModel" view="myView" >
<binder>
<binding property="list1"/>
<binding property="list2"/>
<binding property="string1"/>
<binding property="string2"/>
.
.
.
</binder>
.
.
.
</view-state>
It's been a while, but in my project I have a custom ConversionService, so maybe you can try using one like this:
[EDIT]
Here is an example of a converter using a service (that gets the object from the db)
#Named
public class StringToMyType extends StringToObject {
#Inject
private MyTypeService service;
public StringToMyType(MyType myObject) {
super(myObject);
}
#Override
protected Object toObject(String id, Class<?> targetClass) throws Exception {
if (id != null && id.length != 0) {
return service.findById(new Long(id));
} else return null;
}
#Override
protected String toString(Object myObject) throws Exception {
return Objects.toString(((MyType) myObject).getId());
}
}
and add it here
public class CustomDefaultConversionService extends DefaultConversionService {
#Override
protected void addDefaultConverters() {
super.addDefaultConverters();
addConverter(new MyTypeConverter()
addConverter(new ObjectToCollection(this));
}
}
it needs to then be registered this way (xml):
<webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator" conversion-service="conversionService"/>
<bean id="conversionService" class="path.to.converter.CustomDefaultConversionService"/>
hope this helps

Websocket - httpSession returns null

I would like to make the connection between a websocket handshake \ session to a HttpSession object.
I've used the following handshake modification:
public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator
{
#Override
public void modifyHandshake(ServerEndpointConfig config,
HandshakeRequest request,
HandshakeResponse response)
{
HttpSession httpSession = (HttpSession)request.getHttpSession();
config.getUserProperties().put(HttpSession.class.getName(),httpSession);
}
}
As mentioned in this post:
Accessing HttpSession from HttpServletRequest in a Web Socket #ServerEndpoint
Now,
For some reason on the hand shake, the (HttpSession)request.getHttpSession() returns null all the time.
here is my client side code:
<!DOCTYPE html>
<html>
<head>
<title>Testing websockets</title>
</head>
<body>
<div>
<input type="submit" value="Start" onclick="start()" />
</div>
<div id="messages"></div>
<script type="text/javascript">
var webSocket =
new WebSocket('ws://localhost:8080/com-byteslounge-websockets/websocket');
webSocket.onerror = function(event) {
onError(event)
};
webSocket.onopen = function(event) {
onOpen(event)
};
webSocket.onmessage = function(event) {
onMessage(event)
};
function onMessage(event) {
document.getElementById('messages').innerHTML
+= '<br />' + event.data;
}
function onOpen(event) {
document.getElementById('messages').innerHTML
= 'Connection established';
}
function onError(event) {
alert(event.data);
}
function start() {
webSocket.send('hello');
return false;
}
</script>
</body>
</html>
Any ideas why no session is created ?
Thanks
This is intended behaviour, but I agree it might be confusing. From the HandshakeRequest.getHttpSession javadoc:
/**
* Return a reference to the HttpSession that the web socket handshake that
* started this conversation was part of, if the implementation
* is part of a Java EE web container.
*
* #return the http session or {#code null} if either the websocket
* implementation is not part of a Java EE web container, or there is
* no HttpSession associated with the opening handshake request.
*/
Problem is, that HttpSession was not yet created for your client connection and WebSocket API implementation just asks whether there is something created and if not, it does not create it. What you need to do is call httpServletRequest.getSession() sometime before WebSocket impl filter is invoked (doFilter(...) is called).
This can be achieved for example by calling mentioned method in ServletRequestListener#requestInitalized or in different filter, etc..
Here is an impl for Pavel Bucek's Answer, after adding it, i got my session
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
#WebListener
public class RequestListener implements ServletRequestListener {
#Override
public void requestDestroyed(ServletRequestEvent sre) {
// TODO Auto-generated method stub
}
#Override
public void requestInitialized(ServletRequestEvent sre) {
((HttpServletRequest) sre.getServletRequest()).getSession();
}
}
Building on #pavel-bucek 's answer, I wrote a simple HttpSessionInitializerFilter servlet filter.
Just download the jar from the "Releases" page and save it anywhere in the classpath, then add the following snippet to your web.xml descriptor (modify the url-pattern as needed):
<filter>
<filter-name>HttpSessionInitializerFilter</filter-name>
<filter-class>net.twentyonesolutions.servlet.filter.HttpSessionInitializerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HttpSessionInitializerFilter</filter-name>
<url-pattern>/ws/*</url-pattern>
</filter-mapping>
first: create a new class
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
#WebListener
public class RequestListener implements ServletRequestListener {
#Override
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
}
#Override
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
((HttpServletRequest)servletRequestEvent.getServletRequest()).getSession();
}
}
and then add the "ServletComponentScan" annotation on the App main:
#SpringBootApplication
#ServletComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

HttpInvokerServiceExporter + HttpInvokerProxyFactoryBean - Could not access HTTP invoker remote service

I'm trying to use HttpInvokerServiceExporter + HttpInvokerProxyFactoryBean, but whatever I do I get an exception:
org.springframework.remoting.RemoteAccessException: Could not access HTTP invoker remote service at [http://localhost:9999/testcaseapp/testcaseservice]; nested exception is java.io.IOException: Did not receive successful HTTP response: status code = 404, status message = [Not Found]
For the simplicity, I've created a test case.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class RemoteTest {
private static final Logger logger = LoggerFactory.getLogger("TestsLogger");
static interface TestCaseService {
public Integer add(Integer arg1, Integer arg2);
}
static class TestCaseServiceImpl implements TestCaseService {
public Integer add(Integer arg1, Integer arg2) {
return (arg1 != null ? arg1.intValue() : 0) + (arg2 != null ? arg2.intValue() : 0);
}
}
#Configuration
static class Config {
#Bean
public HttpInvokerServiceExporter httpInvokerServiceExporter() {
HttpInvokerServiceExporter httpInvokerServiceExporter = new HttpInvokerServiceExporter();
httpInvokerServiceExporter.setService(new TestCaseServiceImpl());
httpInvokerServiceExporter.setServiceInterface(TestCaseService.class);
return httpInvokerServiceExporter;
}
#Bean
public HttpInvokerProxyFactoryBean httpInvokerProxyFactoryBean() {
HttpInvokerProxyFactoryBean httpInvokerProxyFactoryBean = new HttpInvokerProxyFactoryBean();
httpInvokerProxyFactoryBean.setServiceInterface(TestCaseService.class);
httpInvokerProxyFactoryBean.setServiceUrl("http://localhost:9999/testcaseapp/testcaseservice");
httpInvokerProxyFactoryBean.afterPropertiesSet();
return httpInvokerProxyFactoryBean;
}
}
#Autowired
private TestCaseService[] testCaseServices;
private static Server server;
#BeforeClass
public static void setUp() {
try {
server = new Server();
SelectChannelConnector connector = new SelectChannelConnector();
connector.setPort(9999);
server.addConnector(connector);
//
WebAppContext webAppContext = new WebAppContext();
webAppContext.setContextPath("/testcaseapp");
webAppContext.setWar("src/test/java/" + RemotingTest.class.getPackage().getName().replace('.', '/'));
server.setHandler(webAppContext);
//
server.start();
} catch (Exception ex) {
logger.info("Could not permorm the set up: {}", ex.toString());
}
}
#AfterClass
public static void destroy() {
try {
server.stop();
} catch (Exception e) {
}
}
#Test
public void addTest() {
for (TestCaseService testCaseService : testCaseServices) {
Integer sum = testCaseService.add(10, 5);
Assert.assertNotNull(sum);
Assert.assertEquals(15, sum.intValue());
}
}
}
I've also tried to create a TestCaseService bean
#Bean public TestCaseService testCaseService() ...
and provide it as a httpInvokerServiceExporter argument
#Bean public HttpInvokerServiceExporter httpInvokerServiceExporter(TestCaseService testCaseService)
...
httpInvokerServiceExporter.setService(testCaseService);
but the result is still the same.
What am I doing wrong? Thanks!
I think the problem is that the Servlet is not accesible.
SERVER SIDE
Make sure you have in your WEB-INF/web.xml (on the app that is exposing the methods -SERVER-) this code:
<web-app>
...
<servlet>
<servlet-name>remoting</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>remoting</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
...
</web-app>
Here, the remote methods are served under "services", that is, for calling the method, the URL should be:
http://localhost:8080/sample/services/list
And you have to define this Servlet as accesible, by creating a bean (in my case under WEB-INF/remoting-servlet.xml):
<bean name="/list" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service" ref="myObjectQueryService" />
<property name="serviceInterface" value="com.kategor.myapp.sample.service.ObjectQueryService" />
</bean>
CLIENT SIDE
If your using Spring under the client (not as in your example), you must define a bean for accessing the remote resources, defining some beans (one for each public resource):
In this case, it would be:
<bean id="listService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl" value="http://localhost:8080/sample/services/list" />
<property name="serviceInterface" value="com.kategor.myapp.sample.service.ObjectQueryService" />
</bean>
In your example is right.
This way, calling the Service "listService", you would have all the methods available in the class com.kategor.myapp.sample.service.ObjectQueryService
#Controller
public class HomeController {
// This is the remote service definition
#Autowired
private ObjectQueryService<MyObject, Long> objectQueryService;
/* .... */
/**
* List all Objects retrieved through Web Service from a remote Server
*/
#RequestMapping(value = "listRemoteWS", method = RequestMethod.GET)
public String listRemoteWS(Locale locale, Model model) {
StringBuilder result = new StringBuilder();
try {
// The Remote Service is called
List objs = objectQueryService.findAll(0, 10);
result.append(objs.size() + " objs found");
for (MyObject o : objs) {
result.append("<br>* ").append(o.getId()).append(" = ").append(o.getName());
}
} catch (Exception e) {
result.append("No objs have been found");
e.printStackTrace();
}
model.addAttribute("result", result);
return "index";
}
}
So I think the problem comes from the URL: maybe the service is not visible or this is not the correct path to it.
For more information, check this links (the first is really useful):
https://github.com/JamesEarlDouglas/barebones-spring-mvc/tree/master/reference/spring-remoting
http://www.ibm.com/developerworks/web/library/wa-spring3webserv/index.html
For me the problem was tomcat picked up two versions of the same applications. This raised the above error on running the client from STS in debug mode.
So solution is to clean up all the expanded webapp folders in tomcat for the application. Then redeploy the application.

Inserting custom tag in JSF Ajax response XML

Consoder the following code:
<h:commandButton value="do" action="#{testBacking.do}">
<f:ajax execute="#all" render="#all" listener="#{testBacking.listener}"/>
</h:commandButton>
I want to have a custom tag (with value based on server logic), in the Ajax response XML, something like the following:
<isValidationFailed> true </isValidationFailed>
I can use this data to re-enable the button (which was disabled when Ajax begin, to avoid double clicks) if validation is failed.
How can I achieve this (preferably without using any JSF 3rd party libraries)?
EDIT:
The example code, more precisely, should be like this:
<h:commandButton id="myButton" value="do" action="#{testBacking.do}">
<f:ajax execute="id1" render="id2 myButton" listener="#{testBacking.listener}"/>
</h:commandButton>
This is only possible with a custom PartialViewContext which you load into your JSF application using a PartialViewContextFactory. The custom PartialViewContext should in turn return a custom PartialResponseWriter on PartialViewContext#getResponseWriter(). In this custom PartialResponseWriter, you should be able to add extensions to the XML response by calling startExtension() and endExtension() in endDocument(). Something like:
#Override
public void endDocument() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put("name1", "value1");
attributes.put("name2", "value2");
startExtension(attributes);
write("lorem ipsum");
endExtension();
super.endDocument();
}
This will then end up in the XML response as
<extension name1="value1" name2="value2">lorem ipsum</extension>
This is available and traversable by data.responseXML in jsf.ajax.addOnEvent() function.
Here's a full kickoff example how you could utilize it in your particular case:
MyPartialViewContextFactory which provides the custom partial view context:
public class MyPartialViewContextFactory extends PartialViewContextFactory {
private PartialViewContextFactory wrapped;
public MyPartialViewContextFactory(PartialViewContextFactory wrapped) {
this.wrapped = wrapped;
}
#Override
public PartialViewContext getPartialViewContext(FacesContext context) {
return new MyPartialViewContext(wrapped.getPartialViewContext(context));
}
}
MyPartialViewContext which provides the custom partial response writer:
public class MyPartialViewContext extends PartialViewContextWrapper {
private PartialViewContext wrapped;
private PartialResponseWriter writer;
public MyPartialViewContext(PartialViewContext wrapped) {
this.wrapped = wrapped;
this.writer = new MyPartialResponseWriter(wrapped.getPartialResponseWriter());
}
#Override
public PartialResponseWriter getPartialResponseWriter() {
return writer;
}
#Override
public void setPartialRequest(boolean isPartialRequest) {
wrapped.setPartialRequest(isPartialRequest);
}
#Override
public PartialViewContext getWrapped() {
return wrapped;
}
}
MyPartialResponseWriter which writes <extension id="myextension"> with the body as JSON):
public class MyPartialResponseWriter extends PartialResponseWriter {
public MyPartialResponseWriter(ResponseWriter wrapped) {
super(wrapped);
}
#Override
public void endDocument() throws IOException {
startExtension(Collections.singletonMap("id", "myextension"));
write("{\"validationFailed\": " + FacesContext.getCurrentInstance().isValidationFailed() + "}"); // Consider a JSON serializer, like Google Gson.
endExtension();
super.endDocument();
}
}
To get it to run, register the factory as follows in faces-config.xml:
<factory>
<partial-view-context-factory>com.example.MyPartialViewContextFactory</partial-view-context-factory>
</factory>
Here's how you can access, parse and use the <extension id="myextension"> in your jsf.ajax.addOnEvent():
jsf.ajax.addOnEvent(function(data) {
if (data.status == "success") {
var args = JSON.parse(data.responseXML.getElementById("myextension").firstChild.nodeValue);
if (args.validationFailed) {
// ...
}
else {
// ...
}
}
});
However, your particular functional requirement can be achieved in a different, likely simpler, manner. Just let the ajax request update the button itself and let the button's disabled attribute evaluate true when there's means of a successful postback.
<h:commandButton id="myButton" value="do" action="#{testBacking.do}"
disabled="#{facesContext.postback and not facesContext.validationFailed}">
<f:ajax execute="id1" render="#this id2" listener="#{testBacking.listener}"/>
</h:commandButton>

Unable to move from controller to view in Spring MVC

I am using Spring MVC framework for my project.
I am unable to get my code running from controller to view.
Sharing the important chunk of code here.....
Inside AdminController.java controller
System.out.println("controller returning");
return new ModelAndView("dataFrame_","frameData",dataString);
Inside dispatcher-servlet.xml
<bean name="/dataFrame.htm"
class="com.organization.dept.spec.proj.module.controller.DataFrameController" >
</bean>
<bean id="dataFrameViewResolver"
class="com.organization.dept.spec.proj.module.view.DataFrameViewResolver">
<property name="dataFrameView">
<bean class="com.organization.dept.spec.proj.module.view.DataFrameView" />
</property>
<property name="dataFramePrefix" value="dataFrame_"></property>
</bean>
inside DataFrameViewResolver.java
public class DataFrameViewResolver extends AbstractCachingViewResolver {
private String dataFramePrefix;
private View dataFrameView;
#Override
protected View loadView (String viewName, Locale locale) throws Exception {
View view = null;
if(viewName.startsWith(this.dataFramePrefix)){
view = dataFrameView;
}
return view;
}
and
public String getDataFramePrefix() {
return dataFramePrefix;
}
public void setDataFramePrefix(String dataFramePrefix) {
this.dataFramePrefix = dataFramePrefix;
}
public View getDataFrameView() {
return dataFrameView;
}
public void setDataFrameView(View dataFrameView) {
this.dataFrameView = dataFrameView;
}
}
inside DataFrameView.java ...
public class DataFrameView extends AbstractView {
#Override
protected void renderMergedOutputModel(Map map, HttpServletRequest request,HttpServletResponse response) throws Exception {
System.out.println("RenderMergeoutputModel"); //line 99
I was unable to get the above system.out.println i.e. was unable to execute my code till that line 99.
The localhost log files of tomcat revealed some exception java.lang.ClassNotFoundException: javax.servlet.jsp.jstl.core.Config
I put the jstl-1.2.jar in lib and this could just get me rid of exception however still was unable get sysout of DataFrameView of line 99.

Resources