Thanks Aaron,
I'd like to report that I have success! I am able to fire a TextMessage
to my MDB from a Gbean with a thread! My GBean deployment plan fragment
now looks like this:
<sys:gbean class="org.acme.TimerGBean" name="TimerGBean">
<sys:attribute name="period">5000</sys:attribute>
<sys:reference name="ManagedConnectionFactoryWrapper">
<sys:name>ReminderConnectionFactory</sys:name>
</sys:reference>
<sys:reference name="AdminObjectWrapper">
<sys:name>TimerTickQueue</sys:name>
</sys:reference>
</sys:gbean>
Where ReminderConnectionFactory and TimerTickQueue were defined by
adding a JMS resource in the Admin Console. And the pertinent parts of
my GBean are as follows:
private javax.jms.ConnectionFactory connectionFactory;
private Queue queue;
public static final GBeanInfo GBEAN_INFO;
static {
GBeanInfoBuilder infoBuilder = new
GBeanInfoBuilder("TimerGBean", TimerGBean.class);
infoBuilder.addAttribute("period", int.class, true);
infoBuilder.addReference("ManagedConnectionFactoryWrapper",
ConnectionFactorySource.class,
NameFactory.JCA_MANAGED_CONNECTION_FACTORY);
infoBuilder.addReference("AdminObjectWrapper",
AdminObjectSource.class,
NameFactory.JCA_ADMIN_OBJECT);
infoBuilder.setConstructor(new String[]
{"ManagedConnectionFactoryWrapper","AdminObjectWrapper"});
GBEAN_INFO = infoBuilder.getBeanInfo();
}
public static GBeanInfo getGBeanInfo() {
return GBEAN_INFO;
}
/**
* Constructor
* @param period the period in miliseconds.
*/
public TimerGBean(ConnectionFactorySource connectionFactory,
AdminObjectSource queue) {
this.connectionFactory =
(javax.jms.ConnectionFactory)connectionFactory.$getResource();
this.queue = (Queue)queue.$getResource();
}
And finally, the MDB message sending code:
private void SendTickMessage()
{
Connection conn = null;
Session session = null;
MessageProducer producer = null;
try {
conn = connectionFactory.createConnection();
session = conn.createSession(false,Session.AUTO_ACKNOWLEDGE);
TextMessage msg = session.createTextMessage("TICK");
producer = session.createProducer(queue);
producer.send(msg);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
if (conn != null) conn.close();
} catch (Exception ex) {
}
try {
if (session != null) session.close();
} catch (Exception ex) {
}
try {
if (producer != null) producer.close();
} catch (Exception ex) {
}
}
}
This is complete with the finally block to clean things up and the
mandatory exception handling around everything.
The combination of what you said and what David said allowed me to do
the final Queue linkage using the AdminObjectSource class. Thanks very
much for your detailed help with this GBean injection.
Cheers.
-Neal
Aaron Mulder wrote:
<sys:reference name="IS THIS RELATED TO THE GBEAN INFO?">
Yes, you need to add a reference to your GBeanInfo with this name, and
then either add a constructor argument or a setter on the GBean class.
David pointed to configs/system-database/src/plan/plan.xml, which has
this:
<gbean name="NonTransactionalThreadPooledTimer"
class="org.apache.geronimo.timer.jdbc.JDBCStoreThreadPooledNonTransactionalTimer">
...
<reference
name="ManagedConnectionFactoryWrapper"><name>SystemDatasource
</name></reference>
Now if you look in the class
JDBCStoreThreadPooledNonTransactionalTimer, the GBean info contains:
infoFactory.addReference("ManagedConnectionFactoryWrapper",
ConnectionFactorySource.class,
NameFactory.JCA_MANAGED_CONNECTION_FACTORY);
Then
infoFactory.setConstructor(new
String[]{"ManagedConnectionFactoryWrapper", ...
And if you look in the constructor
public JDBCStoreThreadPooledNonTransactionalTimer(ConnectionFactorySource
managedConnectionFactoryWrapper, ...
So this is how the reference works -- you add it to your GBeanInfo
with a name and class, then either just add a setter method, or list
it by name as a constructor argument in the GBean info and add the
actual constructor arg. Either the setter type or constructor arg
type should match the class argument to the GBeanInfo addReference.
The name of the reference in the plan should match the name of the
reference in the GBeanInfo. The connection factory class is
ConnectionFactorySource, and I expect the destination class to use
would be AdminObjectSource.
<sys:name>WHAT IS THIS?</sys:name>
This should match the connectiondefinition-instance/name for the
connection factory, and I think the
adminobject-instance/message-destination-name for the admin object.
Thanks,
Aaron
On 6/11/06, Neal Sanche <[EMAIL PROTECTED]> wrote:
Thanks David,
I've looked for the examples you mention, and probably because it's
late, but I'm not getting it. Let's see if I can follow it at least a
little. I can't use JNDI, that much is clear. The only thing in the
GBean's JNDI is the JMXConnector object.
So, you're saying that I can use constructor dependency injection
instead. So, in my <sys:gbean>, I would have to add a couple of
<sys:reference> tags, the question is what do I use for the 'name'
attribute and the <sys:name> child element of those references?
Then, after I've done that, and set up the references in my GBean Info,
I can set up a constructor that takes those parameters. I've been
looking at the JDBCStoreThreadPooledNonTransactionalTimer class, which
shows exactly how to do that. That makes sense.
I guess all I need is direction on what my <sys:gbean> should look like?
<sys:gbean class="org.acme.TimerGBean" name="TimerGBean">
<sys:attribute name="period">5000</sys:attribute>
<sys:reference name="IS THIS RELATED TO THE GBEAN INFO?">
<sys:name>WHAT IS THIS?</sys:name>
</sys:reference>
</sys:gbean>
If you could tell me how to figure out the two names, I'll try it and
see if I get references to my queue and connection factories.
Thanks!
-Neal
David Jencks wrote:
> Hi Neal,
>
> This isn't going to work using jndi. We only supply the spec-required
> local jndi java:comp context to j2ee components, and there is no
> global jndi context. Therefore a gbean with a thread is not going to
> have a usable jndi context.
>
> What you can do instead is use gbean references and constructor
> dependency injection. This is a bit strange, because the gbeans
> involved are not queues or connection factories but holders for them,
> and to get the queue or connection factory you have to call a
> $getResource method on them.
>
> For instance, for the connection factory you could include in your
> gbean into and constuctor args a reference to a
> ManagedConnectionFactoryWrapper, and get the connection factory by
>
> ConnectionFactory connectionFactory = (ConnectionFactory)
> mcfWrapper.$getResource();
>
> in your constructor: similarly
> Queue queue = (Queue) adminObjectWrapper.$getResource();
>
> If you look in the system-database plan and the timer module you can
> see an example of this, the timer gbean has a reference to a
> MCFWrapper gbean and gets the datasource from it. Activemq journal
> has a similar reference to get a jdbc datasource for long-term
> persistence.
>
> Hope this helps,
> david jencks
>
>
> On Jun 10, 2006, at 10:20 PM, Neal Sanche wrote:
>
>> Hi All,
>>
>> I am doing some research for a Geronimo 1.1 tutorial I'm putting
>> together. I'm writing a little reminder application that uses an MDB
>> that is periodically sent a JMS message to wake it up to perform a
>> little database lookup and send out a bunch of reminder email
>> messages. That's the theory anyway.
>>
>> I have managed to get my MDB to deploy after creating a JMS Resource
>> Adaptor through the Admin console, and then setting up the dependency
>> and MessageDriven section in my open-ejb.xml deployment plan, that
>> looks like the following:
>>
>> <?xml version="1.0" encoding="UTF-8"?>
>> <openejb-jar xmlns="http://www.openejb.org/xml/ns/openejb-jar-2.1"
>> xmlns:nam="http://geronimo.apache.org/xml/ns/naming-1.1"
>> xmlns:pkgen="http://www.openejb.org/xml/ns/pkgen-2.0"
>> xmlns:sec="http://geronimo.apache.org/xml/ns/security-1.1"
>> xmlns:sys="http://geronimo.apache.org/xml/ns/deployment-1.1">
>> <sys:environment>
>> <sys:moduleId>
>> <sys:groupId>default</sys:groupId>
>> <sys:artifactId>ReminderBackend</sys:artifactId>
>> <sys:version>1.0</sys:version>
>> <sys:type>car</sys:type>
>> </sys:moduleId>
>> <sys:dependencies>
>> <sys:dependency>
>> <sys:groupId>console.jms</sys:groupId>
>> <sys:artifactId>ReminderMessageAdaptor</sys:artifactId>
>> <sys:version>1.0</sys:version>
>> <sys:type>rar</sys:type>
>> </sys:dependency>
>> </sys:dependencies>
>> </sys:environment>
>> <enterprise-beans>
>> <message-driven>
>> <ejb-name>TimerTick</ejb-name>
>> <nam:resource-adapter>
>> <nam:resource-link>ReminderMessageAdaptor</nam:resource-link>
>> </nam:resource-adapter>
>> <activation-config>
>> <activation-config-property>
>>
>>
<activation-config-property-name>destination</activation-config-property-name>
>>
>>
>>
<activation-config-property-value>TimerTickQueue</activation-config-property-value>
>>
>> </activation-config-property>
>> <activation-config-property>
>>
>>
<activation-config-property-name>destinationType</activation-config-property-name>
>>
>>
>>
<activation-config-property-value>javax.jms.Queue</activation-config-property-value>
>>
>> </activation-config-property>
>> </activation-config>
>> </message-driven>
>> </enterprise-beans>
>>
>> </openejb-jar>
>>
>>
>> Now, that's all good. It deploys without any warnings. Now, I want to
>> send a message to the queue. So, I thought to myself, 'Self, I'll
>> write a GBean to start a thread to send a TextMessage to the queue
>> periodically.' So I wrote one, and added the following to my
>> deployment descriptor:
>>
>> <sys:gbean class="org.acme.TimerGBean" name="TimerGBean">
>> <sys:attribute name="period">5000</sys:attribute>
>> </sys:gbean>
>>
>> I am getting called back for the start() and stop() lifecycle
>> methods, and so I wrote my thread to be interruptable, and that's all
>> working. My thread wakes up and calls the following method (ignore
>> the resource issues here, I haven't written my finally block yet):
>>
>>
>> private void SendTickMessage() {
>> System.err.println("Tick");
>> try {
>> Queue queue = TimerTickUtil.getQueue();
>> System.err.println(queue.getQueueName());
>> QueueConnection conn = TimerTickUtil.getQueueConnection();
>> Session session =
>> conn.createSession(false,Session.AUTO_ACKNOWLEDGE);
>> TextMessage msg = session.createTextMessage("TICK");
>> MessageProducer producer = session.createProducer(queue);
>> producer.send(msg);
>> } catch (Exception ex) {
>> ex.printStackTrace();
>> try {
>> InitialContext ctx = new InitialContext();
>> NamingEnumeration<NameClassPair> en =
>> ctx.list("");
>> while(en.hasMore()) {
>> NameClassPair pair = en.next();
>> System.err.println(pair.getName() + " -> "+
>> pair.getClassName());
>> }
>> } catch (Exception ex2) {
>> ex2.printStackTrace();
>> }
>> }
>> }
>>
>> Now, the problem is that TimerTickUtil.getQueue() is trying to do a
>> JNDI lookup for the queue, but I have absolutely no idea what form
>> that JNDI name will take? I ran JConsole to get some idea of the JNDI
>> namespace, but that was no good, and hence the silly code in the
>> exception handler that tries to list the entire InitialContext list.
>> But that's not giving me much to go on either.
>>
>> Can anyone tell me what the JNDI name of my queue will be from the
>> above information? Is there a sample MDB app in the source tree that
>> shows how this is done?
>>
>> I'll keep hammering at it and see if I can figure it out.
>>
>> -Neal