Showing posts with label Java EE. Show all posts
Showing posts with label Java EE. Show all posts

Friday, September 16, 2011

Why does f:validateDoubleRange only work for @SessionScoped?

Can someone explain to me why Foo in my example is always null when it gets to the validateDoubleRange class? The end result is the min value for the validator is always 0. The number 3 displays just fine on the page when in the outputText element.
It validates fine if I make the bean `@SessionScoped` instead of `@ViewScoped`

Controller:
import java.io.Serializable;
    import java.math.BigDecimal;
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.ViewScoped;
    
    @ViewScoped
    @ManagedBean(name = "fooController")
    public class FooController implements Serializable {
    
        private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FooController.class);
        private static final long serialVersionUID = 1L;
        private Foo foo;
        private BigDecimal amount;
        private Long fooId;
    
        public Long getFooId() {
            return fooId;
        }
    
        public void setFooId(Long fooId) {
            this.fooId = fooId;
            this.foo = new Foo();
            foo.setFooId(fooId);
            foo.setMinAmount(Double.valueOf(3));
            foo.setMaxAmount(Double.valueOf(10));
        }
    
        public Foo getFoo() {
            return foo;
        }
    
        public void sendAmount() {
            log.debug("sendAmount: " + amount);
        }
    
        public BigDecimal getAmount() {
            return amount;
        }
    
        public void setAmount(BigDecimal amount) {
            this.amount = amount;
        }
    
        public static class Foo {
    
            private Long fooId;
            private Double minAmount;
            private Double maxAmount;
    
            public Foo() {
            }
    
            public void setFooId(Long fooId) {
                this.fooId = fooId;
            }
    
            public void setMinAmount(Double minAmount) {
                this.minAmount = minAmount;
            }
    
            public void setMaxAmount(Double maxAmount) {
                this.maxAmount = maxAmount;
            }
    
            public Long getFooId() {
                return fooId;
            }
    
            public Double getMaxAmount() {
                return maxAmount;
            }
    
            public Double getMinAmount() {
                return minAmount;
            }
        }
    }

JSP:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:ui="http://java.sun.com/jsf/facelets"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns:h="http://java.sun.com/jsf/html"
                >
    <f:metadata>
        <f:viewParam name="fooId" value="#{fooController.fooId}" />        
    </f:metadata>
    <h:form id="myForm">
        <h:outputText value="This is correctly displayed: '#{fooController.foo.minAmount}'"/><br/>
        <h:outputText value="My Input:" />
        <h:inputText id="myInput"
                     value="#{fooController.amount}" 
                     required="true"
                     >
            <f:validateDoubleRange minimum="#{fooController.foo.minAmount}" maximum="80"/>
        </h:inputText>
        <h:message for="myInput"/>
        <br/>
        <h:commandButton id="bidButton"
                         value="Place Bid"
                         action="#{fooController.sendAmount}"
                         >
        </h:commandButton>
    </h:form>
</ui:composition>


I am using JSF 2 on JBoss 6.1

------------------------------------------- UPDATE-------------------------------------------
 Thanks to BalusC on StackOverflow I have the answer. "This problem is related to JSF issue 1492." See http://stackoverflow.com/questions/7445417/why-does-fvalidatedoublerange-only-work-for-sessionscoped/7447265#7447265 for the full answer and work arounds.

Friday, July 01, 2011

JEE 6 Security - Part Two (the implementation)

Alright, I have set up authentication up in JBoss AS 6 using JAAS database (jdbc) authentication. The steps:

1) Setup the logging levels, this will save you some headaches, trust me. Don't forget to change it back once you are setup. Open up jboss-logging.xml under server/default/deploy, under the 'console-handler' tag, there is a 'level' tag, replace 'INFO' with 'TRACE'. Also, add by the other loggers the following:

      
   

2) Add your security domain. To do this create a new XML file, name it something like my-app-name-jaas-jboss-beans.xml and place it in the server/default/deploy folder. Add the following to the file:

  
    
      
        java:/jdbc/myapp
        
          select PASSWORD from USER where USERNAME=?
        
          SELECT r.NAME, 'Roles' FROM ROLE r, USER_ROLE ur, USER u WHERE
          u.USERNAME=? AND u.USERNAME=ur.USERNAME AND ur.ROLE_NAME=r.NAME
        
      
    
  

IMPORTANT: The role query has to have two coloums, the second of which is always 'Roles' exactly like stated. It's a JBoss quirk.

3) You have a security domain, now you have to tell your application to use it. Create or edit jboss-web.xml in your applications WEB-INF folder, it needs the security doman specified like so:

    /myapp
    java:/jaas/myapp-realm


4) Your application is set to use the domain now, but you haven't told it what needs securing and when to authenticate. For testing purposes I have used BASIC authentication, in reality you should use FORM based. I will leave you to research the difference. To test your security add the following to your web.xml:

        Secure Pages
        
            secure-pages
            
            /test/*
        
        
            
            MANAGER
            USER
        
    
    
        BASIC
        myapp-realm
    
    
        
        MANAGER
    
    
        
        USER
    

So I have covered authentication, and EJB 3.1 JEE authorization is covered tons everywhere. One thing lacking in the JEE world is full Identity management, i.e. something where you say identity.createUser("bob") and it will create a user in any abstracted back end user store, LDAP, Database or whatever. This tool does exist, and it is PicketLink. I haven't had a chance to play with it, but it looks promising. I would dare say it is overkill for most applications though, at least until it becomes more mainstream and simple to use.

JEE 6 Security - Part One (the research)

I am starting to look at security for my JEE 6 /EJB 3.1 application. I have to say there is plenty of information on authorization for EJB 3.x (for instance what methods/urls a user has access to etc) but very few simple articles on authentication and identity management (creating new users etc). Authentication isn't really part of the JEE spec as such, although all JEE 6 servers support JAAS.

Using a new library that handles identity management (PicketLink) sounds great, but I don't want to be stuck in a couple of years time replacing it because it is out of fashion. I also want to try not to use Spring Security, I want to stick with JEE standards (even though Spring Security is a pseudo standard).

I hope to follow this up with how I managed to get authentication setup using JAAS and probably JDBC/Database credentials, and how I create new users.

As a side note, I found a good article for Seven Security (Mis)Configurations in Java web.xml Files. Definitely worth a read.

Tuesday, May 24, 2011

Using CDI Beans in your Faces Converter

Unfortunately, you cannot use @Inject within your FacesConverter. This becomes a problem when you want to convert, say, countries loaded from your database and cached in a context such as @ApplicationScoped. There are two answers here:

Option 1: If using JBoss
If you are using JBoss, just use Seam Faces. Just by including the library you can use the @Inject annotation, as well as @PostConstruct. Very Handy. If you are using Maven, just add this to your pom.xml:
<dependency>
<groupId>org.jboss.seam.faces</groupId>
<artifactId>seam-faces</artifactId>
<version>3.0.1.Final</version>
</dependency>
That is it! You can stop reading now :).

Option 2: If using GlassFish
Unfortunately, Glass fish 3.1 has a bug with the class loader, see:
Using Seam Faces exposes the bug. According to the bug report, 'you need to add dependencies to the classpath to satisfy any class that is referenced in a bean archive'. Not only annoying, but I couldn't get it to work even when dependencies where in the pom, it was one issue after another. Until GlassFish 3.1.1 I would recommend creating a simple Service Locator to lookup the CDI beans.

public class CDIServiceLocator {
    private static BeanManager getBeanManager() {
        try {
            InitialContext initialContext = new InitialContext();
            return (BeanManager) initialContext.lookup("java:comp/BeanManager");
        }
        catch (NamingException e) {
            throw new RuntimeException("Couldn't find BeanManager in JNDI");
        }
    }

    public static Object getBeanByName(String beanName) {
        BeanManager bm = getBeanManager();
        Set beans = bm.getBeans(beanName);
        if (beans == null || beans.isEmpty()) {
            return null;
        }
        Bean bean = beans.iterator().next();
        CreationalContext ctx = bm.createCreationalContext(bean);
        Object o = bm.getReference(bean, bean.getClass(), ctx);
        return o;
    }
}

You can then use the ServiceLocator to lookup beans like so:
countries = (List<country>) CDIServiceLocator.getBeanByName("countries");

This is a hack, no doubt about it. But until GlassFish 3.1.1 comes out, I believe its the best option - unless you can switch to JBoss. Big thanks to dominickdorn.com whose code and info this is largely based from.