The answer is YES, with a little help from JNDI lookup.
I just removed the CustomerControllerConverter from the JSF @RequestScoped CustomerController, created the converter class, marked it with @Singleton @Lock(READ), and referenced the @Stateless EJB via JNDI lookup. See below.
package converter;
import java.util.concurrent.TimeUnit;
import javax.ejb.AccessTimeout;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Singleton;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.naming.InitialContext;
import jpa.entities.Customer;
import jpa.session.CustomerFacade;
/**
*
* @author Administrator
*/
@Singleton
@Lock(LockType.READ)
@AccessTimeout(value = 1, unit = TimeUnit.MINUTES)
@FacesConverter(forClass = Customer.class)
public class CustomerConverter implements Converter {
public CustomerConverter() {
}
public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
if (value == null || value.length() == 0) {
return null;
}
/*
* 2012-07-10 when user enters invalid/incomplete value (e.g. "irene", see below) in AutoComplete
*
WARNING: For input string: "irene"
java.lang.NumberFormatException: For input string: "irene"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:492)
at java.lang.Integer.valueOf(Integer.java:582)
...
...
at org.primefaces.component.autocomplete.AutoCompleteRenderer.getConvertedValue(AutoCompleteRenderer.java:529)
at javax.faces.component.UIInput.getConvertedValue(UIInput.java:1030)
at javax.faces.component.UIInput.validate(UIInput.java:960)
*
*/
try {
Integer test = getKey(value);
} catch (java.lang.NumberFormatException e) {
return null;
}
Object object = null;
CustomerFacade ejbFacade;
try {
InitialContext ic = new InitialContext();
ejbFacade = (CustomerFacade) ic.lookup("java:global/appWARFileNameOrAppContextName/CustomerFacade");
if (ejbFacade == null) {
System.err.println("CustomerConverter.getAsObject(): ejbFacade = null)");
return null;
}
} catch (Exception e) {
System.err.println("CustomerConverter.getAsObject(): error on JNDI lookup of CustomerFacade");
e.printStackTrace();
return null;
}
try {
object = ejbFacade.find(getKey(value));
} catch (Exception e) {
System.err.println("CustomerConverter.getAsObject(): error on ejbFacade.find(getKey(value))");
e.printStackTrace();
return null;
}
return object;
}
java.lang.Integer getKey(String value) {
java.lang.Integer key;
key = Integer.valueOf(value);
return key;
}
String getStringKey(java.lang.Integer value) {
StringBuffer sb = new StringBuffer();
sb.append(value);
return sb.toString();
}
public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
if (object == null) {
return null;
}
if (object instanceof Customer) {
Customer o = (Customer) object;
return getStringKey(o.getCustomerId());
} else {
throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + Customer.class.getName());
}
}
}
LESSON LEARNED: ejbFacade could NOT be referenced or instantiated via the following:
@Inject, @EJB, BeanManager
References:
Oracle blogs
- Ken Saks's Blog: Application-specified Portable JNDI Names
- Ken Saks's Blog: Portable Global JNDI Names
TomEE JavaEE Examples - Referencing EJBs
Ultimately, I had to refer to the server.log file of Glassfish, the Reference Implementation (RI), to see a sample of JNDI lookup path for my @Stateless EJB's, since I used Glassfish, in the past. :)
UPDATE:
You can also find the portable global JNDI name in TomEE/catalina log. It will look like this, below.
Apr 13, 2013 10:00:58 AM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=CustomerFacadeLocalBean) --> Ejb(deployment-id=CustomerFacade)
Apr 13, 2013 10:00:58 AM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=global/webApp/CustomerFacade!jpa.session.CustomerFacade) --> Ejb(deployment-id=CustomerFacade)
Apr 13, 2013 10:00:58 AM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=global/webApp/CustomerFacade) --> Ejb(deployment-id=CustomerFacade)
where 'webApp' in the global JNDI name may be the name of your WAR filename or possibly EJB JAR filename, etc...
Hope this helps others!