Threading in Spring

In order to know when a user requests a tarot reading, I needed to set up an email client to send a message to me. The joys of SMTP are that sending email is very straightforward, no matter what your programming language. Java is no different. So I created code to send out the message. Problem was, the email was slow to send, slowing the web page response time down too much. I needed to create a second thread to handle it, in order to avoid the slowdown.

I didn’t take the time to read the Spring MVC model documentation first regarding threads. I just moved my email to a class that implemented Runnable and tried to be done with it. Unfortunately, the Spring MVC (or any other servlet for that matter, I’m guessing) requires that all the threads be tied up in pretty bows before proceeding. So using this method to send the email didn’t help my timing issue – it still required the email thread to finish before sending the response page to the user.

A bit more research brought me to Apache’s Active MQ. That was what I needed. It took care of all the heavy lifting for my producer/consumer pieces. I only need to write those classes and call the Active MQ libraries to put it in place.

The one issue I had with the process, after my first foray into it, was that it required a place to write to my file system. It took a bit of digging to figure out how to change the default location to one that my server would allow.

I see that there’s also a way of using my database. That will be another refactoring later.

Here’s the links you need to use this library:

ActiveMQ home page: http://activemq.apache.org

Setup Information for Spring: http://activemq.apache.org/spring-support.html
Tutorial site. A bit out of date (version 3, current version is 5), but it will help you get started:

http://javaboutique.internet.com/tutorials/activemq/

Getting Up to Speed Again

I’ve found myself with a bit of extra time on my hands. To keep my skills fresh – or to refreshen them, I’m going to attempt to put together a new web site using CoreServlet’s slides. I then pulled the data also following the same directions. Then a bit of Javascript magic anc voila! The data appeared.

More details to follow as I proceed.

On Time Projects

I find myself oftentimes trying to get developers to understand why it’s important to give a client a realistic date upon which to expect a release. I have heard the words that make me cringe: “But it will be ready when it’s ready. This is new stuff and we can’t predict what might happen along the way.” Try telling that to your client for whom your software is a necessary piece for their own software.

I think I’ve finally figured out a way to explain it……

I think every area of the country has the ‘backyard’ auto mechanic. The guy with several cars sitting around that haven’t been repaired since before you were born. But often those folks know more about cars than you can shake a stick at. In my area of the country, we have some of those that are actual businesses. And a few have been recommended to me as the best place to take my not-so-new cars.

When you take your car to a mechanic, it doesn’t halt your need for a vehicle. Especially in areas with poor public transportation. That means either having to rely on someone else to drive you places, or drive with you places, or it means renting a car.

Now the dilemma with the ‘backyard’ mechanic. They may be good. They may be less expensive than the other guy. But many times you don’t know when your car will be finished.

So you take the car in for what you hope is a straightforward repair. You ask the mechanic when it’ll be done and you get a general handwaving. So you make arrangements to hitch a ride, or, worse, you rent a car, to tide you over until your car is ready.

A week passes. Your car isn’t ready yet. Your told the parts have finally arrived, and you’ve moved up the priority list, so they should be working on your car again soon.

Another week passes. Your car isn’t ready yet. Something else came it that was more important than getting your car done.

Another week passes. You finally get your car back. Mind you, when you get it, it runs better than when you left it, because they’ve tweaked a few other things that had been annoying you that you hadn’t even mentioned.

But the fact remains that you were 3 weeks without your car, you were inconvenienced much longer than you expected to be, and you may, if you did end up renting a car, be out more than if you’d taken it to the ‘other guy’.

Now think about a software project. The developers tell you that, with design, development, code review, and testing, the project will take 8 weeks. 6 weeks rolls around and the coding isn’t done. They say it’ll be at least another week added on. 8 weeks passes and the coding is finally done and reviewed. But it’s not tested yet. Add another two weeks. 11 weeks passes. The software is finally delivered. It works great. But in the meantime, you’ve had your team sitting on their thumbs waiting for that functionality so they could get their part done. And your clients, to whom you’ve promised an end product, will now have to be told that it needs to come a month later. So your clients go somewhere else.

Kinda makes sense, huh?

Merging Redmine Databases

Many plug-ins have been written to allow a person to migrate from other issue tracking systems to Redmine. In these casese, the assumption is that the company is discarding an old issue tracking system and starting with a new Redmine installation. Ours is a different scenario. Our group is already using Rackspace. And we were merging with a group that had their own installation of the software. So what I needed to be able to do was merge the two databases together.

The ‘new’ team had two projects in their system, only one of which was of interest to us. That project already existed in our system. A number of users overlapped in the two systems. And the ‘new’ team’s system included some Redmine plugins that we weren’t using. The last one proved to be the most difficult to deal with.

The integration of the wiki into ours was very straightforward. What proved to be difficult was the issues. Using the existing ‘merge’ plug-ins as templates, as well as my knowledge from having created a limited interface (for our clients to see their issues, but not everything in the system), I was able to figure out most of the entries that needed to be moved over.

The easiest method of combining the issues into our system proved to be getting a csv extract from the ‘new’ system, parsing that, and adding it in. Unfortunately, doing it that way, we missed out on any attachments as well as any update history for the issues.

Scripts for migration

Creating a CXF Client Application

I’m creating a client that accesses our in-house SOAP web services. Our code base uses Spring, so I need to incorporate that. The SOAP service has security, so I need to get that working. We use maven as our build tool, so I need to get that in here as well. Here’s the steps I’m following to get it to work. I’ll edit these as I go.

  1. Download and install Apache CXF.
  2. Install the security certificate on your system using Install Cert. If that code ever goes missing, we’re all in trouble!
    • compile the code
    • run the instructions as written
    • move the jsscacert file to your /jre/lib/security folder for the JRE you’re using for your system
  3. Create a generic maven jar project (#5) using maven arechetype:generate.
  4. Add the CXF maven entries to your pom.xml.
  5. Run WSDL2JAVAto generate your base code.
  6. Create a password callback class
    import java.io.IOException;
    
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.callback.UnsupportedCallbackException;
    
    import org.apache.ws.security.WSPasswordCallback;
    
    public class ClientPasswordCallback implements CallbackHandler {
    
    	private String system;
    	public ClientPasswordCallback() {
    		// TODO Auto-generated constructor stub
    	}
    
    	public void handle(Callback[] callbacks) throws IOException,
    			UnsupportedCallbackException {
    		WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
    
    		pc.setPassword("My password");
    
    	}
    	public void setSystem(String pVal)
    	{
    		system = pVal;
    	}
  7. Add the security and bean information to your applicationContext.xml file:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:jaxws="http://cxf.apache.org/jaxws"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="
    
    http://www.springframework.org/schema/beans
    
    http://www.springframework.org/schema/beans/spring-beans.xsd
    
    http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
    <jaxws:client id="[port bean id]"
                      serviceClass="[my port class]"
                      address="[https://mywsdl]">
       <jaxws:outInterceptors>
         <bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"/>
         <ref bean="wss4jOutConfiguration"/>
       </jaxws:outInterceptors>
    </jaxws:client>
    
    <bean id="wss4jOutConfiguration" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
      <constructor-arg>
        <map>
           <entry key="action" value="UsernameToken"/>
           <entry key="passwordType" value="PasswordText"/>
           <entry key="user" value="[my login]"/>
           <entry key="passwordCallbackRef">
             <ref bean="passwordCallback"/>
           </entry>
        </map>
      </constructor-arg>
    </bean>
    
    <bean id="passwordCallback" class="[my callback class]">
       <property name="system" value="test"/>
    </bean>
    </beans>
  8. Modify the test case to use your beans:
    ApplicationContext context = new ClassPathXmlApplicationContext(
    		"/applicationContext.xml");
        	port = ([port class]) context.getBean("[beanid]");
    
            ObjectFactory factory = new ObjectFactory();
    
            [request class] myRequest = factory.create[request class]
  9. Delete the [beanname]Service.java class. You don’t need it when you use the Spring stuff.