Basic Weld example with Embedded Tomcat not working - java

I am trying to use Weld with Embedded Tomcat (10.1.5) using a basic example and settings from official weld docs.
This weld injection with same code works fine with Tomcat on Eclipse.
However, on Embedded Tomcat, the injected bean is always null. If I try to lookup BeanManager using JNDI it throws this error:
//code
Context initContext = new InitialContext();
bm = (BeanManager) ((Context) initContext.lookup("java:comp/env")).lookup("BeanManager");
Exception: javax.naming.NamingException: WELD-001300: Unable to locate BeanManager
Added BeanManager entries to context.xml, web.xml, and empty beans.xml to WEB-INF.
gradle dependency:
implementation group: 'org.jboss.weld.servlet', name: 'weld-servlet-core', version: '5.1.0.Final'
main class:
Tomcat tomcat = new Tomcat();
String webappDirLocation = "src/main/webapp/";
Context ctx = tomcat.addWebapp("/", new File(webappDirLocation).getAbsolutePath());
// declare an alternate location for your "WEB-INF/classes" dir:
File additionWebInfClasses = new File("build/classes/java/main/");
WebResourceRoot webResourceRoot = new StandardRoot(ctx);
webResourceRoot.addPreResources(
new DirResourceSet(webResourceRoot, "/WEB-INF/classes", additionWebInfClasses.getAbsolutePath(), "/"));
ctx.addApplicationListener(Listener.class.getName());
tomcat.enableNaming();
tomcat.getConnector();
tomcat.start();
tomcat.getServer().await();
What is the issue here? What extra setting is needed to use Weld with Embedded Tomcat ?
There is a curious difference in Weld startup logs too:
// Embedded Tomcat
Jan 26, 2023 11:50:56 PM org.jboss.weld.environment.servlet.WeldServletLifecycle initialize
// Tomcat with Eclipse
Jan 26, 2023 11:56:43 PM org.jboss.weld.environment.tomcat.TomcatContainer initialize

The Weld example was missing setResources() call which is needed to initialize this properly.
...
WebResourceRoot webResourceRoot = new StandardRoot(ctx);
webResourceRoot.addPreResources(
new DirResourceSet(webResourceRoot, "/WEB-INF/classes", additionWebInfClasses.getAbsolutePath(), "/"));
// this was missing
ctx.setResources(webResourceRoot);
...
This is also easy to miss due to lack of documentation on embedded Tomcat.

Related

How to modify JNDI Custom Resources Properties Values on the fly

My architecture:
GlassFish Server Open Source Edition 3.1.2.2 (5)
Java EE 6
Eclipse IDE
I created a EJB Timer, which prints a log message:
#Startup
#Singleton
public class ProgrammaticalTimerEJB {
private final Logger log = Logger.getLogger(getClass().getName());
#Resource(name = "properties/mailconfig")
private Properties mailProperties;
#Resource
private TimerService timerService;
#PostConstruct
public void createProgrammaticalTimer() {
log.log(Level.INFO, "ProgrammaticalTimerEJB initialized");
ScheduleExpression everyTenSeconds = new ScheduleExpression().second("*/10").minute("*").hour("*");
timerService.createCalendarTimer(everyTenSeconds, new TimerConfig("passed message " + new Date(), false));
}
#Timeout
public void handleTimer(final Timer timer) {
log.info(new Date().toGMTString() + " Programmatical: " + mailProperties.getProperty("to"));
}
}
This class injects my custom JNDI Resource:
#Resource(name = "properties/mailconfig")
private Properties mailProperties;
Eclipse Console:
INFO: 2 Aug 2013 10:55:40 GMT Programmatical: tim.herold#mylocal.de
INFO: 2 Aug 2013 10:55:50 GMT Programmatical: tim.herold#mylocal.de
INFO: 2 Aug 2013 10:56:00 GMT Programmatical: tim.herold#mylocal.de
Glassfish settings
asadmin> get server.resources.custom-resource.properties/mailconfig.property
server.resources.custom-resource.properties/mailconfig.property.to=tim.herold#mylocal.de
Command get executed successfully.
asadmin>
Now i want to change this property value during application runtime.
Editing it via Adminconsole or Asadmin doesnt work.
Is this possible, or is there an other/better soulution?
Many thanks in advance
There is a possibility to solve your problem:
If an application uses resource injection, the GlassFish Server invokes the JNDI API, and the application is not required to do so.
Once injected the properties are not reloaded and there is no direct posibility to reload the resource by default.
However, it is also possible for an application to locate resources by making direct calls to the JNDI API.
You need to do a JNDI Lookup for your Custom Resoruce, either scheduled or everytime before using the properties. This code worked for me:
#Timeout
public void handleTimer(final Timer timer) throws IOException, NamingException {
Context initialContext = new InitialContext();
mailProperties = (Properties)initialContext.lookup("properties/mailconfig");
log.info(new Date().toGMTString() + " Programmatical: " + mailProperties.getProperty("to"));
}
According to my understanding, the mailProperties resource is injected after the EJB is instantiated by the container which only occurs one time in the lifecycle of bean.
Therefore, futures properties changes are not available to him.
An alternative could be to try to lookup the mailProperties inside #Timeout method.

JAX-WS & Tomcat: storing in InitialContext not possible?

Intro I'm writing a web service using JAX-WS, and deploying it in Tomcat. With a lot of difficulties I finally had some code written.
Problem Unfortunately, when trying to run it I get the following error:
Context is read only
Setting I'm writing a web service that queries multiple databases and returns a single result. For that purpose, in the init() method (marked with #PostConstruct), I create a series of DataSources that I add to the context.
This is how I create the pool (based on Tomcat documentation) and after its creation I add it to the context (based on this tutorial):
#PostConstruct
private void init(){
PoolProperties props = new PoolProperties();
props.setUrl("jdbc:postgresql://" + ...);
props.setUsername(...);
props.setPassword(...);
props.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;" +
"org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
DataSource dataSource = new DataSource();
dataSource.setPoolProperties(propos);
Context ctx = new InitialContext(env);
ctx.bind("java:/comp/env/dbpool", dataSource);
}
And later I use it:
#WebMethod
public Result performQuery(QueryParameters params){
Context ctx = new InitialContext(env);
(DataSource) source = (DataSource) ctx.lookup("java:/comp/env/dbpool");
}
I deploy the web service on a Tomcat 7 server.
Question I understand after Google-ing that I cannot write into the Context on Tomcat. But how else could I solve this? From what I understand about JAX-WS I cannot just have a private variable holding a DataSource, right? I have to pass that DataSource using a Context, right?
The InitialContext is writable from the Tomcat code only, not from your client code. You must add your DataSource to your context.xml and it'll work.

Creation of context fail when JUNIT test is launched

I created a small junit test that is launched from my application client.
My server is glassfish 3.1.1 .
When i run the test i get this error:
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
I have already added the propreties to the context but nothing changed.
This how i set up my context:
#Before
public void setUp() throws NamingException {
Properties props = new Properties();
System.out.println("launch");
props.setProperty("java.naming.factory.initial",
"com.sun.enterprise.naming.SerialInitContextFactory");
props.setProperty("java.naming.factory.url.pkgs",
"com.sun.enterprise.naming");
props.setProperty("java.naming.factory.state",
"com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
// optional. Defaults to localhost. Only needed if web server is running
// on a different host than the appserver
//props.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
// optional. Defaults to 3700. Only needed if target orb port is not 3700.
//props.setProperty("org.omg.CORBA.ORBInitialPort", "3700");
Context annuaire = new InitialContext(props);
GeoBeanRemote service = (GeoBeanRemote) annuaire.lookup(GeoBeanRemote.class.getName());
BeanProvider.setGeoBean(service);
}
app-serv.rt and gf-client are added to my run-test.
Thanks.
I've the same issue when jndi.properties was missing from my classpath.
Addendum:
I'm feeling a bit silly here, but I don't think you can set your initial context that way. I note though that JNDI properties don't even need to be set on Glassfish, so color me confused.

Tomcat +jndi.properties

i have a problem with JNDI in Tomcat:
without tomcat I have used JNDI as following:
Context context = new InitialContext();
JVoiceXml jvxml = (JVoiceXml) context.lookup("JVoiceXml");
And jndi.properties :
java.naming.factory.initial=com.sun.jndi.rmi.registry.RegistryContextFactory
java.naming.provider.url=rmi://localhost:1099
java.naming.rmi.security.manager=true
Now I want to use this code in my Web Application(deployed with Tomcat), I have changed the code to:
Context context = new InitialContext();
Context envCtx = (Context) context.lookup("java:comp/env");
JVoiceXml jvxml = (JVoiceXml) envCtx.lookup("JVoiceXml");
In web.xml:
<resource-env-ref>
<resource-env-ref-name>
JVoiceXml
</resource-env-ref-name>
<resource-env-ref-type>
org.jvoicexml.JVoiceXml
</resource-env-ref-type>
</resource-env-ref>
And in context.xml:
<Resource name="JVoiceXml" auth="Container"
type="org.jvoicexml.JVoiceXml"
factory="com.sun.jndi.rmi.registry.RegistryContextFactory"
url="rmi://localhost:1099"/>
What I have missed, because after lookup() my JVoiceXml is null
Your Tomcat code is not equivalent to what you wrote outside Tomcat. All you've done in the Tomcat case is name an RMI Registry context factory as JVoiceXML. That doesn't seem to make sense: the RMI Registry has nothing to do with XML. I suspect you don't need the java:comp/env stuff at all here. Presumably you have an RMI Registry running somewhere: just look it up with Naming.lookup(). If you want it to act as a Tomcat Resource, you need to define a factory that can create it. That needs to be an instance of javax.naming.spi.ObjectFactory (?). That may in turn do a Naming.lookup(), or a JNDI lookup, outside the java:comp/env namespace.

Object reference lookup from JNDI results in ClassCastException

I'm having problems calling EJB3 stateless bean outside the container.
Code for getting the object reference:
Context envCtx = (Context) context.lookup("ejb");
MyObject o = (MyObject) envCtx.lookup(MyObject);
The second row results in exception:
java.lang.ClassCastException: javax.naming.Reference
I use JBoss.org 5.1.0 GA.
Based on some other posts I suspect this might be due to wrong version of client libraries. However, I'm unsure which library jar(s) I should include in the jar? (I get the error using 5.0.4.GA jnpserver.)
For JBoss, your code should look something like that:
Properties properties = new Properties();
properties.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
properties.put("java.naming.factory.url.pkgs","=org.jboss.naming:org.jnp.interfaces");
properties.put("java.naming.provider.url","localhost:1099");
Context context = new InitialContext(properties);
(EchoBeanRemote) c.lookup("EchoBean/remote");
If you prefer, you can put the JNDI environement settings in a jndi.properties file (that needs to be on the classpath):
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=jnp://localhost:1099
And use the non-arg InitialContext constructor:
Context context = new InitialContext();
(EchoBeanRemote) c.lookup("EchoBean/remote");
This is obviously more portable.
And in both case, you'll need jbossall-client.jar on the classpath on the client side.
P.S.: You can check the Global JNDI Name your bean is registered at in the JNDI View of the web-based JMX console (if it still exists).

Categories

Resources