Imports WMEncoderLib
Imports WMRMOBJSLib
Imports System.IO
Imports System.Xml
Public Class Generate
Shared Sub Main()
Dim profValue
CreateProfile()
End Sub
Shared Sub CreateProfile()
' Create a WMEncoder object.
Dim Encoder As WMEncoder
Encoder = New WMEncoder
' Create an IWMDRMContentAuthor object.
Dim DRM As IWMDRMContentAuthor
DRM = Encoder.EncoderDRMContentAuthor
' Retrieve the collection of DRM profiles.
Dim DRMProColl As IWMDRMProfileCollection
Dim KeyObj = New WMRMKeys
DRMProColl = DRM.DRMProfileCollection
' Declare variables. Specify the provider's Web site, and certificate and
' signing values. The other variables are returned.
Dim sPublicKey As String
Dim sWebURL As String
Dim vProfileID As Object
Dim vSeed As Object
Dim sPrivateKey As String
Dim sSignedPublicKey As String
Dim sSigLSCert As String
Dim sSigRootCert As String
Dim sProfilePublicKey As String
Dim sContentID As String
sContentID = KeyObj.GenerateKeyID()
KeyObj.GenerateSigningKeysEx(sPrivateKey, sPublicKey, sSignedPublicKey)
sWebURL = "http://license3.musicchoice.com/XXXX.asp"
sSigLSCert = KeyObj.GetCertificate("LSLicenseSigningCert")
sSigRootCert = KeyObj.GetCertificate("LSRootCert")
' Create the DRM profile. The public key, DRM profile ID, and
' license key seed are returned.
sProfilePublicKey = DRM.CreateDRMProfile(sWebURL, sPrivateKey, sSignedPublicKey, sSigLSCert, sSigRootCert, vProfileID, vSeed)
' Create an IWMDRMProfile object and retrieve a profile.
Dim DRMPro As IWMDRMProfile
DRMPro = DRM.GetDRMProfile(vProfileID)
' Set the rest of the properties for the DRM profile.
DRMPro.Description = "DRM for MC portable content"
DRMPro.LicenseAcquisitionURL = "http://license3.musicchoice.com/XXXX.asp"
DRMPro.Name = "MC Portable DRM"
DRMPro.V1LicenseAcquisitionURL = "http://go.microsoft.com/fwlink/?LinkId=10141"
' Add the required individualization version as an attribute.
Dim ProAttr As IWMDRMAttributes
ProAttr = DRMPro.Attributes
ProAttr.Add("SECURITYVERSION", "2.2")
ProAttr.Add("ContentID", sContentID)
Dim sDetails As String
Dim oXMLWriter As New XmlTextWriter("C:\Inetpub\wwwroot\wm\IssuedDetails.xml", System.Text.Encoding.UTF8)
oXMLWriter.WriteStartElement("Details")
oXMLWriter.WriteStartElement("Detail")
oXMLWriter.WriteAttributeString("ContentID", sContentID)
oXMLWriter.WriteAttributeString("Seed", vSeed)
oXMLWriter.WriteAttributeString("Key", sProfilePublicKey)
oXMLWriter.WriteAttributeString("PrivateKey", sPrivateKey)
oXMLWriter.WriteEndElement()
oXMLWriter.WriteEndElement()
oXMLWriter.Close()
DRMPro.Update()
DRM.ExportDRMProfile(DRMPro.ID, "password", "C:\Inetpub\wwwroot\wm\ExportProfile.drm")
End Sub
Shared Sub SaveInfo(ByVal nSeed As String, ByVal nPath As String)
Dim objStreamWriter As StreamWriter
objStreamWriter = New StreamWriter(nPath)
objStreamWriter.WriteLine(nSeed)
objStreamWriter.Close()
End Sub
End Class
Wednesday, August 27, 2008
Code Review Vol. 5 - DRM Profile Generator in VB.Net
Here is a follow up to the Windows Media Encoder and DRM script I posted previously. I mentioned in the article that I had to export a DRM profile from the DRM server, but I never really elaborated on that. Here is the script that I wrote that I ran on the server which generated the DRM profile.
Saturday, August 23, 2008
Code Review Vol. 4 - Perl Recursive Directory Stepper
Here is a recursive directory browser I wrote in Perl. I later decorated it a bit and used it for a project back at Toll Brothers. The goal was to create a shared directory for the IT Training department, where trainers for each department could store their respective white papers without the admin for IT Training having to manage those documents.
So this script simply reads the contents of the shared directory and recursively steps through all folders inside and lists out all documents.
So this script simply reads the contents of the shared directory and recursively steps through all folders inside and lists out all documents.
#!/usr/bin/perl
use DBI;
use CGI;
my $q = new CGI;
my $logFile = "exceptions.txt";
my $showDir= "/EASYT/TRAINING/manuals";
print $q->header( "text/html" );
peruseDir($showDir, '0');
exit(0);
sub peruseDir{
#create local copy of parameters
#second parameter of which is an indirect file handle
#so we can keep making recursive calls to peruseDir
#increment the indirect fhandle as we go so that we
#arent stuck on the same file through each iteration
local($currDir, $input) = @_;
$input++;
if($currDir !~ m/.*\..*/){
opendir($input, $currDir) || die print "Can't open $currDir $!
\n\n";
my @tempArr = grep { $_ ne '.' and $_ ne '..' } readdir($input);
foreach $myDir(@tempArr){
if(-d $currDir."/".$myDir){
#if its a directory make another recursive step
print "$input $myDir
";
peruseDir($currDir."/".$myDir, $input);
}else{
#otherwise its a file, show file
my $linkDir = $currDir;
$linkDir =~ s/\/EASYT\/TRAINING\///;
print "$myDir
";
}
}
closedir($input);
}
}
sub logExceptions{
open(LOG, ">> $logFile") || die print "Couldn't write to log $!";
foreach $exception(@_){
print LOG "$exception\n";
}
close(LOG);
}
Friday, August 22, 2008
Code Review Vol. 3.01 - WMEncode and DRM Walkthrough
Imports WMEncoderLib
Imports System.Windows.Forms
Imports System.IO
Module Module1
Dim WithEvents Encoder As WMEncoder
Dim glbQuitBool As Boolean = False
Dim baseURL As String
Dim DRMProfilePass As String = "XXX"
Dim DRMProfile As String = "ExportProfile.drm"
Sub Main()
Init()
SearchDir(baseURL)
End Sub
Sub Init()
Dim sr As StreamReader = New StreamReader("baseLoc.ini")
Dim line As String
line = sr.ReadLine()
sr.Close()
baseURL = line
End Sub
Function DoEncode(ByVal sourceFile As String, ByVal outputFile As String, ByVal thisProfile As WMEncProfile2, ByVal fileType As String) As Boolean
Try
Encoder = New WMEncoder
Dim SrcGrpColl As IWMEncSourceGroupCollection = Encoder.SourceGroupCollection
Dim SrcGrp As IWMEncSourceGroup = SrcGrpColl.Add("SG_1")
Dim newFile As IWMEncFile = Encoder.File
If fileType = "video" Then
Dim vidFile As IWMEncVideoSource = SrcGrp.AddSource(2)
vidFile.SetInput(sourceFile)
End If
Dim audFile As IWMEncAudioSource = SrcGrp.AddSource(1)
Up until this point it's fairly standard WMEncoder SDK code - create a sourcegroup collection, create a sourcegroup, and add a video or audio source to the source group - but here we introduce the DRM element. It follows the same template
Dim DRM As IWMDRMContentAuthor
Dim DRMProColl As IWMDRMProfileCollection
Dim tempDRMPro As IWMDRMProfile
DRM = Encoder.EncoderDRMContentAuthor
' Retrieve the collection of DRM profiles.
DRMProColl = DRM.DRMProfileCollection
'First remove any DRM Profiles that may still linger
tempDRMPro = DRMProColl.Item(0)
DRM.RemoveDRMProfile(tempDRMPro.ID)
' Import a DRM profile.
DRM.ImportDRMProfile(DRMProfilePass, DRMProfile)
DRMProColl = DRM.DRMProfileCollection
Dim DRMPro As IWMDRMProfile
DRMPro = DRMProColl.Item(0)
Essentially the DRM set up follows the same format as the Encoder, create a ProfileCollection, create a profile object which references the literal .drm profile file that I had exported from the DRM server. A DRMContentAuthor is pulled from the base WMEncoder object and everything is imported into that.
' Set the current DRM profile into the encoding session.
Dim vKeyID As Object = "XXXXX
DRM.SetSessionDRMProfile(DRMPro.ID, vKeyID)
Dim newProfile As WMEncProfile2 = New WMEncProfile2
audFile.SetInput(sourceFile)
newFile.LocalFileName = outputFile
newProfile = thisProfile
' newProfile.LoadFromFile(thisProfile)
SrcGrp.Profile = newProfile
Encoder.AutoStop = True
Encoder.RemoteAdmin = True
Encoder.PrepareToEncode(True)
Encoder.Start()
Dim x As Integer
For the longest time the code didn't work. Until I found out that I needed to put a slight wait before encoding. And even while its encoding down below inside the while loop it still needs a pause between each iteration to register events and change states when necessary.
'HACK - needs this to actually work, bug in WM SDK
For x = 0 To 30
Application.DoEvents()
x = x + 1
Next
While Encoder.RunState = WMENC_ENCODER_STATE.WMENC_ENCODER_RUNNING
Dim temp = Encoder.RunState
Dim y As Integer
For y = 0 To 300
y = y + 1
Next
Application.DoEvents()
End While
Encoder.Stop()
Return True
Catch ex As Exception
Console.WriteLine(ex)
Dim errFile As String = outputFile + ".error"
File.Create(errFile)
File.Delete(outputFile)
Return False
End Try
Encoder = Nothing
End Function
Here I grab the .drm file from the filesystem and load it into the WMEncProfile2 object.
Function RetrieveProfile(ByVal nFile) As WMEncProfile2
Try
Dim BasicEdit As WMEncBasicEdit
BasicEdit = New WMEncBasicEdit
' Specify the input, output, and configuration files.
BasicEdit.MediaFile = nFile
' Retrieve the duration of the input file, in seconds.
Dim lFileDur As Long
lFileDur = BasicEdit.Duration / 1000
' Retrieve the profile used by the input file.
Dim Pro As WMEncProfile2
Pro = BasicEdit.Profile
Return Pro
Catch ex As Exception
Console.WriteLine(ex)
End Try
End Function
And here is the engine - I essentially read the directory that was set aside as the publishing directory, where all raw files to be encoded and distributed were deposited, and encode and drm them.
Sub SearchDir(ByVal dir)
'Environment.CurrentDirectory
Dim di As New DirectoryInfo(dir)
' Create an array representing the files in the current directory.
Dim fi As FileInfo() = di.GetFiles()
Dim tempFile As FileInfo
For Each tempFile In fi
Dim currentProfile As WMEncProfile2
Dim currentSourceFile As String = baseURL + "\" + tempFile.Name
Dim currentOutputFile As String = baseURL + "\DRMed\" + tempFile.Name
Dim currentFType As String
Dim currentFTypeArr = Split(tempFile.Name, ".")
If currentFTypeArr(1) = "wma" Then
currentFType = "audio"
ElseIf currentFTypeArr(1) = "wmv" Then
currentFType = "video"
End If
currentProfile = RetrieveProfile(currentSourceFile)
DoEncode(currentSourceFile, currentOutputFile, currentProfile, currentFType)
Next tempFile
End Sub
End Module
And that's it. Pretty straightforward, but by automating the encoding process and combining it with the DRMing process I was anble to integrate that into the automated workflow that I was building as the infrastructure to the overall Music Choice broadband product.
Wednesday, August 20, 2008
Code Review Vol. 3 - Encode and DRM Audio and Video Content With Windows Media Encoder SDK and VB.Net
Here is a snippet of code I wrote several years ago to encode and DRM content to WMV format. Back when I worked at Music Choice one of my initial tasks was to come up with a DRM solution for all videos on the web. My initial solution was clunky, basically following Microsoft's sample code - what little there actually was for the subject. But over time I revisited the solution and came up with a more elegant solution. Essentially I encapsulated the transcoding and DRMing of raw content to WMVs to a single console application. I exported a DRM profile from our DRM servers and used that to generate the DRM envelope. The console application was included in the automated work flow when new content was distributed to our clients.
Imports WMEncoderLib
Imports System.Windows.Forms
Imports System.IO
Module Module1
Dim WithEvents Encoder As WMEncoder
Dim glbQuitBool As Boolean = False
Dim baseURL As String
Dim DRMProfilePass As String = "XXX"
Dim DRMProfile As String = "ExportProfile.drm"
Sub Main()
Init()
SearchDir(baseURL)
End Sub
Sub Init()
Dim sr As StreamReader = New StreamReader("baseLoc.ini")
Dim line As String
line = sr.ReadLine()
sr.Close()
baseURL = line
End Sub
Function DoEncode(ByVal sourceFile As String, ByVal outputFile As String, ByVal thisProfile As WMEncProfile2, ByVal fileType As String) As Boolean
Try
Encoder = New WMEncoder
Dim SrcGrpColl As IWMEncSourceGroupCollection = Encoder.SourceGroupCollection
Dim SrcGrp As IWMEncSourceGroup = SrcGrpColl.Add("SG_1")
Dim newFile As IWMEncFile = Encoder.File
If fileType = "video" Then
Dim vidFile As IWMEncVideoSource = SrcGrp.AddSource(2)
vidFile.SetInput(sourceFile)
End If
Dim audFile As IWMEncAudioSource = SrcGrp.AddSource(1)
Dim DRM As IWMDRMContentAuthor
Dim DRMProColl As IWMDRMProfileCollection
Dim tempDRMPro As IWMDRMProfile
DRM = Encoder.EncoderDRMContentAuthor
' Retrieve the collection of DRM profiles.
DRMProColl = DRM.DRMProfileCollection
'First remove any DRM Profiles that may still linger
tempDRMPro = DRMProColl.Item(0)
DRM.RemoveDRMProfile(tempDRMPro.ID)
' Import a DRM profile.
DRM.ImportDRMProfile(DRMProfilePass, DRMProfile)
DRMProColl = DRM.DRMProfileCollection
Dim DRMPro As IWMDRMProfile
DRMPro = DRMProColl.Item(0)
' Set the current DRM profile into the encoding session.
Dim vKeyID As Object = "XXXXX"
DRM.SetSessionDRMProfile(DRMPro.ID, vKeyID)
Dim newProfile As WMEncProfile2 = New WMEncProfile2
audFile.SetInput(sourceFile)
newFile.LocalFileName = outputFile
newProfile = thisProfile
' newProfile.LoadFromFile(thisProfile)
SrcGrp.Profile = newProfile
Encoder.AutoStop = True
Encoder.RemoteAdmin = True
Encoder.PrepareToEncode(True)
Encoder.Start()
Dim x As Integer
'HACK - needs this to actually work, bug in WM SDK
For x = 0 To 30
Application.DoEvents()
x = x + 1
Next
While Encoder.RunState = WMENC_ENCODER_STATE.WMENC_ENCODER_RUNNING
Dim temp = Encoder.RunState
Dim y As Integer
For y = 0 To 300
y = y + 1
Next
Application.DoEvents()
End While
Encoder.Stop()
Return True
Catch ex As Exception
Console.WriteLine(ex)
Dim errFile As String = outputFile + ".error"
File.Create(errFile)
File.Delete(outputFile)
Return False
End Try
Encoder = Nothing
End Function
Function RetrieveProfile(ByVal nFile) As WMEncProfile2
Try
Dim BasicEdit As WMEncBasicEdit
BasicEdit = New WMEncBasicEdit
' Specify the input, output, and configuration files.
BasicEdit.MediaFile = nFile
' Retrieve the duration of the input file, in seconds.
Dim lFileDur As Long
lFileDur = BasicEdit.Duration / 1000
' Retrieve the profile used by the input file.
Dim Pro As WMEncProfile2
Pro = BasicEdit.Profile
Return Pro
Catch ex As Exception
Console.WriteLine(ex)
End Try
End Function
Sub SearchDir(ByVal dir)
'Environment.CurrentDirectory
Dim di As New DirectoryInfo(dir)
' Create an array representing the files in the current directory.
Dim fi As FileInfo() = di.GetFiles()
Dim tempFile As FileInfo
For Each tempFile In fi
Dim currentProfile As WMEncProfile2
Dim currentSourceFile As String = baseURL + "\" + tempFile.Name
Dim currentOutputFile As String = baseURL + "\DRMed\" + tempFile.Name
Dim currentFType As String
Dim currentFTypeArr = Split(tempFile.Name, ".")
If currentFTypeArr(1) = "wma" Then
currentFType = "audio"
ElseIf currentFTypeArr(1) = "wmv" Then
currentFType = "video"
End If
currentProfile = RetrieveProfile(currentSourceFile)
DoEncode(currentSourceFile, currentOutputFile, currentProfile, currentFType)
Next tempFile
End Sub
End Module
Tuesday, August 12, 2008
Code Review Vol. 1.01 - Calendar Class Walkthrough
import flash.display.*;
import net.com.calendar.Day;
public class AbstractCalendar extends Sprite
{
private static var _dayIDSequence:Number = 0;
private var _dayHeight:Number = 50;
private var _dayWidth:Number = 50;
private var _startX:Number = 10;
private var _startY:Number = 10;
private const WEEKDAYCOUNT:Number = 7;
private var _bgColor:uint = 0xCCCCCC;
private var _borderColor:uint = 0x666666;
private var _borderSize:uint = 1;
public function AbstractCalendar(month:Number)
{}
CreateDay instantiates a Day object and sets all of its properties. Date is the date object for the specific day, Name is used to getChildByName and Display is the string value to be stored in the textfield in the Day. OriginalStackIndex is exactly what it sounds like, the original index in the display list that the object was first created. I get this at runtime by pulling from a sequence of my own creation - I'm enamored with the Oracle concept of sequences. It really isn't used in this example, its a remnant from my actual implementation where I change the child index when a user clicks on a day.
private function createDay(today:Date,name:String, display:String, dayNum:Number):Day
{
var tempDay:Day = new Day()
tempDay.name = getNewDayID();
tempDay.setDate(today)
tempDay.setName(name);
tempDay.setDisplay(display);
tempDay.setDayNumber(dayNum)
tempDay.drawDay(_bgColor, _borderSize,_borderColor, _dayWidth, _dayHeight);
tempDay.originalStackIndex = Number(tempDay.name)
return tempDay
}
getNewDayID is my version of the Oracle sequence. It gives unique ids for the objects and tells me their stack index
private function getNewDayID():String
{
return (_dayIDSequence++).toString();
}
DrawMonth is the engine for this implementation. Essentially you pass in a number for the month you want to render. With that month number I create a date object for the first day of the month. I assume its the current year, change at your own discretion. Once I have the date object for the first day I just keep iterating and incrementing the date object one day at a time. I check several things - if its the first day of the month and the day of the week isn't Sunday I back fill for however many days away from Sunday the actual day is. I check to make sure we are still on the month we're supposed to be rendering, if we aren't, then I find out what day it is and front-fill the current week with as many days as we are away from Saturday. If we are still in the month then I keep drawing days. I check if the current day is Sunday, if it is I reset the x coordinate back to 0 to start a new week. I also check if the current dayStepper - which is just an incrementor to keep track of how many times we've looped through, to account for the back and front-filling we've been doing - gives a remainder when divided by 7 (the number of days in a week) if it doesn't I know a full week has been rendered and I need to increment the y coordinate by the height of the day to start a new line.
public function drawMonth(tempMonth:Number,tempDay:Day, backDay:Day):void{
var currentDay:Number = 1
var dayStepper:Number = 0
var tempDate:Date = new Date(tempMonth + "/"+currentDay+"/" + new Date().getFullYear());
var tempMonthChecker:Number = tempDate.getMonth()
//check for current month to step through each day in the month
while(tempDate.getMonth() + 1 == tempMonth){
tempDate = new Date(tempMonth + "/"+currentDay+"/" + new Date().getFullYear());
tempMonthChecker = tempDate.getMonth()
// check for day num, at each zero
// reset startX back to 0
if(tempDate.getDay() == 0){ _startX = 10}
//figure out the day number for the first day only
if(tempDate.getDay() > 0 && currentDay == 1 )
{
for(var x:Number = 0;x < tempDate.getDay(); x++)
{
//backfill previous days
backDay = createDay(tempDate,"","",x)
backDay.x = _startX
backDay.y = _startY
_startX += _dayWidth
addChild(backDay);
dayStepper++
}
}
if(tempDate.getMonth() + 1 == tempMonth){
tempDay = createDay(tempDate, "",currentDay.toString(),tempDate.getDay())
tempDay.x = _startX
tempDay.y = _startY
_startX += _dayWidth
addChild(tempDay);
dayStepper++
// increment startY by the _dayHeight
if(dayStepper % WEEKDAYCOUNT == 0){_startY += _dayHeight}
currentDay++
}else{
for(var y:Number = tempDate.getDay(); y < WEEKDAYCOUNT;y++)
{
//front fill the next months days
backDay = createDay(tempDate,"","",x)
backDay.x = _startX
backDay.y = _startY
_startX += _dayWidth
addChild(backDay);
}
}
}
}
}
And that's it. When taken apart and examined the logic is fairly straightforward. Yet it's extensible and powerful. You can extend the Day class to do almost anything and encompass any kind of custom logic. You can change the basic engine to draw a single day or draw a week or a set window of weeks.
Friday, August 8, 2008
man me pt. 5
After Toll I went to a small software firm right outside of Philadelphia. What I found there was a small team of really talented people who had formed this great bond and work dynamic, seemingly in-spite of an oppressively micromanaging and confused management team. The management team was comprised of three investors who each had a say and a stake, yet none of which had any understanding of software or how to make it. It was confusing because their dynamic would change at seemingly random times, one taking the lead from the other and roles being changed and priorities following suit. Meetings frequently became discussions of the same topic over and over again, each time with different results.
This tumultuous environment had served to strengthen the team's internal dynamic. Everyone was fiercely loyal to the team. This actually back-fired on the management team towards the end of my tenure there, as work from home had been taken away company-wide - a mandate intended to strengthen communication and team unity when one of the partners asserted controlf from another - almost everyone in the company began to leave. But not just random job searches, they each communicated with each other, with several members going to the same company. By the time I left there was no one left from the original team when I had started.
My responsibilities there were:
First to serve as Lead. At first I was lead for several products but as time went on I assumed lead of all technology at the company. By the end of my time there I was in a Director position setting the technology strategy company-wide and leading a department of developers and interns that I had personally hired.
Second, to serve as Architect and Sr Engineer. I architected solutions to migrate the company's two legacy products to a Service Oriented Architecture, using .Net web services and Flex front-end. I architected a blue-print for the company to create mobile pieces to plug into their newly forming enterprise. I also created a plan to create build servers where database topography and pre-built templates would be used to generate code and build new instances of products for client installs.
When I left, the development department was rebuilt and energized with a good technology road map to lead them well into the next two years.
My responsibilities there were:
First to serve as Lead. At first I was lead for several products but as time went on I assumed lead of all technology at the company. By the end of my time there I was in a Director position setting the technology strategy company-wide and leading a department of developers and interns that I had personally hired.
Second, to serve as Architect and Sr Engineer. I architected solutions to migrate the company's two legacy products to a Service Oriented Architecture, using .Net web services and Flex front-end. I architected a blue-print for the company to create mobile pieces to plug into their newly forming enterprise. I also created a plan to create build servers where database topography and pre-built templates would be used to generate code and build new instances of products for client installs.
When I left, the development department was rebuilt and energized with a good technology road map to lead them well into the next two years.
Wednesday, August 6, 2008
man me pt. 4
I was originally hired by Toll Brothers to maintain and update an internal legacy application for the Land Development department. But after a couple weeks I found that task would realistically only take a fraction of my potential bandwidth. So I turned my attention to the state of the company's application infrastructure. I saw a young IT department still finding it's legs in a mature company. I saw many different departments having different applications, some .Net apps, some Java apps, a Perl app, some apps using Oracle, some SQL Server and one using MySQL. No shared class libraries and minimal if any code re-use. This heterogeneous environment was a result of different departments within the company acting independently of IT, hiring outside contractors and even in-house developers working exclusively for their department, to build their applications for their immediate needs, not concerned with adhering to or establishing standards.
Seeing this, I began a series of weekly meetings with the leads of the different applications to try and find points of commonality. With the sheer volume and scope of applications it would be unrealistic to re-write the applications under one technology - instead I proposed that we move the business logic that the apps had in common to a central repository: a series of web services that would use abstract base classes and interfaces to allow departments to inherit and implement their own specialized classes while data that any other application on the enterprise could access and have a hook into. After all, Toll's main business model was project based - projects being tracts of land and each department had their own view on the tract of land. Land Purchasing focused on buying the land, Land Development focused on what to do with the land (twenty estates homes or seventy townhomes?), Sales focused on selling the homes built on the land. Land was even kept as an asset for potential liquidity. So projects were the biggest point of commonality, even if departments had access to different views of a project, at least they would still be talking about the same project and any changes to that project would be reflected real-time in every other app in the enterprise.
Having the business logic be available via web services then opened up the possibility of expanding the services that were offered to clients (from a Toll IT perspective clients were other internal departments). Specifically creating mobile applications, or mobile extensions to existing applications, that would consume the web services and feed data back to the enterprise for real time exception reporting.
Once we had decided on a company-wide standard for mobile phones, ie what specific phone, OS and carrier we would use, I started to create the base skeletal functionality. More r&d and proof of concept than actual business implementation, I fleshed out routines for authenticating the web services with the Novell servers and the core store and forward patterns that all new apps would use for offline use.
Seeing this, I began a series of weekly meetings with the leads of the different applications to try and find points of commonality. With the sheer volume and scope of applications it would be unrealistic to re-write the applications under one technology - instead I proposed that we move the business logic that the apps had in common to a central repository: a series of web services that would use abstract base classes and interfaces to allow departments to inherit and implement their own specialized classes while data that any other application on the enterprise could access and have a hook into. After all, Toll's main business model was project based - projects being tracts of land and each department had their own view on the tract of land. Land Purchasing focused on buying the land, Land Development focused on what to do with the land (twenty estates homes or seventy townhomes?), Sales focused on selling the homes built on the land. Land was even kept as an asset for potential liquidity. So projects were the biggest point of commonality, even if departments had access to different views of a project, at least they would still be talking about the same project and any changes to that project would be reflected real-time in every other app in the enterprise.
Having the business logic be available via web services then opened up the possibility of expanding the services that were offered to clients (from a Toll IT perspective clients were other internal departments). Specifically creating mobile applications, or mobile extensions to existing applications, that would consume the web services and feed data back to the enterprise for real time exception reporting.
Once we had decided on a company-wide standard for mobile phones, ie what specific phone, OS and carrier we would use, I started to create the base skeletal functionality. More r&d and proof of concept than actual business implementation, I fleshed out routines for authenticating the web services with the Novell servers and the core store and forward patterns that all new apps would use for offline use.
When the first mobile project was then approved I served as the technical lead for an off-shore team of developers who fleshed out the business logic on top of the skeletal structure I provided.
Toll was both a really good and very interesting experience for me. It was the first large company I worked for, the first publicly traded company. My first exposure to SOX compliance, the first time I was in-house in such a heterogenous environment. Had the housing market not taken a dump when it did, making staying at Toll a volatile prospect, I would probably still be there to this day.
I made a lot of friends while I was at Toll, some of which have become very good friends that I still see to this day. One of which then brought me on to my next company with him.
Subscribe to:
Posts (Atom)