Integrating spring and vaadin - spring

Is it good to integrate Spring and vaadin? I am looking to use vaadin in view layer and spring for my services. So far I am not able to find any neat solution for integration. Is it even a good idea for Production applications like management solutions or ERP?
what could be the design of the application?
How to keep clear separation between application layers?
Issues with Vaadin integration with spring security?
How to manage scope of spring beans?
Also could anyone share the advantages and disadvantages of this integration over spring MVC.

You have a very useful add-on for Vaadin called SpringVaadinIntegration.
You can keep a clean separation very easily with Vaadin, just use Spring #Autowired and services for the data retrieval and modification.
I've used Spring security and I had no problems with Vaadin.
You can manage the scope with the #Scope annotation, with three differents values, if I remember correctly: Singleton (default), Prototype and Session.

Did you consider using Vaadin UIProvider mechanism. This way autowiring in UI is totally transparent.
You can have a look at a really simple example that uses this solution on github: spring-vaadin-example

You don't need any special vaadin addons for spring at all. Just use aspectj and #Configurable annotation along with #Autowired for every component you want to integrate with spring. Like this:
#Configurable(preConstruction = true)
public class LoginUserPasswdDialog extends LoginDialogBase {
static final Logger log = Logger.getLogger(LoginUserPasswdDialog.class);
#Autowired
private AppConfig config;
#Autowired
UserFactory userFactory;
StringBuffer name;
LoggedAction action;
protected Window parent = null;
protected Button ok;
protected Label l;
protected TextField nameText;
protected PasswordField password;
protected CheckBox saveUserPass;
protected final Window w = new Window("");
#SuppressWarnings("serial")
public void create(AbstractComponent component) throws Exception {
parent = component.getWindow();
VerticalLayout v = new VerticalLayout();
v.setSizeFull();
v.setSpacing(true);
l = new Label(
_.getString("LoginUserPasswdDialog.0"), Label.CONTENT_XHTML); //$NON-NLS-1$
l.setSizeFull();
l.addStyleName("centeredLabel");
v.addComponent(l);
HorizontalLayout h = new HorizontalLayout();
h.setMargin(true);
h.setSpacing(true);
nameText = new TextField();
nameText.setWidth("100%");
v.addComponent(nameText);
nameText.focus();
password = new PasswordField();
password.setWidth("100%");
v.addComponent(password);
saveUserPass = new CheckBox(_.getString("LoginUserPasswdDialog.1")); //$NON-NLS-1$
v.addComponent(saveUserPass);
v.setComponentAlignment(saveUserPass, Alignment.MIDDLE_RIGHT);
ok = new Button(_.getString("LoginUserPasswdDialog.2")); //$NON-NLS-1$
ok.setWidth("100px");
ok.setClickShortcut(KeyCode.ENTER);
h.addComponent(ok);
h.setComponentAlignment(ok, Alignment.MIDDLE_CENTER);
v.addComponent(h);
v.setComponentAlignment(h, Alignment.MIDDLE_CENTER);
Cookie nameCookie = CookieUtils.getCookie("username");
Cookie passCookie = CookieUtils.getCookie("password");
if (nameCookie != null && passCookie != null) {
nameText.setValue(nameCookie.getValue());
password.setValue(passCookie.getValue());
saveUserPass.setValue(true);
}
w.setWidth("400px");
w.setCaption(config.getTitle() + _.getString("LoginUserPasswdDialog.4"));
w.setResizable(false);
w.setClosable(false);
w.setModal(true);
w.center();
ok.addListener(new ClickListener() {
public void buttonClick(ClickEvent event) {
String name = (String) nameText.getValue();
String pass = (String) password.getValue();
User u = userFactory.getUser(name, pass);
if (u != null) {
if ((Boolean) saveUserPass.getValue()) {
CookieUtils.makeCookie("username", name);
CookieUtils.makeCookie("password", pass);
} else {
CookieUtils.deleteCookie("username");
CookieUtils.deleteCookie("password");
}
userFactory.updateUser(u);
action.loggedIn(u);
parent.removeWindow(w);
return;
} else {
password.setValue("");
WaresystemsUI.handle
.get()
.getMainWindow()
.showNotification(
"",
_.getString("LoginUserPasswdDialog.3"), Notification.TYPE_ERROR_MESSAGE); //$NON-NLS-1$
return;
}
}
});
w.addComponent(v);
parent.addWindow(w);
}
#Override
public void setAction(LoggedAction loggedAction) {
this.action = loggedAction;
}
}
Of course you need add support to the web.xml:
<!-- SPRING -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/application-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
<init-param>
<param-name>threadContextInheritable</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Take a look also on Spring UI scope add-on http://vaadin.com/addon/spring-ui-scope
The add-on defines custom Spring scope: UI-scope, which pass well with Vaadin application.
There is also sample application using the scope.

Related

Do JASON internal actions work with Spring Autowire?

I am developing an application using JADE, JASON (Agent frameworks) and Spring Boot. Basically what I have is a JADE Container where Both Jade and Jason Agents are registered in. And Since I am using Spring, I tend to Autowire services. In that case I am in need to access some services, inside some of my Jason internal actions (which I custom wrote extending DefaultInternalAction class). which seems not working. I have the idea how to Autowire and how the Beans work. My doubt is whether those internal actions are in the spring context or not. I guess they are not. Thats why may be the Autowire thing is not working. Can someone please explain me about the real action inside the jade container and internal actions so that I can think differently about using Autowire inside jason internal actions.
As far as I know, internal actions is created by jason, not spring that is why you cant autowire services. Personnaly, I create factory and use it for getting instance of a service. Something like this:
public class SpringPluginFactory {
private static final SpringPluginFactory INSTANCE = new SpringPluginFactory();
private ApplicationContext applicationContext;
private SpringPluginFactory(){}
private <T> T createPlugin(Class<T> iface) {
if(applicationContext == null){
throw new IllegalStateException("applicationContext cannot be null");
}
try {
return applicationContext.getBean(iface);
} catch (Exception e) {
throw new RuntimeException("factory unable to construct instance of " + iface.getName());
}
}
public static <T> T getPlugin(Class<T> iface){
return INSTANCE.createPlugin(iface);
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
then I create bean in order to set aplicationContext:
#Bean
public SpringPluginFactory pluginFactory(ApplicationContext applicationContext){
SpringPluginFactory pluginFactory = SpringPluginFactory.INSTANCE;
pluginFactory.setApplicationContext(applicationContext);
return pluginFactory;
}
and use the factory in any behaviours or internal actions
SpringPluginFactory.getPlugin(YouService.class).doSomething();
Maybe it will help.

using shiro with stormpath for jax-rs rbac

I'm attempting to adapt this excellent stormpath post by Brian Demers - https://stormpath.com/blog/protecting-jax-rs-resources-rbac-apache-shiro - to my own purposes and so far it works pretty well - except that now I want to add stormpath for user/role management rather then having the users in a shiro-ini file.
I'm using Apache Shiro shiro-jaxrs 1.4.0-RC to secure a REST endpoint using jax-rs. It works fine. I'm able to selectively secure the endpoints using a #RequiresPermissions tag like so:
#Path("/scan")
#Produces("application/json")
public class ScanService {
final static Logger logger = Logger.getLogger(ScanService.class);
#GET
#Path("/gettest")
#RequiresPermissions("troopers:read")
public List<Barcode> gettest() throws Exception {
ArrayList<Barcode> listofstrings = new ArrayList<Barcode>();
Barcode b = new Barcode();
b.setBarcode("this is a big barcode");
listofstrings.add(b );
return listofstrings;
}
#GET
#Produces( MediaType.APPLICATION_JSON )
#Path("/gettest2")
public List<Barcode> gettest2() throws Exception {
ArrayList<Barcode> listofstrings = new ArrayList<Barcode>();
Barcode b = new Barcode();
b.setBarcode("this is a BIGGER barcode");
listofstrings.add(b );
return listofstrings;
}
I also have an application class to add my resource and the ShiroFeature class like so:
package ca.odell.erbscan;
import ca.odell.erbscan.ws.ScanService;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;
import org.apache.shiro.web.jaxrs.ShiroFeature;
import com.stormpath.shiro.jaxrs.StormpathShiroFeature;
#ApplicationPath("/")
public class ERBApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
// register Shiro
classes.add( ShiroFeature.class);
// register resources
classes.add(ScanService.class);
return classes;
}
}
and my web.xml to init my Application class like so:
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>ERBSCAN</display-name>
<servlet>
<servlet-name>ERBRest</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>ca.odell.erbscan</param-value>
</init-param>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>ca.odell.erbscan.ERBApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ERBRest</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
</web-app>
and finally my shiro.ini
[main]
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager
securityManager.sessionManager.sessionIdCookieEnabled = false
securityManager.sessionManager.sessionIdUrlRewritingEnabled = false
[urls]
/** = noSessionCreation, authcBasic[permissive]
[users]
# format: username = password, role1, role2, ..., roleN
root = secret,admin
emperor = secret,admin
officer = secret,officer
guest = secret
[roles]
admin = *
officer = troopers:create, troopers:read, troopers:update
What I want to do next is add Stormpath for RBAC rather then having users and roles in a file. My feeling is there's a simple way to do this and that I'm overthinking it.
I thought it would be a fairly straightforward manner of adding in my shiro.ini:
stormpathClient = com.stormpath.shiro.client.ClientFactory
stormpathClient.cacheManager = $cacheManager
stormpath.application.href=http://....
But I was wrong. Could someone point me in the right direction?
thanks for reading that post!
A couple things I want to point out:
Use this feature com.stormpath.shiro.jaxrs.StormpathShiroFeature
instead of ShiroFeature
Your shiro.ini could look something like:
[main]
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager
securityManager.sessionManager.sessionIdCookieEnabled = false
securityManager.sessionManager.sessionIdUrlRewritingEnabled = false
[urls]
/** = noSessionCreation, authcBasic[permissive]
[stormpath]
stormpath.application.href=http://....
Permissions can be stored as user or role Custom Data, you can update the Custom Data in the Stormpath admin console:
{
… your other custom data fields …,
"apacheShiroPermissions": [
"troopers:create",
"troopers:read",
"troopers:update"
]
}
This blog post covers the custom data bit, it is a little older, but still relevant. I'll be updating the doc on this in the near future, so feedback welcome.
If this doesn't help you can also ping support, and we will get you going!
I'm going to answer my own question here. I don't think this is the best solution, but it something I managed to get to work.
I followed this web app tutorial off of the shiro site.
https://shiro.apache.org/webapp-tutorial.html
I checked out step6 of the project and copied the [main] section of the shiro.ini as follows: Note I added the
https://api.stormpath.com/v1/applications/$STORMPATH_APPLICATION_ID
at the bottom the [main] section.
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager
stormpathClient = com.stormpath.shiro.client.ClientFactory
stormpathClient.cacheManager = $cacheManager
# we can disable session tracking completely, and have Stormpath manage it for us.
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager
securityManager.sessionManager.sessionIdCookieEnabled = false
securityManager.sessionManager.sessionIdUrlRewritingEnabled = false
stormpathRealm = com.stormpath.shiro.realm.ApplicationRealm
stormpathRealm.client = $stormpathClient
stormpathRealm.groupRoleResolver.modeNames = name
securityManager.realm = $stormpathRealm
stormpathRealm.applicationRestUrl = https://api.stormpath.com/v1/applications/$STORMPATH_APPLICATION_ID
I then completely removed the [users] section of the shiro.ini. Since it's now wired up to Stormpath, I need to add users and groups there. My ScanService ( as above ) has a method called gettest decorated thusly:
#GET
#Path("/gettest")
#RequiresPermissions("trooper:read")
public List<Barcode> gettest() throws Exception {
.
.
.
so I need to added an account, a group and permissions in stormpath to match the permissions on the above resource. In order to do this, I need to add an account in Stormpath ( I already have the Application setup ) under my existing test application. I also added a group called officer1. The under this group I added Custom Data an array called apacheShiroPermissions - I added a string key/value pair 'trooper:read' to the apacheShiroPermissions - the JSON is below
{
"apacheShiroPermissions": [
"trooper:read"
]
}
Then I simply made sure my account - in this case jlpicard was part of the officer1 group.
Testing with curl
curl --user jlpicard:Changeme1 http://localhost:8080/JPA1_Web_exploded/rest/scan/gettest
Confirms jlpicard has access on the permission level. Adding and removing the strings entry's to the apacheShiroPermission array i.e. allows that fine grained access.
Also removing jlpicard from the officer1 or adding another account to it works as expected.
There is undoubtedly a better way to do this but this has what was worked for me so far.

Accessing ServletContext object in Action class in Struts 1.2

I have been given a use-case, to come up with a solution to allow configured number of users per user id to be logged in to my application at any given time.
For example : userid 'parentuser' can be used to log in to the application for a max of 10 times at any time.After this limit, the user will not allowed to log in as max number of users are accessing the application for that user.
Now, To implement this, I have created a context listener which will instantiate an attribute which I'll keep updating as the user logs in the application in the Action class.
My Context Listener is as under :
public class ApplicationContextListener implements ServletContextListener {
private Map<String, List<ApplicationContextBean>> userMap;
#Override
public void contextDestroyed(ServletContextEvent arg0) {
userMap = null;
}
#Override
public void contextInitialized(ServletContextEvent event) {
userMap = new HashMap<String, List<ApplicationContextBean>>();
}
public Map<String, List<ApplicationContextBean>> getUserMap() {
return userMap;
}
public void setUserMap(Map<String, List<ApplicationContextBean>> userMap) {
this.userMap = userMap;
}
}
web.xml is as under
<listener>
<listener-class>com.pcs.bpems.portal.listener.ApplicationContextListener</listener-class>
</listener>
Question : How can I now access this context object 'userMap' from my action class? If anyone has any other approach different than this also, kindly post the same.
Thanks
The answer is in the title of your question: store the Map (or an object wrapping the map and providing useful methods) into an attribute of the servlet context (accessible from the event), and retrieve it from wherever you want: the HttpServletRequest provides access to the servlet context.
A better solution, which would also work in case your application is clustered, would be to use the database.
Also, don't forget to decrement the counter when the session expires.
This can be stored in the Servlet Context as under :
#Override
public void contextInitialized(ServletContextEvent event) {
userMap = new HashMap<String, Map<String,List<ApplicationContextBean>>>();
event.getServletContext().setAttribute(ApplicationConstants.LOGGED_IN_USERS, userMap);
}
The stored parameters can be then fetched from the HttpSession Object as under :
currentSession.getServletContext().getAttribute(LOGGED_IN_USERS)

How to use jersey 2.0 guice on grizzly

I want to use Guice + Jersey 2.0 on Grizzly. According to this How to use guice-servlet with Jersey 2.0? discussion there is no direct Guice integration for Jersey2 at present but it can be achieved using HK2 as a bridge. I also checked the sample project in Github https://github.com/piersy/jersey2-guice-example-with-test . This project is implemented using Jetty.
But my problem is to implement it in Grizzly. On Jetty it is used like this
#Inject
public MyApplication(ServiceLocator serviceLocator) {
// Set package to look for resources in
packages("example.jersey");
System.out.println("Registering injectables...");
GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
guiceBridge.bridgeGuiceInjector(Main.injector);
}
My problem on grizzly is , how to get this serviceLocator object?
Thank you.
I have created the sample here
https://github.com/oleksiys/samples/tree/master/jersey2-guice-example-with-test
The Grizzly initialization code looks like this:
final URI uri = UriBuilder.fromUri("http://127.0.0.1/")
.port(8080).build();
// Create HttpServer
final HttpServer serverLocal = GrizzlyHttpServerFactory.createHttpServer(uri, false);
// Create Web application context
final WebappContext context = new WebappContext("Guice Webapp sample", "");
context.addListener(example.jersey.Main.class);
// Initialize and register Jersey ServletContainer
final ServletRegistration servletRegistration =
context.addServlet("ServletContainer", ServletContainer.class);
servletRegistration.addMapping("/*");
servletRegistration.setInitParameter("javax.ws.rs.Application",
"example.jersey.MyApplication");
// Initialize and register GuiceFilter
final FilterRegistration registration =
context.addFilter("GuiceFilter", GuiceFilter.class);
registration.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), "/*");
context.deploy(serverLocal);
serverLocal.start();
add dependecy
compile group: "org.glassfish.hk2", name: "guice-bridge", version: "2.4.0"
create feature
public class GuiceFeature implements Feature {
#Override
public boolean configure(FeatureContext context) {
ServiceLocator serviceLocator = ServiceLocatorProvider.getServiceLocator(context);
GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
Injector injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
bind(YYY.class).to(ZZZ.class);
}
});
guiceBridge.bridgeGuiceInjector(injector);
return true;
}
}
register feature
ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.register(GuiceFeature.class);

Spring #Secured method is not working when called through a filter that uses a Flying Saucer (Itext) ReplacedElementFactory implementation

When I call a Spring #Secured method that is found on a #Service class, through a normal #Controller class, the authentication is working correctly.
When I call the same method through an IText PDF filter, using a org.xhtmlrenderer.extend.ReplacedElementFactory implementation, I get the following stack trace:
org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:325)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:196)
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:64)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
The security is obviously working because users without the required roles receive an Access Denied Exception, while other users with the correct roles have no issues at all.
Here is a snippet from my web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter>
<filter-name>pdfFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>pdfFilter</filter-name>
<url-pattern>/reports/pdf/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Here is a snippet of the ReplacedElementFactory implementation:
#Inject private ImageService imageService;
#Override
public ReplacedElement createReplacedElement(LayoutContext ctx, BlockBox box, UserAgentCallback uac, int width, int height) {
Element el = box.getElement();
if (el == null) {
return null;
}
String nodeName = el.getNodeName();
if (nodeName.equalsIgnoreCase("img")) {
String srcAttr = el.getAttribute("src");
FSImage fsImage;
try {
fsImage = getImage(srcAttr, uac);
}catch(BadElementException ex) {
fsImage = null;
}catch(IOException ex) {
fsImage = null;
}catch(NullPointerException ex) {
fsImage = null;
}
if (fsImage != null) {
if (width != -1 || height != -1) {
fsImage.scale(width, height);
}
return new ITextImageElement(fsImage);
}
}
return null;
}
private FSImage getImage(String src, UserAgentCallback uac) throws IOException, BadElementException, NullPointerException {
FSImage fsImage;
String[] split = src.split("/");
if (src.contains("image/person/")) {
Long id = Long.valueOf( split[split.length - 1] );
Image img = imageService.getPersonImageByImageId(id);
fsImage = new ITextFSImage(com.lowagie.text.Image.getInstance(img.getImage()));
return fsImage;
}
Here is my ImageService class method:
#Secured({"ROLE_MY_ROLE_READ"})
public Image getPersonImageByImageId(Long imageId) {
return imageDao.findOne(imageId);
}
The failure happens on the call to the image service method, assumably because it is Secured and the ReplacedElementFactory implementation does not have access to the security context, but how do I authenticate?
I am new to posting, so please let me know if there is anything else required.
Not sure how you have configured your security to kick in. but if you have used for that also then check the ordering of the filter. The security filter should be before your pdffilter.

Resources