Friday, March 21, 2008

Converting to a different timezone using C#

Here is some code that I like to use for converting between timezone using C#. There are two methods. One that uses DateTime and the other uses DateTime? which can be null.
/// <summary> /// Converts a date that is assumed to be have an offset from UTC of sourceUtcOffset to an offset from UTC of targetUtcOffset /// </summary> /// <param name="sourceDate">The date and time that needs to be converted</param> /// <param name="sourceUtcOffset">The offset from UTC of the sourceDate</param> /// <param name="targetUtcOffset">The offset from UTC of the timezone that the DateTime should be converted to.</param> /// <returns>A DateTime that has been adjusted to the offset from UTC of targetUtcOffset</returns> public static DateTime ConvertDateTime2AnotherTimezone(DateTime sourceDate, int sourceUtcOffset, int targetUtcOffset) { DateTime asUtcDateTime = sourceDate.AddHours(sourceUtcOffset); DateTime targetDateTime = asUtcDateTime.AddHours(targetUtcOffset); return targetDateTime; }
/// <summary> /// Converts a date that is assumed to be have an offset from UTC of sourceUtcOffset to an offset from UTC of targetUtcOffset /// </summary> /// <param name="sourceDate">The date and time that needs to be converted</param> /// <param name="sourceUtcOffset">The offset from UTC of the sourceDate</param> /// <param name="targetUtcOffset">The offset from UTC of the timezone that the DateTime should be converted to.</param> /// <returns>A DateTime that has been adjusted to the offset from UTC of targetUtcOffset</returns> public static DateTime? ConvertDateTime2AnotherTimezone(DateTime? sourceDate, int sourceUtcOffset, int targetUtcOffset) { if (sourceDate.HasValue) { DateTime nonNullSourceDate = sourceDate.Value; DateTime asUtcDateTime = nonNullSourceDate.AddHours(-1 * sourceUtcOffset); DateTime targetDateTime = asUtcDateTime.AddHours(targetUtcOffset); return new DateTime?(targetDateTime); } // if there is no value, then it is null, and thus we have nothing to convert else { return sourceDate; } }

Thursday, March 20, 2008

Lessons learned with Web Services in Eclipse 6

I am using MyEclipse 6. It is quite nice. I learned the hard way were to find some resources and how to do things like Exception handling. I found the process to be much more difficult and the learning curve much steeper than I thought it would be. Here are some things I learned. MyEclipse has a project type called Web Service Project. Use this to start a new project that will be your web service. It also allows you to use XFire web services (not CXF until version ?? of MyEclipse). You can use Java 1.5 or Java 5. Getting Started:
Start with the tutorial I mention in my blog to get started: http://www.myeclipseide.com/documentation/quickstarts/webservices/
Examples: Get the XFire distribution (http://xfire.codehaus.org/Download and pick the Binary Distribution in zip package for the newest release) because it has some good examples in it. I didn't find this until way too late. You can also download the source code for XFire on this page if you want to also. Once you download the zip I highly recommend the Book example. It shows how to return complex types, and how to create your own custom exceptions. How to store application settings
I am sure there are many ways to do this... check out my blog on: http://justgeeks.blogspot.com/2008/03/storing-application-settings-in.html Make Complex types that use java.util.Date as a data type be nillable when generated in the WSDL.
The basic solution is create a file called YourClassNameHere.aegis.xml and put it in the same location as the class that defines the complex type that contains the java.util.Date property. In the file, do something like this:
<mappings>
<mapping>
<property name="datePropertyName" nillable="true"/>
<property name="anotherDatePropertyName" nillable="true"/>
</mapping>
</mappings>
Now your automatically generated WSDL will have nillable="true" for the properties that you specified in the mapping file. This is particular important when using ASP.Net 2.0 and Nullable Types to consume your web service. It means the difference between DataTime and DateTime?. For more details check out: http://www.nileshk.com/node/69#comment-12609 Exception Handling You can follow the example in the Book example noted above, or you can do it another way also. You can do much like they did in the Book example, except just have your custom exception class extend java.lang.Exception instead of the XFire specific type. This will cause your custom exception class to be serialized and set as the Detail property in the SoapException. You can then parse it using a standard XML parser on the client side. You will be catching an Exception of type SoapException on ASP.Net. If you want your properties of your custom exception class to show up in the serialized text, you will need to make sure that you have setters and getters for each member variable in your class. One key is that your web methods must explicitly throw your custom exception, not just java.lang.Exception. If you don't, the Detail property of the SoapException won't be filled in when it is serialized and sent to your client (web service consumer). This basically tells Aegis to use our custom exception type instead of just java.lang.Exception. Changing parameters (in0, in1, in2, etc) to the real names when the WSDL is generated. I searched long and hard to find a simple solution for this one. Much to my amazement there did not seem to be too many intuitive solutions. I picked the easiest one. My solution is very simple and requires no maintenance. It seems to be a bug to me, so.... Do just like the tutorial referenced in the Getting Starting section of this blog and add the new web service just as says EXCEPT when you get to the page that asks you for the Service Interface and Service impl. class, set the Service interface to the same thing as Service impl class. This will affect your server.xml file. Finish the wizard as noted in the tutorial. Next, open the xxxImpl.java file and remove the implements xxxx from the class declaration such that it does not implement the interface file. If there is an interface file you can safely remove it from your project now. You will never need it now. Now, when the WSDL is generated it will use the proper parameter names as you would expect. Go figure! Word of caution, I did not have as much luck doing effectively manually doing the same thing AFTER I did the wizard as the tutorial suggests. So, I suggest doing it from the start when you do it in the wizard. I also found that I couldn't query the for the WSDL without my CPU going to nearly 100% when I did it manually. I don't really know why, but it did. I suspected that maybe I just had to many methods in my class and was slowing the parsing of the class to generate the WSDL or something, so I put all my real code in another class and just have stub like web methods that simply call the other object and a method on it. This seemed to help, but all these issues could have been do to needing a reboot and trying too many different things and messing up some files. Hard to tell, so let me know if anyone else has a similar experience. Other Tips Make your life easier, just forget about getting access to the Request and other servlet type things. It is just too much of a pain. Stay away from web.xml when it comes to storing application settings. Accessing it programmatically seems to be container (application server) specific, so use a properties file or xml file.

Storing application settings in a property file

This is not a totally necessary class, but it doesn't abstract loading text from a properties file. For example if you need to store application specific settings or even localizations you can use this class to access it using flexible paths (dot notation or directory path style). Here is how to use it: Properties props = PropertyLoader.loadProperties("/some/package/Config.properties"); String val = props.getProperty(key); package mypackage;
import java.util.ResourceBundle; import java.util.Properties; import java.io.InputStream; import java.util.Locale; import java.util.Enumeration;
public class PropertyLoader { /** Creates a new instance of PropertyLoader */ public PropertyLoader() { } /** * Looks up a resource named 'name' in the classpath. The resource must map * to a file with .properties extention. The name is assumed to be absolute * and can use either "/" or "." for package segment separation with an * optional leading "/" and optional ".properties" suffix. Thus, the * following names refer to the same resource: * <pre> * some.pkg.Resource * some.pkg.Resource.properties * some/pkg/Resource * some/pkg/Resource.properties * /some/pkg/Resource * /some/pkg/Resource.properties * </pre> * * @param name classpath resource name [may not be null] * @param loader classloader through which to load the resource [null * is equivalent to the application loader] * * @return resource converted to java.util.Properties [may be null if the * resource was not found and THROW_ON_LOAD_FAILURE is false] * @throws IllegalArgumentException if the resource was not found and * THROW_ON_LOAD_FAILURE is true */ public static Properties loadProperties (String name, ClassLoader loader) { if (name == null) throw new IllegalArgumentException ("null input: name"); if (name.startsWith ("/")) name = name.substring (1); if (name.endsWith (SUFFIX)) name = name.substring (0, name.length () - SUFFIX.length ()); Properties result = null; InputStream in = null; try { if (loader == null) loader = ClassLoader.getSystemClassLoader (); if (LOAD_AS_RESOURCE_BUNDLE) { name = name.replace ('/', '.'); // Throws MissingResourceException on lookup failures: final ResourceBundle rb = ResourceBundle.getBundle (name, Locale.getDefault (), loader); result = new Properties (); for (Enumeration keys = rb.getKeys (); keys.hasMoreElements ();) { final String key = (String) keys.nextElement (); final String value = rb.getString (key); result.put (key, value); } } else { name = name.replace ('.', '/'); if (! name.endsWith (SUFFIX)) name = name.concat (SUFFIX); // Returns null on lookup failures: in = loader.getResourceAsStream (name); if (in != null) { result = new Properties (); result.load (in); // Can throw IOException } } } catch (Exception e) { result = null; } finally { if (in != null) try { in.close (); } catch (Throwable ignore) {} } if (THROW_ON_LOAD_FAILURE && (result == null)) { throw new IllegalArgumentException ("could not load [" + name + "]"+ " as " + (LOAD_AS_RESOURCE_BUNDLE ? "a resource bundle" : "a classloader resource")); } return result; } public static Properties loadProperties (final String name) { return loadProperties (name, Thread.currentThread ().getContextClassLoader ()); } private static final boolean THROW_ON_LOAD_FAILURE = true; private static final boolean LOAD_AS_RESOURCE_BUNDLE = true; // if true localization and caching is used. private static final String SUFFIX = ".properties"; }

Monday, March 17, 2008

Creating a web service in MyEclipse 5 or 6 and deploying to Tomcat application server.

Creating a web service in MyEclipse 5 or 6 and deploying to Tomcat application server.
Well, I can't say it is difficult, but I think the link below that points to a MyEclipse tutorial is great. It gave me everything I needed to get started.
The tutorial is also in the documentation included in MyEclipse 6 (maybe 5 also, I don't know). The tutorial is called "MyEclipse Code-First Web Services Tutorial" if you want to search the included doc for it. It is the same either way. Your choice. ;)
Enjoy!

Thursday, March 6, 2008

Setting Default page in JSF

I am assuming you have a JSF application that runs in Tomcat, and that you are using MyEclipse as your IDE (though it isn't really that important. What I wanted to do was instead of a url that included the specific default page, I wanted the ability for users to assume a default page in the url. For example: Users could put in the browser: http://myhost:8080/MyJSFApp/MyJSFPage.faces What I want them to also be able to do that will get them to the same page as if they had typed the above url. http://myhost:8080/MyJSFApp or
http://myhost:8080/MyJSFApp/
To make this work, there is a little trickery that we need to do. Step 1: Create a new JSP page called index.jsp (it could be called anything) Step 2: The only thing you need in the index.jsp file is: <jsp:forward page="/MyJSFPage.faces"/> At this point you should be able to type the following into the browser and have it redirect (without the url changing) to the MyJSFPage.faces page. http://myhost:8080/MyJSFApp/index.jsp Step 3: Now all we have to do is edit the web.xml file. You will most likely have a welcome-file-list tag already in the file. Change it (or add it if it doesn't exist) to the following (or similar for your application).

<welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> That's it. Side Notes This all assumes that JSF is using the .faces pattern to designate what a JSF page is. The whole reason we need the first two steps to create the index.jsp file is because the welcome-file tag must point to a file that actually exists in the file system. It can't be a .faces file, because it doesn't actually exist. Has anyone tried it such that JSF is setup to use a pattern like /faces/* instead of *.faces?. I have not tried it, but I think the same problem would exist because the faces directory directory doesn't exist either. Feedback is welcome on this issue. Instead of the JSP forward tag, you could use pageContext.forward("/MyJSFPage.faces") or requestDispatcher.forward("/MyJSFPage.faces") and the behavior would be the same. On the other hand if you want the url to change to the url of the new page in the browser, you could use response.sendRedirect("...") which can redirect to any page on any server (any url really). The difference is that this sends a response to the browser that sends back an immediate request to the url that you wanted to redirect to. This is slower, but may be the behavior that you need in some cases.

Wednesday, March 5, 2008

PHP MS SQL extension connection bug

I found out the hard way that when I installed PHP Eclipse and select MS SQL plugin in the installer, it installs ntwdblib.dll in the same directory as php.exe. This is fine, except that the version that it installs is BUGGY! It doesn't seem to support anything but using Windows Authentication when I try to connect to the database. There is an option in the php.ini that is support to let you change this so that it will use SQL Server logins, but it doesn't use the option, it simply ignores it! When trying to connect to a database using something like: $c = @mssql_connect("mydbserver","sqlUserHere","password", true) It says it cannot connect when I run it from IIS which uses anonymous user. It does work if I use php.exe -f test.php since this process runs as me, and I have access to the database.
That is the general idea of the problem.
Here is what I found.
The version of ntwdblib.dll that is installed by the PHP installer is 2000.2.8.0. The version you need to fix this bug is: 2000.80.194.0. As it turns out MANY people have had the same problem. Read the numerous posts on this here.
This is a good page to use for all problems with the MS SQL PHP extension.
I hope this helps.
Brent

Monday, March 3, 2008

Installing PHP on Windows

PHP is in many ways like ASP or JSP. In this blog entry I will share some of the things I ran into while installing PHP on Windows and IIS 5 (IIS that comes with Windows XP Professional). First download the software: http://us2.php.net/get/php-5.2.5-Win32.zip/from/a/mirror/php-5.2.5-Win32.zip Run the installer. I recommend installing PHP at C:\PHP instead of C:\Program Files\PHP. Do NOT select all extensions as some of them have other prerequisites that can make your installation not work. Installing more extensions than needed complicates troubleshooting. You can always to go Add/Remove Programs again and add more extensions after you know the basic installation works fine.
After you run the installer, there are some things you may need to do to get things to work properly.
You will want to set some environment variables in Windows. 1. Append C:\PHP; to the Path Windows Environment Variable. 2. Create a new Windows Environment Variable called PHPRC and set it to c:\PHP\php.ini assuming you installed PHP at c:\PHP. This will tell Windows where the php.ini file is should it get confused. You can verify that PHP knows were your php.ini file is by using the test page shown later in this blog. On the test page, verify that the line labeled "Loaded Configuration File" should be c:\PHP\php.ini. You will probably need to restart IIS for it to see the new environment variable. You will want to make sure that PHP is properly configured in IIS. Get Properties on Start Menu | Admin Tools | Internet Information Services | <machine> | Web Sites. On the Home Directory tab, click the Configuration button. In the Application Configuration dialog click the line with .php as the extension, then click the Edit button. On the "Add/Edit Application Extension Mapping" make sure the fields have the values: .php, C:\PHP\php5isapi.dll, All Verbs, Script Engine checkbox is checked, and Check that files exists checkbox is checked. The installer will put a DOS style path instead of C:\PHP\php5isapi.dll. This is probably ok, but if you have problems try the full win32 path as noted here. To verify that the installation was successful, all you have to do is use your favorite text editor to create a .php file and access it. I recommend the contents of the file be the following as it will prove several things: 1. That IIS is handing off the request to Php5isapi.dll 2. That PHP tags are being interpreted properly by PHP 3. Give you lots of information related to how PHP is configured. <html><head><title>Test PHP Page</title></head> <body> Success for PHP <?php echo "Hello PHP Scripting"; ?> </body> </html>

If you have any trouble I suggest that you read this article on how to manually install PHP. It will give you a better understanding of what the installer does, and how PHP works.

http://www.iis-aid.com/articles/how_to_guides/installing_php_5_on_iis_in_5_simple_steps?page=0%2C0

For more information on doing development in an IDE with a debugger, check out my other blog entry titled "PHP Development Environment."

PHP Development Environment

Let me first start by saying that I have only started using PHP because I have to maintain a project that was written in PHP, so my experience is quite limited. However, I figure many others may be in the same situation. At the very least I wanted to note all the things I had to do to get my project to work. There are some very basic things I expect when doing development. 1. An IDE 2. A debugger that is integrated into the IDE 3. Stability in the IDE and debugger. This was not as easy as I thought it would be. However, after reading some blogs, etc, I determined there is at least one free option that actually work pretty well. Please read my comments below to better understand why I chose the tools I chose. The IDE is most important to me. Beyond the requirements above, I need it to be free because the project I am working on doesn't have a budget to buy us a pricey IDE. The IDE I like is PHP Development Tools (PDT), which is basically an Eclipse plug-in that allows you to do PHP development (including debugging) in the Eclipse IDE. Eclipse is a stable IDE with lots of features and is the same as what I use for Java development so the learning curve is smaller. I also tried Maguma Studio IDE and found it to be EXTREMELY frustrating. My scroll wheel crashes the IDE every time I touch it, and I do that a lot without even thinking about it. It also didn't seem to support virtual directories, so my projects had to be in my web root, which was not what I like to do. The debugger required regularly changing my php.ini if I remember correctly, which was more work than I felt I should have to do. If you those things don't bother you, you may like this product. There are a couple of debuggers out there, but I recommend the Zend debugger as it seems to work well with complex projects that have nested directories of source code. It Debuggers for PHP come in different flavors and are compatible with different products and different versions of products. I found this VERY confusing and a hassle to get my IDE and debugger working together. For this reason, I STRONGLY recommend that you use an all in one download / installation. This more or less guarantees the IDE and debugger will work together and with any luck even be pre-configured which can save you time. I believe the debugger choices are:
1. Zend Debugger
2. XDebug 3. DBG
I have not personally used anything except Zend Debugger, but my co-worker has, and he had trouble with nested directories and just generally getting it to work.
I like the Zend Debugger for several reasons.
1. I can download an all-in-one that includes the Zend and XDebug debuggers) and it fast to download (the site is fast)
2. It is comes pre-configured
3. It seems to work on nested directory structure
4. Seems stable
5. It works with the latest version (3.3.1.1) of Eclipse IDE
6. Use the newest PDT 1.0.2 (R2008010)
OK, now that you understand a little more of what I chose and why, here are the links to the downloads.
All-in-one download that includes Zend and XDebug debuggers, Eclipse IDE 3.3.1.1, PDT 1.0.2 (R20080103) http://downloads.zend.com/pdt/all-in-one/dt-1.0.2.R20080103_debugger-5.2.12.v20071210-all-in-one-win32.zip
If you don't want / need the Zend debugger I have heard good things about the PDT all by itself, but the site is much slower, and you won't get the Zend debugger, but it is the best place to get the latest PDT (I think) http://download.eclipse.org/tools/pdt/downloads/release.php?release=R20080103
You will also need the Java Runtime (JRE 5) to run the IDE. The JDK should also work if you already have it installed. http://java.sun.com/javase/downloads/index_jdk5.jsp
PHP (I don't actually recommend you install PHP separately since PDT comes with it. There are some things you will want to do if you want to run your project without the IDE on your machine. See http://www.nusphere.com/kb/phpmanual/install.windows.iis.htm).
A few tips: You will want to set the .php extension to point to something like: "C:\Program Files\pdt-1.0.2.R20080103_debugger-5.2.12.v20071210-all-in-one-win32\eclipse\plugins\org.zend.php.debug.debugger.win32.x86_5.2.12.v20071210\resources\php5\php-cgi.exe" You can do this at the Default Web Site level. However, in IIS those changes are COPIED when you create a virtual directory to your project (assuming you use a virtual directory and not just put your project in the web root itself). This means that If you set the .php extension BEFORE you create the virtual directory it will COPY that extension to the virtual directory extensions. However, if you set the .php extension AFTER you create the virtual directory, you will need to also put it in the extensions for that virtual directory.