Analytics


Google

Friday, October 31, 2008

Consuming Webservice using MSSoap

Even though majority of the programmers have started using vb.net, there may be cases where you have a legacy system that still needs to consume webservice. This is how to do it with MSSoap.

First thing to be aware of is you may encounter issue if the webservice returns XML, so have it return a string instead. This is easily done by using a wrapper function. For example, if you have a webmethod say getLotData, just create a getLotDataStr as follows:

<WebMethod()> _
Public Function getLotData(ByVal pLotID As String) As XmlDocument
....
End Function

...

<WebMethod()>
Public Function getLotDataStr(ByVal pLotID As String) As String
Dim tmpStr As String = ""
Dim xDoc As XmlDocument

xDoc = getLotData(pLotID)
tmpStr = xDoc.OuterXml

Return tmpStr
End Function


To consume the webservice, in vbscript or VB, you then use the MSSoap client as follows:

Dim wsClient As New MSSOAPLib30.SoapClient30
Dim urlStr as String = "http://www.blogger.com/wservice.asmx?WSDL"
Dim sReply, lotID As String
Dim xDoc As DOMDocument30

lotID = ...
wsClient.MSSoapInit urlStr
sReply = wsClient.getLotDataStr(lotID)

xDoc.loadXML sReply

...


Once the information is loaded to the XmlDocument, you can then access the information by using the getElementsByTagName. You can also access the inner text by access the Text Property.

E.g.

Dim lotNode As IXMLDOMNode
Dim processStep As String

Set lotNode = xDoc.getElementByTagName("processID")
ProcessStep = lotNode.Text


'If it is an attribute then access it by the Attributes as in
ProcessStep = lotNode.Attributes.getNameItem("Name").Text


You can also use the DomDocument30 data type to create the parameters if the Webservice requires a XML as a parameter.

Wednesday, October 29, 2008

Creating properly aligned content in Blogger

The easiest way to create a properly aligned information in Blogger is:
  1. Open excel and place the data in table as shown below.
  2. Copy and then paste into the compose screen (this only works if you are using FireFox) and there you have it, your data is aligned correct (as shown below).

This is how the excel looks like:


Using Firefox:

Date Mileage time
1-Jan-08 10 1 hr
2-Jan-08 5 0.5 hr

Saturday, October 25, 2008

Dynamically loading UserControl in ASP.Net

I gathered information from the following sources to come up with the following:

4 Guys from Rolla
ASP.Net
CodeProject

First the UserControl:

This is how it looks like in VS Designer:


The code is as follows:

<%@ Control Language="vb" AutoEventWireup="false" Codebehind="ucAckFrm.ascx.vb" Inherits="testWeb.ucAckFrm" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %>
<asp:panel id="PaneCtrl" runat="server">
<asp:Label id="lblCtrlName" runat="server"></asp:Label>
<BR>
<asp:Panel id="paneDisp" runat="server">
<asp:Label id="lblMsg" runat="server"></asp:Label><BR><BR>
<asp:Button id="btnAck" runat="server" Text="Acknowledge"></asp:Button>
<asp:Button id="btnReject" runat="server" Text="Reject"></asp:Button>
<asp:TextBox id="txtReason" runat="server"></asp:TextBox><BR>
<asp:Label id="lblErrMsg" runat="server" ForeColor="Red"></asp:Label>
<HR>
</asp:Panel>
</asp:panel>


The code behind is as follows:

Public Class ucAckFrm
Inherits System.Web.UI.UserControl

#Region " Web Form Designer Generated Code "

'This call is required by the Web Form Designer.
Private Sub InitializeComponent()

End Sub
Protected WithEvents lblMsg As System.Web.UI.WebControls.Label
Protected WithEvents btnAck As System.Web.UI.WebControls.Button
Protected WithEvents btnReject As System.Web.UI.WebControls.Button
Protected WithEvents txtReason As System.Web.UI.WebControls.TextBox
Protected WithEvents lblCtrlName As System.Web.UI.WebControls.Label
Protected WithEvents lblErrMsg As System.Web.UI.WebControls.Label
Protected WithEvents PaneCtrl As System.Web.UI.WebControls.Panel
Protected WithEvents paneDisp As System.Web.UI.WebControls.Panel

'NOTE: The following placeholder declaration is required by the Web Form Designer.
'Do not delete or move it.
Private designerPlaceholderDeclaration As System.Object

Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
'CODEGEN: This method call is required by the Web Form Designer
'Do not modify it using the code editor.
InitializeComponent()
End Sub

#End Region

Public Event AckClick As EventHandler
Public Event RjctClick As EventHandler

Public Property RjctReason() As String
Get
Return txtReason.Text
End Get
Set(ByVal Value As String)
txtReason.Text = Value
End Set
End Property

Public Sub setMainPane(ByVal pVisible As Boolean)
PaneCtrl.Visible = pVisible
End Sub

Public Sub setDispPane(ByVal pVisible As Boolean)
paneDisp.Visible = pVisible
End Sub

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
lblCtrlName.Text = Me.ID
End Sub

Private Sub btnAck_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAck.Click
RaiseEvent AckClick(Me, e)
End Sub


Private Sub btnReject_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnReject.Click
Dim tmpStr As String

tmpStr = Trim(txtReason.Text)

If tmpStr.Length > 0 Then
RaiseEvent RjctClick(Me, e)
Else
lblErrMsg.Text = "Reject Reason cannot be blank"
End If
End Sub
End Class


The main aspx page:


The code:

<%@ Register TagPrefix="uc1" TagName="ucAckFrm" Src="ucAckFrm.ascx" %>
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="TestPage.aspx.vb" Inherits="testWeb.WebForm1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<title>WebForm1</title>
<meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
<meta content="Visual Basic .NET 7.1" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
</HEAD>
<body>
<form id="Form1" method="post" runat="server">
<asp:label id="lblMsg" runat="server"></asp:label><br>
<asp:textbox id="txtMsg" runat="server"></asp:textbox><br>
<br>
<asp:button id="btnSubmit" runat="server" Text="Submit"></asp:button><br>
<asp:Label id="lblErrMsg" runat="server" ForeColor="Red"></asp:Label><br>
<hr>
<br>
<uc1:ucAckFrm id="DefAck" runat="server"></uc1:ucAckFrm><br>
<asp:PlaceHolder id="pHolder" runat="server"></asp:PlaceHolder></form>
</body>
</HTML>


The code behind:

Public Class WebForm1
Inherits System.Web.UI.Page

#Region " Web Form Designer Generated Code "

'This call is required by the Web Form Designer.
Private Sub InitializeComponent()

End Sub
Protected WithEvents lblMsg As System.Web.UI.WebControls.Label
Protected WithEvents txtMsg As System.Web.UI.WebControls.TextBox
Protected WithEvents btnSubmit As System.Web.UI.WebControls.Button
Protected WithEvents defAck As ucAckFrm
Protected WithEvents pHolder As System.Web.UI.WebControls.PlaceHolder
Protected WithEvents lblErrMsg As System.Web.UI.WebControls.Label

'NOTE: The following placeholder declaration is required by the Web Form Designer.
'Do not delete or move it.
Private designerPlaceholderDeclaration As System.Object

Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
'CODEGEN: This method call is required by the Web Form Designer
'Do not modify it using the code editor.
InitializeComponent()
End Sub

#End Region

Dim vStr As String
Dim ackArray As New ArrayList

Private Sub PageInit2(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
Dim ctrlCnt, tmpStr As String
Dim loopCnt, ackCnt As Integer
Dim vAckCtrl As ucAckFrm
Dim ctrl As Control

ctrlCnt = Request.Item("opt")
vStr = ctrlCnt

If IsNumeric(vStr) Then
ackCnt = CInt(vStr)
If ackCnt > 0 Then
For loopCnt = 0 To (ackCnt - 1)
ctrl = LoadControl("ucAckFrm.ascx")
tmpStr = "Ack_" & loopCnt
ctrl.ID = tmpStr
vAckCtrl = CType(ctrl, ucAckFrm)
AddHandler vAckCtrl.AckClick, AddressOf AckHandlerAck
AddHandler vAckCtrl.RjctClick, AddressOf AckHandlerRjct

ackArray.Add(vAckCtrl)
pHolder.Controls.Add(ctrl)
Next
End If
End If

AddHandler defAck.AckClick, AddressOf AckHandlerAck
AddHandler defAck.RjctClick, AddressOf AckHandlerRjct

End Sub


Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
If IsPostBack = False Then
Try
lblMsg.Text += "ctrlCnt value is " & vStr
Catch ex As Exception
lblErrMsg.Text += "<br>" & ex.Message
End Try

End If

End Sub


Private Sub AckHandlerAck(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim idName As String

idName = UCase(CType(sender, Control).ID)

lblMsg.Text += "<br>Acknowledge by " & idName
End Sub

Private Sub AckHandlerRjct(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim idName, reason As String
Dim handledCtrl As ucAckFrm

idName = UCase(CType(sender, Control).ID)
handledCtrl = CType(sender, ucAckFrm)
reason = handledCtrl.RjctReason

lblMsg.Text += "<br>Rejected by " & idName & " due to " & reason
End Sub
End Class


In this example, to simplify testing, I use the url parameter opt to determine how many times I want to load the usercontrol. In the following example, I loaded it twice - i.e. ?opt=2


Key points I learn from the articles are:
  • Init will be called each time the page is refreshed.
  • View State is loaded after the init phase before the page load phase.
  • To load the control, we actually use the .ascx file using Page.LoadControl
  • After loading the control, we need to use CType to change back to the class defined in the codebehind for the usercontrol so we can access the properties, events etc for the user control.
Other Notes on this example:
  • In the example above, I assigned the ID for each of the controls that are dynamically loaded, this is actually for a project I am working on where the requestor will specify how many persons will be informed of a request made. Each person receiving the request will then have an option to either acknowledge the request or reject it. In that situation, I will then name each of the controls with the role for each receipient.
  • I added the mainPane and dispPane to provide an option if to either hide the whole control or to display on the header (but not used in the example above).
  • I use a try catch and throw to practice Error handling I wrote in my previous article.

Wednesday, October 22, 2008

Consuming WebService in Lotus NOTES

I found it difficult to find reference on how to consume webservice in Lotus NOTES. That is why I have this as a bookmark to help me get back to those locations:

Consuming webservice in LN 6


Another good one that shows a simple client side method is found here (snippet as follows):
Dim Client As Variant
Set Client = CreateObject("MSSOAP.SoapClient")
'Initialize connection to the Web Service
Call Client.mssoapinit
("http://localhost/testWS.nsf/Simple?wsdl")
'Call our simple GetEmailAddress
function provided by Web service
Dim result As String
result = Client.getJoke()
'output result to message box
Messagebox result, 48, "Get Joke"


There is also an open source project which produces a java stub to consume the webservice called stubby, however, still not sure whether is meets my counterparts requirements.

In LN 8, it is much simpler to consume the webservice, just have to create a new script - either JavaScript, LotusScript or Java Library and there is a button at the bottom labeled WSDL, just click it and import WSDL to create the required reference to consume the webservice.

There is also another reference on how to write do some of the coding in java - found here. Another reference talking about webservice in LN 8.5 is found here.

Monday, October 20, 2008

Lotus NOTES programming

If you are curious about programming in Lotus NOTES, IBM provides an excellent resource here. The item I found most useful is the reference entitle Lotus Script Language Guide. Unfortunately, there is only one version of the reference book available (i.e. version 7.x).

When I first started on Lotus NOTES (4.x), they only provided formula for programming. Since version 5.x, the introduced JavaScript and LotusScript. If you are from MS environment, you will probably be more comfortable with LotusScript, since the syntax is identical to VBScript used for macros of all the MSOffice products.

If you prefer, you can either program in Java or JavaScript which is also available within Lotus NOTES. So just as you can program in Oracle using PL/SQL or using Java. The preference is yours.

Wednesday, October 15, 2008

Oracle 10G migration Issues - not group by

When we migrated from Oracle 9i to 10G, we encountered a few issues. One of the strangest one is as follows.

The following query works fine in 9i but when we execute in 10G, we encounter the following error:

ORA-00979: not a GROUP BY expression

The SQL statement (changes have been made on the column names and table names to protect the innocent code) is as follows:

SELECT TO_CHAR(Time_Date, 'yyyymmdd') Time_Date ,
Def_Code ,
StepName ,
ScrapReason ,
StartQty ,
ScrapQty ,
BonusQty ,
ROUND(DECODE(StartQty,0,0,(ScrapQty-BonusQty)/StartQty*100), 2) DefectPercentage,
0 Normalised
FROM
(SELECT Time_Date,
Def_Code ,
StepName ,
ScrapReason ,
ScrapQty ,
BonusQty ,
(SELECT SUM(YLDPACKAGE.GET_OPSTEPSTARTQTY(StepName,StartQty,ScrapQty,BonusQty))
FROM yld_summary
WHERE Time_Date = d.Time_Date
AND RType = 'ASSEMBLY'
AND (Owner LIKE 'SPECIALBUILD%'
AND (Category = 'PRODUCTION'
OR Category = 'BETA' ) )
AND (PRODUCTNAME(WafID,Owner) = 'VISTA')
AND YLDPACKAGE.GET_STEPGRP(StepName) = d.StepName
) StartQty
FROM
(SELECT Time_Date ,
Def_Code ,
YLDPACKAGE.GET_STEPGRP(StepName) StepName ,
REPLACE(ScrapReason, '_RI','') ScrapReason,
SUM(ScrapQty) ScrapQty ,
SUM(BonusQty) BonusQty
FROM yld_dtl
WHERE Time_Date BETWEEN to_date('20081007', 'yyyymmdd') AND to_date('20081014', 'yyyymmdd')
AND RType = 'ASSEMBLY'
AND (Owner LIKE 'SPECIALBUILD%'
AND (Category = 'PRODUCTION'
OR Category = 'BETA' ) )
AND (PRODUCTNAME(WafID,Owner) = 'VISTA')
AND YLDPACKAGE.GET_STEPGRP(StepName) = 'LAPPING'
AND ScrapReason = 'Scratches'
GROUP BY Time_Date ,
Def_Code ,
YLDPACKAGE.GET_STEPGRP(StepName),
REPLACE(ScrapReason, '_RI','')
) d
) order by time_date


The work around is to just add another column in the group by (highlighted below in red):

SELECT TO_CHAR(Time_Date, 'yyyymmdd') Time_Date ,
Def_Code ,
StepName ,
ScrapReason ,
StartQty ,
ScrapQty ,
BonusQty ,
ROUND(DECODE(StartQty,0,0,(ScrapQty-BonusQty)/StartQty*100), 2) DefectPercentage,
0 Normalised
FROM
(SELECT Time_Date,
Def_Code ,
StepName ,
ScrapReason ,
ScrapQty ,
BonusQty ,
(SELECT SUM(YLDPACKAGE.GET_OPSTEPSTARTQTY(StepName,StartQty,ScrapQty,BonusQty))
FROM yld_summary
WHERE Time_Date = d.Time_Date
AND RType = 'ASSEMBLY'
AND (Owner LIKE 'SPECIALBUILD%'
AND (Category = 'PRODUCTION'
OR Category = 'BETA' ) )
AND (PRODUCTNAME(WafID,Owner) = 'VISTA')
AND YLDPACKAGE.GET_STEPGRP(StepName) = d.StepName
) StartQty
FROM
(SELECT Time_Date ,
Def_Code ,
YLDPACKAGE.GET_STEPGRP(StepName) StepName ,
REPLACE(ScrapReason, '_RI','') ScrapReason,
SUM(ScrapQty) ScrapQty ,
SUM(BonusQty) BonusQty
FROM yld_dtl
WHERE Time_Date BETWEEN to_date('20081007', 'yyyymmdd') AND to_date('20081014', 'yyyymmdd')
AND RType = 'ASSEMBLY'
AND (Owner LIKE 'SPECIALBUILD%'
AND (Category = 'PRODUCTION'
OR Category = 'BETA' ) )
AND (PRODUCTNAME(WafID,Owner) = 'VISTA')
AND YLDPACKAGE.GET_STEPGRP(StepName) = 'LAPPING'
AND ScrapReason = 'Scratches'
GROUP BY Time_Date ,
Def_Code ,
YLDPACKAGE.GET_STEPGRP(StepName),
StepName ,
REPLACE(ScrapReason, '_RI','')
) d
) order by time_date



Nov 23, 2008

Found the above code did not product correct output, had to rewrite it as follows:

 SELECT TO_CHAR(Time_Date, 'yyyymmdd') Time_Date                                   ,
Def_Code ,
StepName ,
ScrapReason ,
StartQty ,
ScrapQty ,
BonusQty ,
ROUND(DECODE(StartQty,0,0,(ScrapQty-BonusQty)/StartQty*100), 2) DefectPercentage,
0 Normalised
FROM
(SELECT Time_Date,
Def_Code ,
StepName ,
ScrapReason ,
ScrapQty ,
BonusQty ,
(SELECT SUM(YLDPACKAGE.GET_OPSTEPSTARTQTY(StepName,StartQty,ScrapQty,BonusQty)),
YLDPACKAGE.GET_STEPGRP(StepName) step
FROM yld_summary
WHERE Time_Date = d.Time_Date
AND RType = 'ASSEMBLY'
AND (Owner LIKE 'SPECIALBUILD%'
AND (Category = 'PRODUCTION'
OR Category = 'BETA' ) )
AND (PRODUCTNAME(WafID,Owner) = 'VISTA')
group by YLDPACKAGE.GET_STEPGRP(StepName)) l,
(SELECT Time_Date ,
Def_Code ,
YLDPACKAGE.GET_STEPGRP(StepName) StepName ,
REPLACE(ScrapReason, '_RI','') ScrapReason,
SUM(ScrapQty) ScrapQty ,
SUM(BonusQty) BonusQty
FROM yld_dtl
WHERE Time_Date BETWEEN to_date('20081007', 'yyyymmdd') AND to_date('20081014', 'yyyymmdd')
AND RType = 'ASSEMBLY'
AND (Owner LIKE 'SPECIALBUILD%'
AND (Category = 'PRODUCTION'
OR Category = 'BETA' ) )
AND (PRODUCTNAME(WafID,Owner) = 'VISTA')
AND YLDPACKAGE.GET_STEPGRP(StepName) = 'LAPPING'
AND ScrapReason = 'Scratches'
GROUP BY Time_Date ,
Def_Code ,
YLDPACKAGE.GET_STEPGRP(StepName),
StepName ,
REPLACE(ScrapReason, '_RI','')
) d where l.step = d.stepname
) order by time_date

Sunday, October 12, 2008

Installing Framework 1.1 in Vista (if error)

Found the article from here.
Install Microsoft .NET Framework 1.1 on Windows Vista - Fix RegSvcs.exe Fails Error

Windows Vista comes packaged with Microsoft .NET Framework 2.0 and 3.0, but not version 1.1, which may still required by some applications such as QuickBooks 7, GFI Report Packs, VS.NET 2003, InstallShield 11.5, and many other developed software. However, when trying to install Microsoft .NET Framework 1.1 (dotnetfx.exe) on Windows Vista, one or more error messages similar to one of the following text will appear, and stop or prevent setup installation of .NET Framework 1.1 from continuing successfully.

RegSvcs.exe - Common Language Runtime Debugging Services

Application has generated an exception that could not be handled.
Process id=0xe50 (3664), Thread id=0xd44 (3396).

Click OK to terminate the application.
Click CANCEL to debug the application.

In Event Viewer of Vista, the following log or similar can be seen:

Source: MsiInstaller
Event ID: 1030
Description:
Product: Microsoft .NET Framework 1.1. The application tried to install a more recent version of the protected Windows file C:\Windows\Microsoft.NET\Framework\sbs_wminet_utils.dll. You may need to update your operating system for this application to work correctly. (Package Version: 1.0.0.0, Operating System Protected Version: 1.0.0.0).

Source: MsiInstaller
Event ID: 1030
Description:
Product: Microsoft .NET Framework 1.1. The application tried to install a more recent version of the protected Windows file C:\Windows\Microsoft.NET\Framework\sbs_system.enterpriseservices.dll. You may need to update your operating system for this application to work correctly. (Package Version: 1.0.0.0, Operating System Protected Version: 1.0.0.0).

The error pops up in the end of .NET Framework 1.1 setup when it’s almost finished, and is registering “System.EnterpriseServices.dll” when the error occurs, time remaining for the installatin process shows 0 seconds.

Why exactly the error occurs when installing Microsoft .NET Framework 1.1 in Windows Vista is not known, as the issue happens randomly. It may affect both 32-bit and 64-bit Vista system, but not all system will have the issue. But one thing is for sure. Microsoft .NET Framework 1.1 SP1 (Service Pack 1) has resolved the issue. However, Microsoft does not provide download to standalone .NET Framework 1.1 installer that integrated with SP1.

Thus, the workaround to fix the Microsoft.NET Framework 1.1. installation error on Vista is to slipstream .NET Framework 1.1 SP1 into .NET Framework 1.1 installer, so that both the .NET Framework and the Service Pack can be installed at the same time.

To slipstream .NET 1.1 SP1 into .NET Framework setup package to have a integrated .NET Framework 1.1 SP1 installer, follow steps in this trick:


1. Create a new folder named DotNet in C:\ drive (C:\DotNet is used in this guide, you can change to any folder you prefer, but ensure that you use correct path in the following steps).
2. Download Microsoft .NET Framework 1.1 Redistributable Package (dotnetfx.exe). Make sure the setup file is saved as dotnetfx.exe.
3. Download Microsoft .NET Framework 1.1 Service Pack 1 (NDP1.1sp1-KB867460-X86.exe). Make sure that the file is renamed and saved as dotnetfxsp1.exe, so that the rest of the steps can be followed easily.
4. Move both installation files into the same directory (i.e. C:\DotNet), if you’re not saving them together.
5. Open command prompt as Administrator.
6. Change to the directory where the two installation setup files for .NET 1.1 are saved (i.e. C:\DotNet).
7. Run the following commands one by one, press Enter after each one.
* dotnetfx.exe /c:"msiexec.exe /a netfx.msi TARGETDIR=C:\DotNet"

If you’re not using C:\DotNet directory, change the target to your path accordingly.

Install Microsoft .NET Framework 1.1 on Windows Vista
Then click on “Yes” when prompted to answer “would you like to install Microsoft .NET Framework 1.1. Package?”

Wait for the uncompression, extraction and setup to complete with the display of the following dialog which says installation complete.
Install Microsoft .NET Framework 1.1 on Windows Vista
* dotnetfxsp1.exe /Xp:C:\DotNet\netfxsp.msp

No status message for this step.
* msiexec.exe /a c:\DotNet\netfx.msi /p c:\DotNet\netfxsp.msp

Install Microsoft .NET Framework 1.1 on Windows Vista
Wait for Windows Installer for Microsoft .NET Framework 1.1 to finish and disappear automatically.
8. Install Microsoft .Net Framework 1.1 with slipstreamed/integrated Service Pack 1 by running netfx.msi created in the working folder.

Wednesday, October 8, 2008

Microsoft is offering three VS 2008 PDF for free download but...

Just found the following in my email today from Microsoft - just click the following link:


After signing up, it allows you to download the three books (from Microsoft Press) in PDF format:

Programming Microsoft LINQ
Introducing Microsoft Silverlight 2
Programming ASP.NET 3.5

I was expecting the whole book but only selected chapters of each book is provided : (

However, Microsoft does provide some other pdf books for free such as:

Composite Application Guidance for WPF (but requires simple registration - just log into hotmail)

Tuesday, October 7, 2008

Decompiler

Recently one of my team member was in the midst of migrating to a new database and was performing some testing and encountered some problem. I told him to go back to the code and make the changes and testing. However, when he did that, he found that the person who previously wrote the code (and left the company) failed to checkin the source code into our SourceSafe repository.

As such, I went to search for decompilers. I came across many articles but the following are the more helpful ones:

Decompiling .Net Assemblies
Decompilers

For .Net, it appears that Reflector is the free solution recommended.

There were a couple of sharewares that did the samething - Spice, Dis# and Salamander.

For Java, you have Jode and Jad. Hmm, where do this people come up with these names :)

Wednesday, October 1, 2008

Connecting to RAC using SQLDeveloper

The following are two definition in tnsnames.ora pointing to the same RAC database. The first one uses name (racdb1), the second (racdb2) uses actual IP address:

racdb1 =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = db1.blogspot.COM)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = db2.blogspot.COM)(PORT = 1521))
(LOAD_BALANCE = yes)
)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = ORCL.BLOGSPOT.COM)
(FAILOVER_MODE =
(TYPE = SELECT)
(METHOD = BASIC)
(RETRIES = 180)
(DELAY = 5)
)
)
)


racdb2 =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.155.1.1)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.155.1.2)(PORT = 1521))
(LOAD_BALANCE = yes)
)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = ORCL.BLOGSPOT.COM)
(FAILOVER_MODE =
(TYPE = SELECT)
(METHOD = BASIC)
(RETRIES = 180)
(DELAY = 5)
)
)
)

If you use SQL Developer to connect to racdb1 using the TNS, you will encounter the following error:

Status: Failure - Test failed: (null).

It works fine if you connect to racdb2. Apparently, it is not able to perform a nslookup to obtain the IP address when using TNS. It works fine if you use advance and use thin client to connect as in:

Strangely, if you use Advanced and put the following string, it works:

jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS = (PROTOCOL = TCP)(HOST = db1.blogspot.COM)(PORT = 1521))(ADDRESS = (PROTOCOL = TCP)(HOST = db2.blogspot.COM)(PORT = 1521))(LOAD_BALANCE = yes))(CONNECT_DATA=(SERVER = DEDICATED)(SERVICE_NAME = ORCL.BLOGSPOT.COM)(FAILOVER_MODE=(TYPE = SELECT)(METHOD = BASIC)(RETRIES = 180)(DELAY = 5))))

Friday, September 26, 2008

AJAX in Framework 3.5

AJAX is now built into Framework 3.5. Using it is quite straight forward:


First add
<asp:ScriptManager runat="server">
</asp:ScriptManager>
within the form tag:

The form tag is normally within the <body> </body> tags:
As in:
<head>
...
</head>
<body>
...
<form id="form1" runat="server">
....
</form>
</body>


Next use put your controls within the Update Panel. All controls within the Update Panel are automatically AJAX. However, make sure to put it within the ContentTemplate!!


<asp:UpdatePanel ID="uPane1" runat="server">
<ContentTemplate>
...
</ContentTemplate>
</asp:UpdatePanel>

Sunday, September 21, 2008

Invalid Path when consuming Webservice

This will happen if you are consuming a webservice which generates xml as return value. What happens is when the webservice works correctly, it will return a well formed xml as a reply.

However, if you are using IIS to serve the webservice and when there is an error, IIS will return the error in HTML. Since the routine (proxy class) that consumes the webservice expects a well formed xml and it gets a html response (which is typically an invalid xml), it will return "Invalid Path".

Unfortunately, in most cases the error is very misleading.

Friday, September 19, 2008

Creating Database link in Oracle to without defining remote database in sqlnet

Normally, when we create a database link to a remote database, we will define the alias in SQLNet and then create the database link as follows:

create database link dbtest connect to scott identified by tiger using 'dbtest';


However, it is possible to connect directly by using what is defined in the sqlnet as follows:

create database link dbtest connect to scott identified by tiger using '(DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = db.blogspot.COM)(PORT = 1521)))(CONNECT_DATA =(SID = orcl)))';

Tuesday, September 16, 2008

Hack your Canon Powershot

Looks like programming has gone everywhere. Pretty soon, we should be able to hack into our car and make it do fancy things but for now, I found this interesting article on how to hack into your Cannon Powershot camera - found here.

Sunday, September 14, 2008

Working with Netbeans

Two of the most popular free Java IDE available are Eclipse and Netbeans. Personally, I prefer Netbeans because it is a lot similar to Visual Studio.

I have been using it since version 3.x and it is currently version 6.1.

.jarContent
In version, 5 and below, it has its only proprietary way of compiling into jar file. It has a a binary file with the extension .jarContent. This file content contains all the information needed to build build and create the jar package.

Pro:
I am able have many java files in one folder and create multiple .jarcontent file to create different .jar application with it (by right clicking on the .jarContent file and select build jar).

Con:
I cannot build the .jar file without netbeans since the manifest file is with the .jarcontent file and I need a special editor to access it.


Ant
In Netbeans 6.0 was converted to use ant instead. This proved have its own challenges. One thing is migrating my old code to the new environment. One option is to create project from existing sources but this did not work very well with me because I was not able to put my folder in the right place.

A much easier way is to:
  1. Create a new Java Project.
  2. Create the package with the src folder.
  3. Copy the original code into the package folder. So for example the package is com.blogspot.programmersjournal, the folder will be src\com\blogspot\programmersjournal\ inside the project folder.
I use SourceSafe to keep all my codes, I found that the critical files needed for the project are:
  • build.xml (which is in the root folder of the project)
  • nbproject folder (which contains the settings needed by netbeans).
  • src folder (which contains the source code).
The other folders are not necessary.
  • dist folder is deleted and recreated when you do clean and build.
  • libraries contains the .jar files you refer to.
  • Test Package is when you want to do unit test.




Other Netbeans 6.x Info

When you create an application, the manifest file is automatically generated for you. However, when you create a library, the manifest file is not automatic. You will need to create it manually (as a blank file) and then add the line inside the project.properties file just after meta.inf.dir entry:

manifest.file=${src.dir}/manifest.mf

I always like to make sure there is a manifest file in all my jar files so that I can check on the version.


By default, if you add reference to other .jar files, netbeans will create a lib folder below the dist folder and put a copy of those .jar files there. At the same, time, it will add lib/... inside the manifest file.

You can override it by placing your own Class-Path: inside the manifest file then the NetBeans will not override it. I do this because I am used to putting my reference library in the parent folder rather then in the child folder.

A few additional things I like about Netbeans are:
  • The plugins. It has a very rich library of plugins include UML, JavaFaces etc.
  • You can easily switch between different versions of Java - by clicking Tools->Platform.
  • It supports cvs, mecurial and subversion (Even though I use Visual SourceSafe in the office but I use subversion at home).
  • Its intellisense is as good as the ones in Visual Studio.
  • Formatting capability is good.
  • It doesn't add reference to strange libraries. JDeveloper from Oracle does that when you create a windows application.
Things I don't like:
  • With the new ant build, I have to create a different folder for each application project I am working on (even if it only contains one .java file.
  • Loading is slow (it chews up a lot of memory), so not useful if your computer is slow.
  • I have not been able to get the debugging to work correctly with line parameters. (it works fine without parameters).

Wednesday, September 10, 2008

Enabling Command line Completion

This is obtained from this site.

Command completion allows you to type a portion of a file name, and then have the system complete the rest by pressing the specified key. This is similar to the UNIX shell command completion feature.

Open your registry and find the key below. Create a new DWORD value, or modify the existing value, called 'CompletionChar' and set it to equal the hex value of the required control character. For example to use the TAB key set the value to '9', to use BackSpace set the value to '8', to use Ctrl-D set the value to '4' and for Ctrl-F set the value to '6'.

Exit your registry, you may need to restart Windows for the change to take effect.

Now when you type the first part of a filename then press the specified key, Windows will complete the filename for you. Pressing the key multiple times will scroll through all the options.

|NameTypeData|
|(Default)REG_SZ(value not set)|
|CompletionCharREG_DWORD0x00000009 (9)|
-
|HKEY_CURRENT_USER\Software\Microsoft\Command Processor|
-
Registry Settings
User Key: [HKEY_CURRENT_USER\Software\Microsoft\Command Processor]
System Key: [HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor]
Value Name: CompletionChar
Data Type: REG_DWORD (DWORD Value)
Value Data: Hex Control Character

Disclaimer: Modifying the registry can cause serious problems that may require you to reinstall your operating system. We cannot guarantee that problems resulting from modifications to the registry can be solved. Use the information provided at your own risk.

Monday, September 8, 2008

Classic ASP utilities - Sep 2008

The following are some functions that will facilitate coding in Classic ASP:
Serial Date

function serialdate(pdate)
' Parameter pdate is a date variable
' returned value is YYYYMMDD HH24MI
' uses function leadzero fill in leading zero
DIM tstr

tstr = year(pdate) & leadzero(month(pdate)) & leadzero(day(pdate)) & _
" " & leadzero(hour(pdate)) & leadzero(minute(pdate))
serialdate = tstr
end function


CheckBox
'==================================================================
' Subroutine to create a checkbox and decide if it should be selected or not
'==================================================================

Sub getCheck(cInput, cVal)

' Parameters are as follows:
' cInput - checkbox name
' cVal - status of checkbox (on or not)

Response.Write "<input type=""checkbox"" name="""
Response.Write cInput
Response.Write """"
if (cVal = "on") then
Response.Write " checked"
end if
Response.Write ">"
End Sub


To use above, you may create a checkbox as follows:



Check Buffer then flush the buffer
'==================================================================
' For checking the buffer count to decide if a response.flush is required
'==================================================================

function bufCheck(tCount)
tCount = tCount + 1
if (tCount > BuffLim) then
response.flush
bufCheck = 0
else
bufCheck = tCount
end if
end function


To use the above, declare a counter and a bufferlimit:

Dim cnt
Dim BuffLimit
BuffLimit = 50 'or whatever number you want



and then increment each time you do a response.write and then call the routine as follows:

cnt = cnt + 1
bufCheck(cnt)


This will reduce the amount of memory used on the server by flushing the buffer to the client once the limit is hit, otherwise it will wait until the asp is fully executed before sending the content to the client.

' =============================================================================
' Function to pad the string so that it has the length of tlen
' =============================================================================

function sp_pad(tString, tlen)
sp_pad = tString + space(tlen - len(tString))
end function


Radio Button
'============================
' For setting default value
'============================
sub defval(pfld, pval)
if pfld = "" then
pfld = pval
end if
end sub

'==================================================================
' check to see if the word checked should be written - used in conjunction
' with a radiobutton
'==================================================================

sub checked(pVar, pVal)
if pVar = pVal then
Response.Write("checked")
end if
end sub


Example of use is as follows:

<%
Dim cSel
cSel = request.form("carType")
defval cSel, "saloon"
%>

<input type="Radio" name="carType" value="saloon" <% checked cSel, "saloon" %>> Saloon
<input type="Radio" name="carType" value="4wd" <% checked cSel, "4wd" %>> 4 Wheel Drive

The above will look like this:

Thursday, September 4, 2008

Adding a dailog box to a webcontrol

To create a dialog box in a asp.net page, we need to use javascript to run on the browser and to add a javascript to a web control, we use webcontrol.attributes.add as in btnDelete.attributes.add("onclick", "return confirm('Are you sure you want to delete?');")

It is important when placing the javascript to end it with a ";". This is because, if the webcontrol autopostback attribute is set to true, the .Net will automatically add "__doPostBack(..." javascript to the control. The ; will be a valid divider to allow both javascripts to coexist and your added javascript will run first.

As for the rest of the java script, you can either add into your asp.net page via the literal webcontrol or code it directly into your aspx file.

One example to remind the person to add skirting in an automobile purchasing website could be as follows:

rbCarOpt.Attributes.Add("onclick", "alert('Did you remember to add skirting?');")

When the person selects Car (as opposed to truck), it will pop up a dialog asking if the customer remember to add the skirting option.

Addendum

If you want to have the alert appear in two lines then add \n to add new line. As in:

rbCarOpt.Attributes.Add("onclick", "alert('Did you remember to add skirting?\nThis will make your car look nicer.');")

will appear like this:


Wednesday, September 3, 2008

Java Configuration File vs .Net Configuration File

.Net

When using ASP.Net, the configuration file is known as web.config and is located in the root of the application folder (virtual folder designated application in IIS). For applications, the config file will follow the name of the application so if your Application is called StartProg.exe the config file will be StartProg.exe.config.

The config file is a xml file and the content will look something like this:
<configuration>
<appSettings>
<add key="orString" value="TestApp is logsmith;aaxx" />
</appSettings>
</configuration>
There are other sections in .Net configuration but I am only going to focus on the AppSettings.

To retrieve the information, you use: System.Configuration.ConfigurationSettings.AppSettings("orString").

In Framework 2.0, this has been change:
System.Configuration.ConfigurationManager.AppSettings("orString").

The value in the parameter is case sensitive. To retrieve the value, you do as follows:

Dim tmpStr As String

tmpStr =
System.Configuration.ConfigurationSettings.AppSettings("orString")

Java

Java does not have a default file naming convention, you can name it anyway you want. But to ease my finding, I will follow the .Net method which is to name the config file similar to the .jar file. So if the jar file is StartProg.jar, I will name my config file as StartProg.config.

In Java, your config file can be a xml or not. Here is a little program, I wrote to test the concept:

package com.testJavaApp;

import java.io.IOException;

/**
*
* @author strovek
*/
public class clsTest {

static String fName = "clsFile.config";
static String fName2 = "clsFile.config2";

public String getVer() {
String vVer = new String();

java.lang.Package p = this.getClass().getPackage();
vVer = p.getImplementationVersion();

return vVer;
}

public void writeProp() throws java.lang.Exception {
try {
java.util.Properties vProp = new java.util.Properties();
String tmpStr = new String();

tmpStr = "TestApp is logsmith;aaxx";

vProp.setProperty("orString", tmpStr);
java.io.FileOutputStream configFile = new java.io.FileOutputStream(fName);
vProp.storeToXML(configFile, "Configuration File");
configFile.close();
configFile = new java.io.FileOutputStream(fName2);
vProp.store(configFile, "Second File");
configFile.close();


} catch (java.lang.Exception ex) {
throw new java.lang.Exception("[clsTest01]" + ex.getMessage());
}
}

public void readProp() throws java.lang.Exception {
try {
java.util.Properties vProp = new java.util.Properties();
java.io.FileInputStream iFile = new java.io.FileInputStream(fName);

vProp.loadFromXML(iFile);
String tmpStr = new String();
tmpStr = vProp.getProperty("orString");
System.out.println("ConnString is \n" + tmpStr);

vProp = new java.util.Properties();
iFile = new java.io.FileInputStream(fName2);
vProp.load(iFile);
tmpStr = vProp.getProperty("orString");
System.out.println("ConnString is \n" + tmpStr);



} catch (java.lang.Exception ex) {
throw new java.lang.Exception("[readProp01]" + ex.getMessage());
}

}
}



The config file generated are as follows:

XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>Configuration File</comment>
<entry key="orString">TestApp is logsmith;aaxx</entry>
</properties>


nonXML

#Second File
#Fri Aug 29 11:43:43 SGT 2008
orString=TestApp is logsmith;aaxx

As you can see from the sample program, java.util.Properties is the class to read and write the configuration file. A few things to note:
  • use .loadFromXML if the configuration file is in XML format.
  • use .load for nonXML.
  • use FileInputStream to read, then you can specify the config file name to load
  • use FileOutputStream to write the configuration file (the whole configuration).
  • use .storeToXML to create a XML configuration file.
  • use .store to create a nonXML configuration file.
I use the above sample file to provide me a template to create subsequent configuration file for my other projects.

Saturday, August 30, 2008

Writing game in Java

I was curious about what it takes to write a game program. I came across the following website which provides me enough information to get started. The website contains a complete draft of Killer Game Programming in Java. It contains enough information to understand what it takes to write a game. A few key things it mentioned was:
  • Controlling the image refresh (that's why you need to write your own graphic refresh mechanism instead of using the built in mechanism) - this is also known as sprite.
  • Difference between writing in full screen mode vs windows mode.
  • Discussion on animation, 3D etc.

I found the draft enough to sooth my appetite but if you want a more updated info then you can get the book latest revision of the book. It has been revised several times since the draft. Here is the link to the book in Amazon:
Killer Game Programming in Java