Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Wednesday, September 23, 2009

Straight talk with ActiveMQ

I found that filling an ActiveMQ queue through a cfml gateway was extremely inefficient when sending a large number of messages at once. Here is the code to send messages directly to the queue via java. This was a little difficult to find this documented anywhere. I had to pull in bits an pieces from different code examples.
<cfset mess = structnew() />

<cfquery name="rs" datasource="dsn">
select id from mytable
</cfquery>

<cfscript>
connectionFactory = createobject(
'java'
,'org.apache.activemq.ActiveMQConnectionFactory'
).init('','', 'tcp://#amqServer#:#amqPort#?jms.useAsyncSend=true');

connection = connectionFactory.createConnection();
connection.start();
// createSession(transacted, session.auto_acknowledge)
javasession = connection.createSession(false, 1);
destination = javasession.createQueue("queuename");
producer = javasession.createProducer(destination);
</cfscript>

<cfloop query="rs">
<cfset mess.agentid = rs.id />
<cfwddx action="cfml2wddx" input="#mess#" output="strMess">

<!--- Send message to activeMQ through our opened channel --->
<cfscript>
message = javasession.createTextMessage(strMess);
producer.send(destination,message);
</cfscript>
</cfloop>

<!--- close up connections with activeMQ now that we are done with the channel --->
<cfscript>
producer.close();
javasession.close();
connection.close();
</cfscript>
Blessings,
Terry

Monday, September 22, 2008

Undocumented Goodness

In working on a project the other day, I needed to allow users to interact with data in such a way that they were not tripping over each other. This led me down the path toward a proof of concept with monitoring sessions for a particular application. The problem is that when you "touch" the sessionScope methods it will reset the session timeout and keep dead sessions alive. This can be countered by calling the methods using reflection like so:
<cfset tracker=createObject("java","coldfusion.runtime.SessionTracker")>
<cfset sessions=tracker.getSessionCollection(application.applicationname)>
<cfoutput>
<cfloop item="loopSession" collection="#sessions#">
Idle Time:
#getSessionProxy(sessions[loopsession],'getTimeSinceLastAccess')#<br/>
</cfloop>
</cfoutput>

<cffunction name="getSessionProxy"
output="false" access="public" returntype="string">

<cfargument name="session" required="true" type="struct" />
<cfargument name="method" required="true" type="string" />

<cfset var _a = arrayNew(1)/>
<cfset var _sessionClass =
_a.getClass().forName("coldfusion.runtime.SessionScope") />

<cfset var _method = ''/>
<cfset var _value = ''/>
<cftry>
<cfset _method =
_sessionClass.getMethod(arguments.method, _a) />
<cfset _value = _method.invoke(arguments.session, _a)/>
<cfcatch><!--- Do Nothing ---></cfcatch>
</cftry>
<cfreturn _value />
</cffunction>

That works great and is very valuable data, but what if you need to find out what the session.idofuser is on one of those sessions or another session variable that you need access too? There really is no reflected function that gives you access to those variables without touching the session timeout. You could do sessions[loopSession].idofuser but that would trip the session. Even a cfdump of the sessions collection trips the session. I couldn't find this documented on blogs or anywhere else, but there is a new sessionScope method going by the name of "getValueWIthoutChange". This must be new in CF8. I'm guessing one reason it was added is for the server monitor which gives you access to this info without touching the session timeout. If you google this method, you get absolutely 0 results. When I saw that in the dump of the sessionScope class, I knew there was hope. Important to note too is that Java is very case sensitive. Notice that the W and I are capped in "WIthout". Typo that made it through? Anywho, my next challange was finding the correct casting and such to be able to pass a var into the reflected getValueWIthoutChange method from CF. I flailed on this for about a day before I took this to a co-worker that was a java guy in a past life. He had it nailed down for me in a 1/2 hour or so. Long story short, we ended up with a method that will allow you to get any session var without touching the sessions. This is a beautiful thing and opens up all kinds of possibilities.
<cfset tracker=createObject("java","coldfusion.runtime.SessionTracker")>
<cfset sessions=tracker.getSessionCollection(application.applicationname)>
<cfoutput>
<cfloop item="loopSession" collection="#sessions#">
Idle Time:
#getSessionProxy(sessions[loopsession],'getTimeSinceLastAccess')#<br/>
User ID:
#getSessionValue(sessions[loopsession],'idofuser')#<br/><br/>
</cfloop>
</cfoutput>
<cffunction name="getSessionValue"
output="false" access="public" returntype="any">
<cfargument name="session" required="true" type="struct" />
<cfargument name="key" required="true" type="string" />

<cfset var a = arrayNew(1)/>
<cfset var valueMethod = ''/>
<cfset var value = ''/>
<cfset var sessionClass =
a.getClass().forName("coldfusion.runtime.SessionScope") />

<cftry>
<cfset a[1] =
CreateObject("java","java.lang.String").GetClass()/>
<cfset valueMethod =
sessionClass.getMethod("getValueWIthoutChange",a) />
<cfset a[1] =
CreateObject("java","java.lang.String").Init(arguments.key)/>
<cfif findnocase(arguments.key,structkeylist(arguments.session))>
<cfset value = valueMethod.invoke(arguments.session, a)/>
<cfelse>
<cfset value = ''/>
</cfif>

<cfcatch><!--- Do Nothing ---></cfcatch>
</cftry>
<cfreturn value />
</cffunction>
<cffunction name="getSessionProxy"
output="false" access="public" returntype="string">

<cfargument name="session" required="true" type="struct" />
<cfargument name="method" required="true" type="string" />

<cfset var _a = arrayNew(1)/>
<cfset var _sessionClass =
_a.getClass().forName("coldfusion.runtime.SessionScope") />

<cfset var _method = ''/>
<cfset var _value = ''/>
<cftry>
<cfset _method =
_sessionClass.getMethod(arguments.method, _a) />
<cfset _value = _method.invoke(arguments.session, _a)/>
<cfcatch><!--- Do Nothing ---></cfcatch>
</cftry>
<cfreturn _value />
</cffunction>

Now, as an important note and as has been echoed on other blogs, this is an undocumented method and the farm should not be bet on it. There is no guarantee that it will live on in other versions of CF so use wisely.

With that said, praise God for technology and go change the world.

Blessings...