My Projects
Search Blog

Categories
Archives
Useful Links
Photo Albums
RSS

Powered by
BlogCFM v1.15

Vivio Technologies VPS Hosting
15 June 2008
Creating IIS Virtual Directories with Coldfusion 8 and .NET integr

Ever had a need to automate the creation of virtual directories in IIS?  Coldfusion 8 can do this quite well using the System.DirectoryServices.DirectoryEntry class in the .NET framework.

After a whole lot of trial and error, this is what I came up with and it seems to work quite nicely:

 

<!--- get the server ID for the specific web site
    from IIS.  The default web site is usually "1"
    --->
<cfset serverid="2017647531">

    <!---
        //  metabasePath is of the form "IIS://<servername>/<service>/<siteID>/Root[/<vdir>]"
        //    for example "IIS://localhost/W3SVC/1/Root"
    --->
<cfset metabasePath = "IIS://localhost/W3SVC/#serverid#/Root">

<!--- name of the virtual directory --->
<cfset vdirName = "vdir001">

<!--- physical path for this virtual directory --->
<cfset physicalPath = "D:\Inetpub\ricktest\realdir">

<!--- full path to the System.DirectoryServices.dll --->
<cfset dllPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.DirectoryServices.dll">

<!--- instantiate a DirectoryEntry .NET object --->
<cfobject
    type=".net"
    class="System.DirectoryServices.DirectoryEntry"
    assembly="#dllPath#"
    name="site">

<!--- initialize the object with the metabase path --->   
<cfset site.init(metabasePath)>

<!--- you need the classname for later --->
<cfset className = site.Get_SchemaClassName()>

<cfif reFind("VirtualDir$",className) gt 0>
    <!--- Get the children so we can add a new child --->
    <cfset vdirs = site.Get_Children()>
    <cftry>
        <!--- add the new virtual directory --->
        <cfset newVDir = vdirs.Add(vDirName, className)>
        <cfcatch type="any">
            <cfoutput><h3>Failed to create #vDirName#</h3></cfoutput>
            <cfif cfcatch.ToString() contains "already exists">
                <p>Another directory with that name already exists.</p>
            <cfelse>
                <cfoutput><p>#cfcatch.ToString()#</p></cfoutput>
            </cfif>
            <cfabort>
        </cfcatch>
    </cftry>
    <Cftry>
        <!--- set the PAth property to the physical directory path --->
        <cfset newVDir.Get_Properties().Get_Item("Path").Set_Value(physicalPath)>
        <!--- commit the changes --->
        <cfset newVDir.CommitChanges()>

        <cfcatch type="any">
            <cfdump var="#cfcatch.ToString()#">
            <cfdump var="#cfcatch#">
            <Cfabort>
        </cfcatch>
    </cftry>
</cfif>


 

 

Posted by rickroot at 9:08 AM | Link | 1 comment
04 June 2008
JavaCSV for creating large CSV and other delmiited files with Coldfusion

In an effort to resolve memory and performance problems with generating large CSV and tab delimited files in an application I wrote at Duke, I started hunting around for solutions.

Initially, I was using the java stringbuffer method, but found that it's really hard to be sure that CF doesn't use String objects, especially when doing things like calling out to an external function to perform formatting (ie, if the field is a string, then surround it with double quotes and escape any internal double quotes).

A simple file drop of 7200 rows and 140 columns took 68 seconds and sucked a lot of memory.  And no, it wasn't the file writing that caused the problem, it was the call out to the formatting function.

If I performed the same drop using the tab delimited format, I didn't have to call out to that function, but the drop still took 30 seconds.  I needed it to be faster because some of the drops my users perform are much much larger.

so I started hunting around for a java-based solution and found the JavaCSV library:

After installing this library in my C:\Jrun4\servers\myInstance\cfusion.ear\cfusion.ear\WEB-INF/cfusion/lib directory and restarting Coldfusion, I was able to use the following code to generate my CSV files:

<cfset var fileOutput = createObject("java","com.csvreader.CsvWriter")>

<cfset fileOutput.init("#expandPath("..")#\drops\#filename#")>

<cfif format eq "TAB">
     <cfset fileOutput.setDelimiter( javacast("char", "     ") )>
</cfif>

<!--- write header --->
<cfloop from="1" to="#numFields#" index="i" step="1">
     <cfset fileOutput.write( fieldsArray[i] ) >
</cfloop>
<!--- end of header row --->
<cfset fileOutput.endRecord()>
<!--- loop through results --->
<cfloop query="resultSet">
     <!--- write record --->
     <cfloop from="1" to="#numFields#" index="i" step="1">
          <cfset fileOutput.write( resultSet[fieldsArray[i]][resultSet.currentRow].toString() )>
     </cfloop>
     <!--- write end of record --->
     <cfset fileOutput.endRecord()>
</cfloop>
<cfset fileOutput.close()>

The same drop which had previously taken 68 seconds now only took 18 seconds - AND used considerably less memory.

As you can see, the code handles both CSV and tab-delimited formats AND handles the proper escaping of strings containing delimiters as well.

Posted by rickroot at 8:03 AM | Link | 1 comment
03 June 2008
cfsavecontent vs. cfset for performance improvement

Many CF programmers out there know that coldfusion uses java string objects to store its variables usually.  And since java strings are "immutable", every time you change it, a new string is created.

If you find yourself doing huge amounts of string concatenations, you'll often see people suggesting that you look up the java StringBuffer object and use that instead.  That would allow you to append to a single StringBuffer object rather than creation a million string objects.

But there's another solution, apparently.

CFSAVECONTENT is so ridiculously fast compared to the old string concatenation method with CFSET that it has got to be using a StringBuffer behind the scenes.  At least, that's what I'm thinking.

Take the following code, for example.  On my local machine, the CFSET method took 64 seconds to complete.  The CFSAVECONTENT method completed in a mere 203ms.

Also, the memory consumption of the CFSET method was significant, while the CFSAVECONTENT method was hardly noticeable.

 

<cfsetting enablecfoutputonly="yes">
<cfsetting requesttimeout="600">
<cfset reps = 100000>

<cfif 1>
     <cfset start = now().gettime()>
     <cfset result = "">
     <cfloop from="1" to="#reps#" step="1" index="i">
          <cfset result = result & i>
     </cfloop>
     <cfset end = now().gettime()>
     <cfoutput><p>#end-start#ms : #len(result)#</p></cfoutput>
<cfelse>
     <cfset start = now().gettime()>
     <cfsavecontent variable="result">
     <cfloop from="1" to="#reps#" step="1" index="i">
          <cfoutput>#i#</cfoutput>
     </cfloop>
     </cfsavecontent>
     <cfset end = now().gettime()>
     <cfoutput><p>#end-start#ms : #len(result)#</p></cfoutput>
</cfif>


 

 

Posted by rickroot at 1:23 PM | Link | 1 comment
07 March 2008
Value Object Generator

I wrote a little CFM file to generate actionscript classes for value objects from coldfusion queries.  It uses getMetaData() on the query to determine data types for the VO.  I've only coded in some simple datatypes in the getColType() method to handle the conversion from the dbtype to actionscript data type - you can add whatever you need.

<cfsetting enablecfoutputonly="yes">
<cfset voName = "EntityLogVO">
<cfset voPackage = "model.vo">
<cfset remoteClass = "cfcs.enquire.vo.#voName#">

<cfquery name="qry" datasource="ENQUIRE" maxrows="1">
 select
  A.QUERYID, A.USERID, A.QUERYDATE, A.INSTANCE,
  A.TITLE, A.SAVED, A.LASTRUNDATE,
  A.CRITERIA
 from dbo.DROP_QUERIES A
 where
  A.USERID=<cfqueryparam cfsqltype="cf_sql_char" value="ADSRJR">
  AND A.SAVED=<cfqueryparam cfsqltype="cf_sql_smallint" value="1">
 order by
  A.QUERYDATE desc
</cfquery>

 

<cffunction name="getColType" output="false" returnType="string">
 <cfargument type="string" name="coltypename" required="yes">
 
 <cfset coltypename = listfirst(coltypename, " ")>
 <cfif coltypename contains "char">
  <cfreturn "String">
 <cfelseif coltypename contains "int">
  <cfreturn "int">
 <cfelseif coltypename contains "date">
  <cfreturn "Date">
 <cfelseif coltypename contains "text">
  <cfreturn "String">
 <cfelseif coltypename contains "float">
  <cfreturn "Number">
 <cfelseif coltypename contains "double">
  <cfreturn "Number">
 <cfelse>
  <cfthrow message="Unhandled Database Type" detail="the database type #coltypename# is not handled.">
 </cfif>
</cffunction>

<cfoutput><pre>
/////////////////////////////////////////////////////
// #voName#.as
//
// generated by voGenerator.cfm (Rick Root)
// generated on #dateFormat(Now(),'yyyy-mm-dd')# at #TimeFormat(Now(),'h:mm tt')#
//
//
/////////////////////////////////////////////////////

package #voPackage#
{
 [RemoteClass(alias="#remoteClass#")]
 public class #voName#
 {
</cfoutput>
<cfset metadata = getMetaData(qry)>
<cfloop from="1" to="#ArrayLen(metadata)#" step="1" index="x">
 <cfoutput>  private var _#metadata[x].Name#: #getColType(metadata[x].TypeName)#;#chr(10)#</cfoutput>
</cfloop>

<cfloop from="1" to="#ArrayLen(metadata)#" step="1" index="x">
 <cfoutput>
  public function get #metadata[x].Name#(): #getColType(metadata[x].TypeName)#
  {
   return _#metadata[x].Name#;
  }

  public function set #metadata[x].Name#(value:#getColType(metadata[x].TypeName)#): void
  {
   _#metadata[x].Name# = value;
  }

 </cfoutput>
</cfloop>
<cfoutput>
  public function #voName#()
  {

  }
 }
}
</pre>
</cfoutput>

 

Here is an example of the value object generated from the code above:

/////////////////////////////////////////////////////
// EntityLogVO.as
//
// generated by voGenerator.cfm (Rick Root)
// generated on 2008-03-07 at 12:40 PM
//
//
/////////////////////////////////////////////////////

package model.vo
{
 [RemoteClass(alias="cfcs.enquire.vo.EntityLogVO")]
 public class EntityLogVO
 {
  private var _QUERYID: int;
  private var _USERID: String;
  private var _QUERYDATE: Date;
  private var _INSTANCE: String;
  private var _TITLE: String;
  private var _SAVED: int;
  private var _LASTRUNDATE: Date;
  private var _CRITERIA: String;

  public function get QUERYID(): int
  {
   return _QUERYID;
  }

  public function set QUERYID(value:int): void
  {
   _QUERYID = value;
  }

 
  public function get USERID(): String
  {
   return _USERID;
  }

  public function set USERID(value:String): void
  {
   _USERID = value;
  }

 
  public function get QUERYDATE(): Date
  {
   return _QUERYDATE;
  }

  public function set QUERYDATE(value:Date): void
  {
   _QUERYDATE = value;
  }

 
  public function get INSTANCE(): String
  {
   return _INSTANCE;
  }

  public function set INSTANCE(value:String): void
  {
   _INSTANCE = value;
  }

 
  public function get TITLE(): String
  {
   return _TITLE;
  }

  public function set TITLE(value:String): void
  {
   _TITLE = value;
  }

 
  public function get SAVED(): int
  {
   return _SAVED;
  }

  public function set SAVED(value:int): void
  {
   _SAVED = value;
  }

 
  public function get LASTRUNDATE(): Date
  {
   return _LASTRUNDATE;
  }

  public function set LASTRUNDATE(value:Date): void
  {
   _LASTRUNDATE = value;
  }

 
  public function get CRITERIA(): String
  {
   return _CRITERIA;
  }

  public function set CRITERIA(value:String): void
  {
   _CRITERIA = value;
  }

 
  public function EntityLogVO()
  {

  }
 }
}

 

 

Posted by rickroot at 10:11 AM | Link | 0 comments
15 August 2007
AIR Url - Adobe AIR Project

The Adobe on AIR bus tour is stopping by the Raleigh area on Saturday, courtesy of TACFUG and RDAUG, and they're having a contest.  Best AIR app wins a prize!

Well, my url shortener app may not be the best, but if I'm lucky, it'll be the only app submitted.

I've recompiled the URL shortener app as an AIR app (I built it when it was still called Apollo), and you can get it here:

Here's the source code:

 

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication
 xmlns:mx="http://www.adobe.com/2006/mxml"
 layout="absolute"
 width="400" height="68"
 creationComplete="init()">
<mx:Script>
 <![CDATA[
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.Fault;
import mx.controls.Alert;

import mx.utils.StringUtil;

private function init():void {
 txtLongUrl.setFocus();
}
private function genericFault(e:FaultEvent):void
{
 txtShortUrl.text = e.fault.faultString;
 btnTryIt.enabled = false;
}
private function tryUrl(url:String):void {
 navigateToURL(new URLRequest(url), '_blank');
}
private function addUrlResult(e:ResultEvent):void {
 txtLongUrl.text = '';
 txtShortUrl.text = e.result.toString();
 if (e.result.toString() != 'Invalid Source URL!') {
  btnTryIt.enabled = true;
 }
}
 ]]>
</mx:Script>
 <mx:WebService id="ro" wsdl="http://url.rickroot.com/url.cfc?wsdl" showBusyCursor="true">
  <mx:operation name="addUrl" fault="genericFault(event)" result="addUrlResult(event)"/>
 </mx:WebService>
 <mx:VBox x="10" y="10">
  <mx:HBox>
   <mx:Label text="Url to Shorten:" width="100" fontWeight="bold"/>
   <mx:TextInput id="txtLongUrl" width="200"/>
   <mx:Button id="btnDoIt" label="Do It!" click="txtShortUrl.text = ''; ro.addUrl(txtLongUrl.text);"/>
  </mx:HBox>
  <mx:HBox>
   <mx:Label text="Results:" width="100" fontWeight="bold"/>
   <mx:TextInput id="txtShortUrl" width="200"/>
   <mx:Button id="btnTryIt" label="Try It!" click="tryUrl(txtShortUrl.text);" enabled="false"/>
  </mx:HBox>
 </mx:VBox> 
</mx:WindowedApplication>

 

 

Posted by rickroot at 9:06 AM | Link | 1 comment