PHP ODBC Across Networked Drives

While integrating some backend services needed by our RIA I ran across a small hiccup that was easily fixed but I thought I’d post in case someone else get’s stumped by this (apparently some already have ).

Problem:

PHP needed access to and ODBC connection that pointed to a dBase III database on a remote server. While local applications could use this ODBC connection flawlessly, connection via PHP failed.

Symptons:

Warning: odbc_connect() [function.odbc-connect]: SQL error: [Microsoft][ODBC dBase Driver] ‘(unknown)’ is not a valid path.

Solution:

You need to enable rights for the Apache Service to have access to the remote directory.

For my particluar situation the server running apache and php was not part of the domain, so I simply right clicked on the apache service, navigated to the Log On tab and selected “This Account” (and filled in the administrator credentials) as opposed to the default “Local System Account.”

Flex Modules Watch Your Scope

Here’s another help hint for those working with Modules in Flex: Watch your variable scope!!

When loading modules, you have a number of options for loading the SWF including the ModuleLoader and ModuleManager. If neither of those fit your needs you always have access to Flash’s Loader class. ModuleManger can be used for fine grained control of the loading process. Either way, variable scope plays a crucial roll in the loading process.

Here’s an example using ModuleLoader…

public function loadSWFModule(swfURL:String):void
{
var moduleLoader:ModuleLoader = new ModuleLoader();
moduleLoader.url = swfURL;

moduleLoader.addEventListener(ModuleEvent.READY,onModuleLoaded);
moduleLoader.addEventListener(ModuleEvent.ERROR,onModuleError);
moduleLoader.addEventListener(ModuleEvent.PROGRESS,onProgress);
moduleLoader.loadModule();
}

The moduleLoader is declared as a local variable. As it turns out this will cause problems, even with the ‘strong’ event listeners. For those not wanting to read the technical details to follow, simply use avoid using a locally scoped variable.

The following are some of the symptoms you may run into using the latter locally scoped variable:

To help those searching the net, I’ll be a bit redundant in the ‘symptom’ descriptions so hopefully you’ll find this post if you’ve stumbled upon this problem

Symptons

  • The module fails to load the first time, but loads successfully the second time.
  • The ModuleEvent.READY is never dispatched
  • The ModuleInfoProxy never picks up the ModuleEvent.READY dispatched by ModuleInfo
  • ModuleInfo.clearLoader() throws an error (which is quietly caught), Error #2029: This URLStream object does not have a stream opened when calling loader.close()
  • The problem comes in when the Loader finishes loading the SWF. ModuleInfo’s internal listener list (listeners attached during ModuleInfoProxy’s constructor) are lost (i.e. null) when ModuleInfo finally reaches it’s readyHandler( ) method. At the end of the readyHandler( ), a ModuleEvent.READY event is dispatched.

    dispatchEvent(new ModuleEvent(ModuleEvent.READY));

    With the listener list being null, the event is never picked up by the ModuleInfoProxy and the initial load fails.

    On subsequent loads (i.e. the second time) ModuleInfoProxy’s load( ) method checks to see if the info has already been loaded and dispatches the ModuleEvent.READY event directly.

    else if (info.loaded)
    {
    //trace("Module[", url, "] load is already loaded");
    if (info.setup)
    {
    ...
    if (info.ready)
    {
    ...
    dispatchEvent(new ModuleEvent(ModuleEvent.READY));
    }
    }
    }

    Causing the load to ‘work’ the second time.

    My understanding is that Garbage Collection is often invoked when a module is loaded. It looks like it’s the cause of this behavior (the listeners being lost). I assumed that the ‘strong’ listeners would be enough to keep the GC away, oh well.

    Again the solution is simple, make sure your not using a locally scoped variable when loading modules.

    Flex, Java Remoting, and JMS [null message body]

    So I was pounding out some code this afternoon, ran into a small snag and thought I’d post. Neuro-physiologists tell us that we better remember what we write down so here goes.

    Similar to my post a few months ago, I made a simple omission in my coding flurry.

    I was working with a backend Java class that published messages to [ActiveMQ] JMS. I wrote up a simple VO class to publish via JMS.


    package com.dl.sifagents.vo;

    import java.io.Serializable;

    public class ZISEventVO implements Serializable
    {
    public String eventType = "";
    public String payloadPackage = "";
    public String payloadElement = "";
    public String xml = "";
    }

    On the Flex side, I wrote up an AS3 implementation


    package com.dl.sifagents.vo
    {
    [RemoteClass(alias="com.dl.sifagents.vo.ZISEventVO")]
    [Bindable]
    public class ZISEventVO
    {
    public var eventType:String;
    public var payloadPackage:String;
    public var payloadElement:String;
    public var xml:String;
    }
    }

    I published the VO to JMS…


    public void publishObjectToJMS(Serializable o)
    {
    try {
    ObjectMessage message = _pubSession.createObjectMessage();
    message.setObject(o);
    _publisher.publish(message, Message.DEFAULT_DELIVERY_MODE, Message.DEFAULT_PRIORITY, 5 * 60 * 1000);
    } catch (JMSException e1) {
    e1.printStackTrace();
    }
    }

    I received the JMS message in Flex (via BlazeDS) but the message body was null. I checked and doubled checked my Java VO implementation vs AS3 VO implementation and couldn’t find any naming conflicts or errors.

    Then it hit me, in my haste I’d forgotten to upload the Java VO class to BlazeDS (i.e. to the WEB-INF/classes folder)!

    That’s my piece of humble pie for the week 🙂 Back to work.

    Dashboards…Flex's Sweet Spot

    Thanks Adobe!!!

    I’ve taken on a number of Flex projects over the past 2-3 years. In that time I’ve used Flex to meet many types of business needs. I’ve spent the last few months working on a enterprise dashboard application built with Flex. This past week the time came for the executives’ ‘sneek peek’ of the project’s progress. The feedback, in their words,

    “Beyond all expectation.”

    I can’t remember having more fun architecting and implementing a project. Dashboards seem to be Flex’s ‘sweet spot’, IMHO. Adobe [Flex] provides so rich a toolset for this type of project, one can’t help but have fun working on dashboards with Flex. Talking with other local Flex developers only resonates the view that Flex + Dashboards are a perfect fit. So once again, thanks to Adobe for this great product, it’s been an absolute joy to work with.

    FYI, the project is using Flex, AMFPHP 1.9, ActiveMQ JMS + BlazeDS, Multicore PureMVC, PureMVC’s Pipes, MySQL to name a few (i.e. a mouthful of open source technologies). BTW, it scales beautifully with dynamic modules using PureMVC Pipes. Thanks too, to Cliff Hall for PureMVC!!

    For those pessimists our there, I can post again once I’ve developed the printouts (Printing is notoriously painful in Flex :)).

    [Tunkey] BlazeDS JMS ActiveMQ

    I spent some time this week with BlazeDS and JMS. I wanted to integrate a Flex RIA with some [existing] backend Java classes. One goal was to interface the two in a loosely coupled fashion, enter Java Message Service (JMS).

    The RIA uses a mx:producer to publish messages to a JMS topic which the backend Java class is listening in on [consuming] elsewhere in the enterprise. I used an ‘external install’ of ActiveMQ.

    I downloaded the turnkey BlazeDS server to get things rolling.

    I came across a few great posts in looking into this…

    Michael Martin’s Simplified BlazeDS and JMS

    Christophe Coenraets
    Flex and JMS: Portfolio Viewer (LCDS jRun)
    30 Minutes Flex Test-Drive for Java Developers (FDS)

    To be helpful, I’ve included some error messages and their causes:

    Flex Runtime Error:
    There was an unhandled failure on the server. MessageClient has been invalidated.
    Cause: ActiveMQ not running.

    Flex Runtime Error:
    Client.Message.Encoding
    Type ‘com.dl.samples.PersonVO’ not found.
    Cannot create class of type ‘com.dl.samples.PersonVO’.
    Cause: Java classes not on server.

    Java Runtime Error
    javax.naming.NameNotFoundException: messageTopic
    at org.apache.activemq.jndi.ReadOnlyContext.lookup(ReadOnlyContext.java:225)
    at javax.naming.InitialContext.lookup(Unknown Source)
    at Chat.(Chat.java:55)
    at Chat.main(Chat.java:27)
    Cause: jndi.properties not present for java class

    Java Runtime [BlazeDS] Error
    [BlazeDS] JMS consumer for JMS destination ‘[destinationName]’ is being removed from the JMS adapter due to the following error: Name jms is not bound in this Context
    [BlazeDS] JMS consumer for JMS destination ‘[destinationName]’ is stopping.
    [BlazeDS] The corresponding MessageClient for JMS consumer for JMS destination ‘[destinationName]’ is being invalidated

    Cause: context.xml Resource names do not match messaging-config.xml connection-factory / destination-jndi-name tags. (i.e. the ‘org.apache.activemq.ActiveMQConnectionFactory’ resource name in context.xml should match the connection-factory value in messaging-config and the ‘org.apache.activemq.command.ActiveMQTopic’ resource name in context.xml should match the destination-jndi-name value in messaging-config).

    Adding the logging pattern ‘Service.Message.JMS’ to your services-config.xml can be very helpful in debugging BlazeDS JMS problems.

    Here are the config files

    C:/blazeds/tomcat/webapps/MyApp/WEB-INF/flex/services-config.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <services-config>
    <services>
    <service-include file-path="messaging-config.xml" />
    </services>
    <security/>
    <channels>
    <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
    <endpoint url="http://localhost:8400/BlazeTest/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
    </channel-definition>
    </channels>
    <logging>
    <target class="flex.messaging.log.ConsoleTarget" level="Debug">
    <properties>
    <prefix>[BlazeDS] </prefix>
    <includeDate>false</includeDate>
    <includeTime>false</includeTime>
    <includeLevel>false</includeLevel>
    <includeCategory>false</includeCategory>
    </properties>
    <filters>
    <pattern>Endpoint.*</pattern>
    <pattern>Service.*</pattern>
    <pattern>Configuration</pattern>
    <pattern>Service.Message.JMS</pattern>
    </filters>
    </target>
    </logging>
    </services-config>

    C:/blazeds/tomcat/webapps/MyApp/WEB-INF/flex/messaging-config.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <service id="message-service" class="flex.messaging.services.MessageService">
    <adapters>
    <adapter-definition id="actionscript" class="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" />
    <adapter-definition id="jms" class="flex.messaging.services.messaging.adapters.JMSAdapter"/>
    </adapters>
    <default-channels>
    <channel ref="my-amf"/>
    </default-channels>
    <destination id="simpleJMS">
    <properties>
    <jms>
    <destination-type>Topic</destination-type>
    <!--<message-type>javax.jms.TextMessage</message-type>-->
    <message-type>javax.jms.ObjectMessage</message-type>
    <connection-factory>java:comp/env/TopicConnectionFactory</connection-factory>
    <destination-jndi-name>java:comp/env/messageTopic</destination-jndi-name>
    <delivery-mode>NON_PERSISTENT</delivery-mode>
    <message-priority>DEFAULT_PRIORITY</message-priority>
    <acknowledge-mode>AUTO_ACKNOWLEDGE</acknowledge-mode>
    <initial-context-environment>
    <property>
    <name>Context.INITIAL_CONTEXT_FACTORY</name>
    <value>org.apache.activemq.jndi.ActiveMQInitialContextFactory</value>
    </property>
    <property>
    <name>Context.PROVIDER_URL</name>
    <value>tcp://localhost:61616</value>
    </property>
    </initial-context-environment>
    </jms>
    </properties>
    <channels>
    <channel ref="my-amf"/>
    </channels>
    <adapter ref="jms"/>
    </destination>
    </service>

    C:/blazeds/tomcat/webapps/MyApp/WEB-INF/web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
    <web-app>
    <display-name>BlazeDS</display-name>
    <description>BlazeDS Application</description>
    <!-- Http Flex Session attribute and binding listener support -->
    <listener>
    <listener-class>flex.messaging.HttpFlexSession</listener-class>
    </listener>
    <!-- MessageBroker Servlet -->
    <servlet>
    <servlet-name>MessageBrokerServlet</servlet-name>
    <display-name>MessageBrokerServlet</display-name>
    <servlet-class>flex.messaging.MessageBrokerServlet</servlet-class>
    <init-param>
    <param-name>services.configuration.file</param-name>
    <param-value>/WEB-INF/flex/services-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
    <servlet-name>MessageBrokerServlet</servlet-name>
    <url-pattern>/messagebroker/*</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    </web-app>

    C:/blazeds/tomcat/webapps/MyApp/META-INF/context.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <Context path="/BlazeTest">
    <Resource name="TopicConnectionFactory"
    type="org.apache.activemq.ActiveMQConnectionFactory"
    description="JMS Connection Factory"
    factory="org.apache.activemq.jndi.JNDIReferenceFactory"
    brokerURL="tcp://localhost:61616"
    brokerName="myBroker"/>
    <Resource name="messageTopic"
    type="org.apache.activemq.command.ActiveMQTopic"
    description="a simple topic"
    factory="org.apache.activemq.jndi.JNDIReferenceFactory"
    physicalName="messageTopic"/>
    </Context>

    Using the above messaging-config’s destination the message will come across as an ObjectMessage in Java 🙂

    Ensuring Windows Services can access Novell NetWare directories

    Ended up spending some time getting this to get this to work last week. We had some Windows services running on a Windows Server (Server 2003) that needed to access data on a NetWare volume. While a logged in user could access the data on the NetWare server, the windows service could not (or was intermittent at best).

    Here’s what I found – hope someone finds it helpful.

    Per Microsoft – Windows services should use UNC paths not Mapped Drives
    http://support.microsoft.com/kb/180362/EN-US/

    Novell’s direction on getting MS Service applications to access NetWare volumes if the service was written in a non-novell-aware manner.
    http://www.novell.com/support/viewContent.do?externalId=7000312

    After following the latter directions everything is working great.

    Time to get back to some RIA development 🙂