Whenever I revert to coding in PHP after an extended sprint in Java, I inevitably find myself somewhat frustrated by some of the shortcomings of PHP. Most of these have to do with how much less maintainable a large code-base becomes in PHP as opposed to Java. Recently, I wanted to quickly whip up a few webapps and decided to try working with the Symony PHP framework to see how quickly I could generate a webapp compared to using Struts 2 in Java.

java-v-php

I found Symfony to be a very effective and well-thought out framework. It was easy to learn and yes, it was not long before I had a functional web app online.

My issues are not with Symfony, but with PHP itself. First off is the plethora of static functions that PHP has on offer. Most of these would be encapsulated as methods of objects in Java (for instance instead of string.equals(otherString) in Java one would use in PHP the static method str_cmp(string, otherString)). This lack of encapsulation and the huge number of global methods makes for a very messy and expansive domain in which to work. Ultimately, I suppose this is a vestige of PHP’s procedural roots.

The lack of namespaces is another gripe, which further adds to the murky domain space of a PHP project. It’s not easy to see how objects relate to each other in terms of an organisational hierarchy in PHP, whereas this is a necessity in Java.

I also find awkward that in PHP you are in the postion of having to import files in order to gain additional functionality rather than importing classes. While technically these two things might not be so different, conceptually they are. An imported file can have functions and variables defined with no association to an object that effectively become global in scope on import. Static classes can have the same effect in Java, but I think most Java programmers have by now learned to avoid using static objects for the most part. The default behavior in Java is to use instances of classes whereas in PHP the default behaviour for many still seems to be to use collections of functions and function libraries.

I also find that PHP feels really quite verbose. All my PHP templates look rather ugly with echo statements littered everywhere. It’s not nearly as elegant as Freemarker.

With all other factors such as scalability, support, and resilience aside, I think PHP works great for small- to mid-sized web apps where maintainability of the code base is not a top priority. But for large, complex, long-life webapps, It seems to me that using a Java framework may be more appropriate in no small part because the quality and maintainability of the code will be considerably higher. This is not to say that you can’t create quality, maintainable apps in PHP, but that it is easier and more natural to do so in Java, where types are static, code encapsulation is paramount, and namespaces rule the roost.

Written on January 18th, 2010 , Dev & Test, Tech

I’m currently running several web apps from one Tomcat instance and they share several libraries that require log4j logging, Sitemesh, for instance. For this reason, I removed log4j.jar from each of my webapp’s “lib” folders and placed it instead in “${catalina.home}/lib” (note that I’m using Tomcat 6. This would be “${catalina.home}/common/lib” in earlier Tomcat versions)

I didn’t realise that this would create a a myriad of problems. What I found was that in my test environment, logging for all webapps ended up going to the log file for one particular webapp, while in my staging environment logging for all webapps went to the log file for a totally different webapp.

It took some time, but ultimately I got to the bottom of it. Apparently log4j does not play nice when the same log4j.jar is being used by multiple webapps. Configuring the rootLogger for one webapp appears to overwrite rootLogger settings for another webapp if log4j.jar is shared. Since each of my webapps was configuring the rootLogger to append to a different particular file, this meant that all logging ended up in only one file.

To circumvent the issue, log4j.jar must be place in each individual webapp’s “lib” folder in addition to Tomcat’s common library folder. Additionally, your web apps must be configured to use their own class loaders before using the parent class loader. This was my stumbling block. Your Tomcat context containers need to be set up something like:

<Context>
     <loader delegate=“false”/>
</Context>

If delegate is set to true then each webapp loads the common log4j.jar in favour of its own log4j.jar, giving rise to the problem.

Written on September 2nd, 2009 , Dev & Test, Tech

Matt Raible has a post here discussing how to use Sitemesh to decorate multiple webapps. When applying this to various Struts 2 webapps that use Freemarker, I found the process required a little further fine tuning. I’ve outlined the steps I’ve taken to get this working here.

One key issue to keep in mind is that the struts 2 sitemesh filter that comes with Struts 2 cannot refer to decorators in other webapps. This isn’t documented anywhere and certainly tripped me up.

  1. Configure a web app to host the decorators. This should have a web.xml that includes something like the following:
    <filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>sitemesh</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
           
    <servlet>
        <servlet-name>sitemesh-freemarker</servlet-name>
        <servlet-class>com.opensymphony.module.sitemesh.freemarker.FreemarkerDecoratorServlet</servlet-class>
            <init-param>
                    <param-name>TemplatePath</param-name>
                    <param-value>/</param-value>
            </init-param>
            <init-param>
                    <param-name>default_encoding</param-name>
                    <param-value>ISO-8859-1</param-value>
            </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
           
    <servlet-mapping>
        <servlet-name>sitemesh-freemarker</servlet-name>
        <url-pattern>*.ftl</url-pattern>
    </servlet-mapping>

    Note that this webapp is thus set up basically just to use Freemarker and Sitemesh together as outlined here.

  2. Struts 2 web apps that will use the shared decorators in some other webapp must NOT use the struts2-sitemesh PageFilter that comes with Struts 2, but instead use the PageFilter that comes with the regular sitemesh distribution:
  3. <filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
    </filter>
    <filter-name>sitemesh</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
  4. Struts 2 web apps point to decorators in the host webapp, as outlined in MR’s post:
    <decorators>
        <excludes>
            <pattern>/styles/*</pattern>
            <pattern>/scripts/*</pattern>
            <pattern>/images/*</pattern>
            <pattern>/index.html</pattern>
            <pattern>/admBase/*</pattern>
            <pattern>/jforum.page?module=admBase*</pattern>
        </excludes>
     
        <!– load decorator from a different web-app deployed in the server –>
        <decorator name=“layout” webapp=“yourWebApp” page=“/WEB-INF/decorators/YourDecorator.ftl”>
            <pattern>/*</pattern>
        </decorator>

    </decorators>

  5. crossContext must be set to true for all your webapps. (Your context elements will no doubt look considerably different, especially if you’re loading webapps from server.xml rather than individual context files)
  6. <Context reloadable=“false” crossContext=“true”>
            <Loader delegate=“true”/>
    </Context>

    And you should be good to go.

Written on July 14th, 2009 , Dev & Test, Tech

I’ve been using Spring with Struts 2 for some time now– I love how it saves me from worrying about object creation and makes my code so much more testable. One recent problem I’ve encountered, though, has led to a bit of a “gotcha” that I hadn’t foreseen.

In general, I’m autowiring my Struts 2 actions by type so that I don’t have to configure beans for actions within my Spring applicationContext.xml. I tried doing this for an action that had two dependencies that I wanted to pass in through the constructor:

public UsersAction (IDeviceService deviceService, IFacebookFacade fbFacade) {
        this.deviceService = deviceService;
        this.fbFacade = fbFacade;
}

Upon executing the action I encountered the following cryptic exception (note spelling mistake):

javax.servlet.ServletException: Unable to intantiate Action! – action

Not terribly informative. Unfortunately Google searches yielded nothing despite that unique, improperly spelled exception message. I soon learned that any action where I wanted to pass in an IFacebookFacade suffered the same fate. After much investigation I discovered the source of my error: I had another bean defined for a class that was a subclass of an IFacebookFacade implementation in my applicationContext.xml. Thus, Spring found two objects that corresponded to the same interface and wasn’t sure how to autowire by type. It would be helpful if the error message was a little more informative..

Anyhow, the solution I used was to pass the fbFacade into UsersAction by setter injection:

public UsersAction (IDeviceService deviceService) {
        this.deviceService = deviceService;
}

public void setFbFacade(IFacebookFacade fbFacade) {
        this.fbFacade = fbFacade;
}

This way, Spring will autowire by name and look for a bean with the same name as the property addressed by the setter. Job done.

Note that you could also resolve this issue by explicity defining a bean for the action in applicationContext.xml, but it is recommended to use declarative ways of specifying dependencies so as to minimise the amount of config in your applicationContext.xml. See this link for more info.

Written on June 17th, 2009 , Dev & Test, Tech

For a number of reasons, some time ago I decided to move away from using a programmatic authorization solution in a Struts 2 web app towards using Tomcat Container Managed Security (CMA). I now regret that decision as it’s caused me all sorts of issues. The three things that bother most, though, are the following:

  1. When logging in directly from the login page without first requesting a protected resource, Tomcat throws up an error. Tomcat CMA mandates that you navigate directly to a protected resource before logging in, in which case it will display the login page instead. This seems awkward and is not the case with other servlet containers like JBoss.
  2. I can’t specify a Struts 2 action as the login page. This means I have to have a separate JSP that contains all the relevant login markup, which is inconsistent with the use of the framework everywhere else in the application.
  3. As far as I can tell, CMA does not play nice with my configuration of Sitemesh, Freemarker and Struts 2 across multiple webapps. I wasn’t able to get to the root cause of the problem. I have multiple webapps, some Struts 2, some not, that all use Freemarker and use the same Sitemesh decorators. The CMA login page would not display correctly for some of these.

Ultimately item 3 was the straw that broke the camel’s back. I’ve since moved to Spring Security, which I’ve found easy to configure and resolved all of the issues listed above.

Written on April 14th, 2009 , Dev & Test, Tech

Amazon Web Services has a great tutorial on how to get MySQL up and running on their persistent storage solution, Elastic Block Store. If you did follow this tutorial on a Fedora instance, however, you may have invalidated your MySQL client config and your PHP configuration.

In the case of the MySQL client, you may observe the following error when trying to access MySQL from the command line:

ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’

The cause is that everything in /var/lib/mysql was moved to /vol/lib/mysql in the tutorial, including the socket for the client to connect to, so this is easily remedied by adding the following to /etc/my.cnf:

[client]
/vol/lib/mysql/mysql.sock

In the case of PHP, you may find that connections can no longer be made to MySQL for the same reason. Simply ensure that the following is set in /etc/php.ini:

mysql.default_socket = /vol/lib/mysql/mysql.sock

Your HTTP daemon will now need to be restarted.

Another option later suggested in the article would involve using symbolic links from the old locations to new ones.

Written on January 28th, 2009 , All, Amazon Web Services, Dev & Test, Tech

In July 2007 Vodafone rolled out its mobile internet service with much fanfare. One of its promises was to deliver mobile content formatted for mobile phones that conserves bandwidth and makes it more appropriate for the smaller screens of mobile devices relative to desktop computers. At that time Vodafone also began offering a reasonably priced flat rate data plan for this service.

Unfortunately the mechanism by which content is formatted for mobile devices presents challenges for mobile developers. Vodafone’s WTE (Web Translation Engine) uses a Novarra transcoder to reformat web pages, downsize & downgrade images, etc. The WTE system does this by intercepting HTTP requests from the mobile device, mangling the HTTP headers of the request and resubmitting the request. When it receives the response, it then performs several transformations on the data, including changing the HTTP headers of the HTTP response and then sends the response back to the mobile device.

Probably the most dire consequence for mobile developers is that the WTE system changes the “User-Agent” header of the request to dupe web servers into thinking that the request is not coming from a mobile device, but a desktop web browser (specifically the Mozilla desktop browser). Sites that have specially formatted their content for mobile devices often depend on the “User-Agent” header to determine whether they should return the mobile format or desktop format of their sites. The system has a few way to circumvent this, by hosting content at specifically formatted domain names or by setting a “Cache-Control: No-Transform” header on the request. These methods are discussed here.

This prevents HTTP responses from being transformed, but what it does not do is prevent HTTP requests from mobile devices being transformed. I’ve found that when I make HTTP requests from a mobile device with certain HTTP headers set for things like security, the WTE system strips these off and submits a request to my web servers without these headers. Naturally, this is frustrating. Vodafone UK are looking into this for me and hopefully I will get an answer soon. One thing they can do is put my domains on a white list so no requests or responses will be transformed at all, but Vodafone UK certainly aren’t the only company using Novarra transcoders and I don’t envy having to submit white list requests to all of them. I’m hoping there is another solution that is not yet publicly documented.

Issues relating to the WTE system are discussed on Betavine in this Betavine forum.

Written on January 16th, 2009 , Dev & Test, Mobile, Tech

I can’t praise Amazon Web Services enough. They make it so easy to create and manage instances of your server images in the cloud. Given that Procinity is in its infancy, we’re currently only using an EC2 Small Instance, along with an Elastic IP, Block Store and S3 for all static web content.

A couple great plugins for FireFox have proven invaluable:

They’re by no means bug free but make life much easier than working with AWS from the command line.

Written on September 12th, 2008 , Amazon Web Services, Dev & Test

All the development I’ve done to date for Procinity has made use of Struts 2, Freemarker for templating, Hibernate for persistence, and Spring for dependency injection. I’m really liking the way all this hangs together. Some of the plus points, in my view:

  • Unit testing is a breeze. Using a dependency injection framework like Spring makes testing the units as true units a pleasure.
  • The code naturally separates nicely along MVC lines.
  • The code is genuinely easy to maintain. I can set it aside for weeks, forget all about it, and quickly pick up where I left off when I return. I wish I could say the same about what I’m doing in J2ME.

Some things I’m not so sure about:

  • Hibernate occassionally uses a few more queries than I would if I were putting together the same queries by hand.
  • Between Struts 2 and Spring, I occassionally feel like I’m up to my eyeballs in XML configuration.
  • Struts 2 does not seem geared towards RESTful URLs. I am using the SmartURLs plugin to avoid “.action” suffixes and the like, but still, framing URLs as actions like Struts 2 does seems contrary to the resource-oriented approach of REST.
Written on July 16th, 2008 , All, Dev & Test, Tech

Well it’s finally arrived– my last day at SQS. The crowd at BP joined me for a bout of drinking at 1802 which was a fine way to be seen off, if a little hard on the head today. They also picked me up a couple fine bottles of cognac and rum and so it seems they want to keep me that way. :-)

On Monday it’s day 1 as Procinity Ltd. May the fun begin!

Written on April 25th, 2008 , Dev & Test, Tech

richardrauser.com is proudly powered by WordPress and the Theme Adventure by Eric Schwarz
Entries (RSS) and Comments (RSS).

richardrauser.com