ColdFusion Migration to Java or .NET

Semantic Designs can provide your organization with highly accurate automated conversion of legacy ColdFusion applications (with embedded HTML, JavaScript and SQL) to modern technologies based on Java or C#.

Migrating ColdFusion to new languages such as Java or .Net promises the following nice properties:

  • Makes the application more maintainable, and easier to enhance due to the enormous libraries available for Java and C#
  • Enables some degree of automatic bug detection by virtue of (Java) compiler static analysis, which does not/cannot occur with ColdFusion so many such problems are found after deployment,
  • Moves it to modern web technology such as JSP or Java Server Faces/PrimeFaces, enhancing developer productivity and users' UI experience
  • Provides the organization with access to more easily found (Java) software engineers,
all which contribute to faster turnaround on desired changes for management.

A key concern is, What will translated code look like? Weak translators convert code blindly line-by-line, with virtually no understanding of how the context of the code should shape its translation. Such translated code preserves the properties of the original ColdFusion, sometime the point of even preserving the syntax. Even if such code works, it not be maintainable and will ultimately cost the organization sorely.

Semantic Designs translators parse the original code with tools that have the same understanding as the original compilers; (for example, see our ColdFusion Front End). ColdFusion doesn't really provide declarations of variable types, so SD's tools need to infer appropriate Java/C# types based on how variables are used in the program, where and how they are used ("the context"). Using this information the translator can thus produce extremely good translations. Because SD also customizes the tools to the specific needs of the customer, the code reflects those needs properly.

A ColdFusion program translation

Here we show you a small sample of ColdFusion translated as SD's technology could translate it to Java.

A simple ColdFusion program

We have chosen to provide a small ColdFusion program to prevent the reader from being overwhelmed by the complexities that occur in real examples.

<!--- DEMO.CF --->
<!--- DDL: CREATE TABLE Items ( PartID VARCHAR(17), Quantity INT, Cost DECIMAL(5,2) ) --->

<cfinclude template="definitions.cf">
<cif Country=="England"
  <cfset CurrencySymbol="£">
  <cfset Tax=.10>
<cfelse>
  <cfset CurrencySymbol="$">
  <cfset Tax=.05>
</cfif>
<cfquery datasource=#dsn# name="Items"
            SQL="Select PartID,Quantity,Cost from ItemTable where Quantity>0"
</cfquery>
<table>
<cfoutput>
  <tr><th>PartNumber</th><th>Quantity</th><th>Unit Price</th></tr>
  <cfloop>
  <tr><td><a href="BuyOne.cfm?buy=#Items.PartID#">#Items.PartID#</a></td>
      <td>#Items.Quantity#</td>
      <td>#CurrencySymbol##Items.Cost*(1+Tax)#</td>
  <tr>
  </cfloop>
</table>
</cfoutput>

Each client has different goals and these can change the chosen target technology.

  • Target language of C# or Java. Given that ColdFusion has been built on top of Java, that tends to be the strongly preferred target for most ColdFusion migrations.
  • Generation of web pages using Java Server Pages style (similar to legacy ColdFusion), which provide for an easier migration but requireds the web developers to build their complex widgets, or using a more modern UI framework such as Java Server Faces and possibly its extension, PrimeFaces. Choosing the latter gives the website engineers libraries of well designed and tested UI components with which to build a rich user experience. A key issue with using JSF/Primefaces is whether to fold multiple legacy HTML pages together into single DOM image with dynamic updates using Ajax.
  • Mapping of database queries to the client's database of choice; this may be complicated by the fact that SQL only appears to be standard across databases.
  • Usingly legacy HTML constructs such as or using Primefaces components such as Accordion tables.
  • Cleaning up Javascript by replacing ad hoc with well-designed libraries, getting rid of duplicate code, and finding/fixing security holes induced by sloppy JavaScript use (esp. "eval").

One should note that the translator must chose fixed data types for variables compatible with their usage in the ColdFusion program or the database schema, but with a different representation better suited for Java. Note the different choice of Java integer types based on the sizes of the values being stored.

In particular, note the choice of the Java BigDecimal class used where ColdFusion values represent fractional or very big numbers. The translation is adjusted to use appropriate method calls on the BigDecimal class instead of native Java operators +, -, *, / which do not work on classes. We remark that a different custom translation could scale decimal numbers by 100 or 10000, allowing use of Java-native + and - operators instead of method calls. Which of these choices are made depend on what the client thinks in more important to long term maintainablity: representation of decimal numbers as 'decimals' in the BigDecimal class with somewhat less readable expressions for decimal arithmetic, or a slightly non-intuitive representation of decimal numbers with readable expressions.

Which combination of choices is made can determine very different style of translated code. The translator needs to be configured to account for the client's choices. For this example, we have chosen to use PrimeFaces. Note that the translator produces a variety of files (java, xhtml) that collectively implement the orginal Cold Fusion page. The translator produces nicely formatted for each type of file as a standard by-product.

ColdFusion program translated to Java

------------------------------Demo.java----------------------------------------------------

// Java Bean
import java.math.BigDecimal;

@Named
@ViewScoped
public class DemoBean implements Serializable {
  DemoBean() {
     if (Definitions.Count.eq("England") {
       this.CurrencySymbol="£";
       this.Tax=.10;
     } else {
      this.CurrencySymbol="$";
      this.Tax=.05;
     }
  }

  private char CurrencySymbol;
  public char getCurrentSymbol() {
    return CurrencySymbol;
  }
  public setCurrencySymbol(char currencySymbol) {
    this.CurrencySymbol = currencySymbol;
  }

  private float Tax;
  public float getTax() {
    return Tax;
  }
  public void setTax(Tax float) {
    this.Tax = Tax
  }
    
  public string UnitPrice(Cost BigDecimal) {
    return CurrencySymbol + Cost.Multiply(1+Tax);
  }
}

------------------------------Demo.properties.vo.java-------------------------------------

// Value Object
package com.semanticdesigns.demo.properties.vo;

import java.math.BigDecimal;

public final class ItemsVO implements java.io.Serializable {
  private String partID;
  private int Quantity;
  private BigDecimal Cost;

  public ItemsVO() {}

  public ItemsVO(String PartID, int Quantity, BigDecimal Cost) {
    this.partID = PartID;
    this.quantity = Quantity;
    this.cost = Cost;
  }

  public String getPartID() {
    return this.PartID;
  }
  public void setPartID(String PartID) {
    this.PartID = PartID;
  }

  public int getQuantity() {
    return this.Quantity;
  }
  public void setQuantity(int Quantity) {
    this.Quantity = Quantity;
  }

  public BigDecimal getCost() {
    return this.Cost;
  }
  public void setCost(BigDecimal Cost) {
    this.Cost = Cost;
  }

  @Override
  public String toString() {
    return "ItemsVO [PartID=" + PartID + 
           ", Quantity=" + Quantity + 
           ", Cost=" + Cost + 
           "]";
  }
}

------------------------------Demo.properties.dao.java------------------------------------

// Data Access Object
package com.semanticdesigns.demo.properties.dao;

import java.math.BigDecimal;

import com.semanticdesigns.demo.properties.util.PropertiesLogger;
import com.semanticdesigns.demo.properties.vo.ItemsVO;

@org.springframework.stereotype.Repository
public class ItemsDAO {
  @javax.persistence.PersistenceContext(
    unitName = "demoEntityManager"
  )
  private javax.persistence.EntityManager entityManager;

  private static String createItems() {
    return "SELECT PartID,\n" + 
           "       Quantity,\n" + 
           "       Cost,\n" + 
           "WHERE Items.Quantity>0\n"; 
  }

  @org.springframework.transaction.annotation.Transactional
  public java.util.List<ItemsVO> getItems() {
    PropertiesLogger.enter();
    java.util.List<ItemsVO> result = java.util.Collections.emptyList();
    try {
      javax.persistence.Query query = entityManager.createNativeQuery(createItems());
      java.util.List<Object[]> list = query.getResultList();
      PropertiesLogger.debug("List size: " + list.size());
      result = list.stream().map(obj ->
                   new ItemsVO( ( (String) obj[0] // PartID
                                , (int) obj[1] // Quantity
                                , (BigDecimal) obj[2] // Cost
                                )).collect(java.util.stream.Collectors.toList());
    }
    catch (java.lang.Exception ex) {
      PropertiesLogger.error(".getItems throws exception.", ex);
      throw new org.hibernate.QueryException(ex);
    }
    finally {
      PropertiesLogger.exit();
    }
    return result;
  }
}

------------------------------Demo.UI.xhmtl-----------------------------------------------

<!-- Primefaces component -->
<p:dataTable var="Items" value="#{dtBasicView.Items}">
    <p:column headerText="PartID" onclick="BuyOne.html?buy=#{Items.Name}">
        <h:outputText value="#{Items.Name}" />
    </p:column>
    <p:column headerText="# In Stock">
        <h:outputText value="#{Items.Quantity}" />
    </p:column>
    <p:column headerText="Unit Price">
        <h:outputText value="#{DemoBean.UnitPrice(Items.Cost)}" />
    </p:column>
</p:dataTable>

------------------------------------------------------------------------------------------

One can get good code like the above, from a translator, if one has the right foundation technology such as SD's DMS Software Reengineering Tookit®. As a practical matter, you can't get good code from an off the shelf translator, because every application system has unique properties: languages, OS features, scripting languages, screens, databases, and a correspondingly unique set of target technologies as decided by the client. It takes some effort to configure DMS for the client's particular source and target software configurations. The effort is rewarded by the maintainablity of the result.

Configuring a custom migration tool to match client needs

Semantic Designs can provide custom configuration of migration tools and migration support to your organization, providing high quality, maintainable code translations.

For more information: [email protected]    Follow us at Twitter: @SemanticDesigns

ColdFusion
Migration