On CBSSports.com: Chance for Championship, #2 Fla @ #1 Ala
BNET Business Network:
BNET
TechRepublic
ZDNet

By John Carroll
Posted on ZDNet News: May 6, 2003 5:20:00 PM

COMMENTARY--I used to collect comic books (or, read a heck of a lot of them and refused to throw them away, depending on how you look at it). That's impossible, you're saying. Programmers are serious people who don't have time for comic books, science fiction, role-playing games, and strange fascinations with a certain "Weird Al" Yankovic's cinematic magnum opus. But, surprising as it might seem, I did.

I remember a certain hard-drinking character from a Hercules Limited Series by Marvel comics who resembled a small ninja turtle, sans mask. Well, to borrow a term used by this unknown character (the meaning of which I can't remember), I've been working my scroggies off.

Given that my brain happens to be stuck deep in programming la la land (as opposed to where it normally sits, which is in a jar, labeled "Abby Normal"), I'm going to take a detour from my usual obsession with the state of the software industry and discuss some of the ways .Net is an improvement over Java. As I've noted before in Talkbacks, I've been programming Java in some form since JDK 1.0. Java development has a number of advantages over traditional environments which output machine language. .Net has the advantage of hindsight, however, and has improved on Java in a number of areas. Here are some that stand out from my most recent project (I could tell you what that project's all about, but then I'd have to eat you).

It's worth noting that this article is somewhat more technical than my norm. This is unavoidable, as .Net, like Java, is essentially technology for enhancing developer productivity. Besides, at this point, I'd probably find a way to make Dr. Seuss stories sound complicated.

1. Standardized configuration:
Java configuration is for the most part oriented around property files, which are simple name-value pairs separated by equal signs in a text file. Property parsers are included as part of Java, and the java runtime executable (java.exe on Windows) accepts named properties on the command line that are included with System properties (which are a centralized repository for global properties).

Though XML parsers certainly exist for Java, Java components don't tend to be configured by XML files, particularly the components included as part of the core JDK. This isn't an oversight on the part of Java. Java came of age prior to the popularity of XML, and property files were a simple and easy way to allow administrators to configure applications with a text editor.

In contrast, XML permeates every corner of .Net. So important is XML to .Net that the core CLR, the portion standardized by the ECMA and on its way to IEEE standardization, includes XML parsing libraries. This means that every conformant CLR of necessity must include XML parsing libraries.

XML is infinitely more flexible than property files, and that makes it a better standard configuration technology than property files. Lists of values are easier to represent in XML, the range of parsing technologies is larger, and the format is familiar to anyone accustomed to HTML.

XML usage in .Net really stands out in the .Net configuration system. .Net configuration files contain XML, which conforms to a simple XML grammar. The name of this file depends on the type of application that is being run. For executable desktop programs (on Windows, ending in .exe), the name of the file is the name of the executable followed by ".config" (example: myapp.exe.config for a program named myapp.exe). In ASP.Net, this configuration file is called web.config, and is located at the root of the web application directory.

The standard XML grammar for .Net configuration files is astoundingly simple. The base schema defines little more than tags by which to define custom XML parsing handlers. These handlers are called during AppDomain startup (the .Net abstraction for the .Net runtime, which I'll discuss later), and they return data objects which are cached at application scope and retrieved at runtime using the central ConfigurationSettings.GetConfig method.

Handler creation is simple. As shown in this example, custom handlers merely implement the System.Configuration.IConfigurationSectionHandler. They are declared for local application using a "section" entry under the "configSections" block of the .Net configuration file. This defines the XML element names that will contain custom XML parsed by your custom handler.

Microsoft includes machine-wide XML parsing handlers inside the centralized machine.config configuration file, which is a file from which every configuration file implicitly inherits. All configuration syntax used by components in the .Net Framework is implemented somewhere by a set of configuration handlers specified at some level in the hierarchy of .Net configuration files. You can extend this machine-wide configuration base by adding your own handlers to this machine.config file, or if the need arises, override existing handlers to handle custom configuration logic.

For Java developers, the biggest advantage to .Net's configuration system is an end to property file proliferation. Property files multiply like rabbits in a large, Java-based web application, where aggregation of numerous third-party subcomponents is the norm. Since there is no global, process wide Java configuration standard, each subcomponent specifies its own configuration property file (the names of which, hopefully, won't clash) which must be included somewhere in the classpath (the classpath specifies where the Java management process (or "runtime") should look for the files it needs in the course of running a program).

With .Net, every component knows to retrieve its configuration information from ConfigurationSettings.GetConfig, the data for which is built from a hierarchy of configuration files. This greatly simplifies administration of applications, and in my experience, has been tremendously useful as a development option.

2. Extensible metadata
Anyone who has developed in Java has encountered the wonders of the Java Reflection system. Reflection is the term used to describe the ability to retrieve type information about a Java class at runtime. Through Reflection, a Java class will tell you about the methods it contains, whether they are public or private, the arguments it expects, the member variables contained inside the class, etc. You can even programmatically call methods and retrieve data from class members, something of use to script writers who require the ability to "bind" to methods at runtime.

Java Reflection goes way beyond the clunky IDL-derived type information found in CORBA and COM, as it is built on the information contained in the bytecodes used to represent the Java class. It was an innovation made possible by Java's transparent and well-defined internal structure, which just so happened to be the same feature that made it possible to run Java on multiple machine architectures.

Not being the sort to ignore good ideas, Microsoft has included Reflection in .Net, and has ensured that it is defined as part of the core CLR (in other words, every conformant .Net runtime must support reflection). Microsoft, however, has taken reflection to the next level, allowing programmers to include custom information with a .Net class which can be retrieved using the .Net reflection APIs.

This out of band information is used extensively by the .Net security system. By "tagging" methods with out of band custom attributes, programmers can tell the .Net security subsystem what sort of access rights it requires, or conversely, what rights it wants to ensure callers do not have. For instance, the ability to display a user interface is controlled by a "permission," and all code that is used to paint user interfaces (WinForms, as an example) is marked with a "Demand" for UI access. Code running in a context without this permission (in a daemon process, for instance) cannot display a user interface.

In ASP.Net, SOAP extensions allow developers to customize the incoming and outgoing XML stream. This customization is triggered through the use of a simple out of band metadata "tag" that informs the SOAP message filters of the class which needs to be loaded to customize the SOAP stream of data. This out of band information is retrieved at runtime using .Net Reflection.

It is very easy to tag methods and classes with existing attributes in the .Net system. As this example shows (which is taken straight out of my CLR Proc Container freeware, the source code for which is now available for download), it is also easy to create custom attributes to carry out of band information of interest to your program.

Customizable type information is an important addition to a programmer's toolbox, and even more important, makes your program simpler and easier to manage.

3. Assemblies
Assemblies are the unit of distribution for .Net code. In some ways, they are akin to Java jar files. Java classes are composed of bytecodes that can be written individually to a disk. If you've ever seen a directory containing a bunch of files with a ".class" extension, then you've seen Java class files in all their uncompressed glory. Jar files use PKZ compression (the same algorithm used in ZIP files) to include multiple compressed java class files into a single unit of distribution. Often this file includes a text-based "manifest" which is used to provide certain details about the contents of the Jar file. Enterprise Java Beans (EJBs) require custom entries in this manifest files, which are used to describe the contents of a jar file to the Java runtime environment.

Assemblies serve a similar purpose, yet are decidedly different in style to jar files. Granted, they are used to package multiple class files into one distribution unit, but for that matter, Assemblies are the ONLY distribution unit for .Net classes since there is no such thing as a .Net ".class" file which sits on a disk drive as a separate entity. Assemblies, however, are a "harder" concept than jars, as they have unique identities in ways that jar files simply do not.

As a "reflection" of the importance of Assemblies, you can retrieve the Assembly from which a .Net class was loaded using the .Net Reflection APIs. On any object, you can call GetType().Assembly to determine details of the assembly which defined the loaded class. The nearest comparable capability in Java is through use of the java.lang.Class.getPackage() method, though the amount of functionality available from an Assembly far exceeds what is available from the java.lang.Package object.

The Assembly provides a great deal of useful information. Highlights include disk location of the assembly (normal in Windows dll's), version (the format of which is standardized, in contrast to the various java.lang.Package version properties, all of which are strings), and custom information included as part of the assembly during compilation. Assemblies always know the location from which they were loaded. This creates useful possibilities, such as applications that know how to look for certain pieces of information relative to the location of the Assembly on disk. Assemblies can also contain certain bits of custom information (e.g. Assembly-level metadata attributes) that can be used during runtime to control what rights code in the assembly has, or whether it is allowed to be loaded at all.

Lastly, Assemblies can have cryptographically strong identities which can be used to programmatically distinguish them from each other. Such "strong named" assemblies have been signed with a private key, and it is this strong identity which allows .Net to run different versions of the same dll in parallel.

The importance of this should be apparent to any Java programmer who has been forced to navigate the Java XML minefield on a large website that integrates products developed by a number of third parties. In Java, only ONE library that conforms to a certain interface convention gets loaded, usually the first one it comes across in the classpath. But all XML parsers implement the same set of interfaces, and thus are replaceable for one another, right? Wrong. First, there are a number of differences between versions of the XML interfaces. Second, even when they theoretically conform to the same interface, there are differences in implementation. For instance, one version might properly protect against simultaneous access from multiple threads, while another won't.

XML is used by a lot of Java products these days. Unfortunately, though there seems to be a certain de facto convergence around the Apache Xerces parser, that convergence isn't universal, and it certainly doesn't imply convergence around the same Xerces parser version. There are workarounds, of course. You can do as I did and write a custom Java classloader that isolates a third-party product from the libraries loaded by the parent web application. That, however, is a non-standard solution, and a standard solution included as part of the base runtime would be a vast improvement. .Net offers such a solution in its ability to run multiple versions of an assembly simultaneously within the same AppDomain.

4. .Net Remoting
.Net Remoting is the manner in which .Net makes objects callable over a network. In that sense, it is like Java RMI, Java's solution for making objects accessible over a network On the other hand, .Net Remoting bears more in common with multi-language interoperability infrastructures like CORBA than RMI. In contrast to RMI's emphasis on Java-only development (JRMF, RMI's default protocol, is particular to Java, in that it relies on the Java serialization format), .Net Remoting emphasizes flexibility and extensibility.

.Net Remoting doesn't define a standard protocol. Rather, it is little more than a set of configurable "channels" (transport layer handlers for dispatch over a network), Formatters (for defining the format into which objects will be serialized for transport over a network) and message sinks (for message customization). The standard channels included with the .Net Framework are the TcpChannel (for sending data over socket connections) and HttpChannel (for sending over http, a protocol layer on top of a socket). The standard formatters are a Binary formatter, which, like JRMP, is more intended for .Net to .Net communication, and a SOAP formatter.

Invocation of a remote object is set up as a chain of messaging handlers (including transport channels and formatters as special types of messaging handlers) that work together to make a call across a network. Channels for dispatch via SMTP or MSMQ exist in the wild, as do formatters that support XML-RPC.

One of the more interesting thing about .Net Remoting, however, is the ability to configure remote objects using only external configuration files. The full class name of the object to be exposed, whether or not it is a singleton or a single call object, the transport it will use, what formatter it will use, and whether any custom messaging filters should be interposed somewhere in the messaging chain are all defined in the text-based XML configuration file for an application. This offers tremendous flexibility for applications which need it, as complex details about the characteristics of a remotely-accessible object can be tuned external to the compiled application.

This is why I have been so adamant in the past that SOAP is no more a required part of .Net than any other protocol used for sending object data across a network. The SOAP Formatter is merely one option available as a serialization format. ANYONE can create their own formatter and use it in place of the SOAP Formatter with little more than a change in a configuration file entry. In other words, if for whatever reason a company decides to shift to XML RPC from SOAP, all they'd have to do is get an XML RPC Formatter and specify its use in the configuration file.

.Net Remoting is interesting technology, and even better, the full source code for a working implementation is included with the Rotor .Net CLR implementation (you can see it online here). Creating your own .Net Remoting extensions can be complicated, which is why access to the source for a working implementation is indispensable (and though I can't say for sure, I suspect from my own use of that code that it bears a strong resemblance to the code that actually ships with the .Net Framework).

For a great book on .Net Remoting, check out Ingo Rammer's "Advanced .Net Remoting", from a! press.

Conclusion
These are only some of the highlights of development with .Net. Add to this a greatly streamlined development API, development tools that make their Java-oriented equivalent look like tinker toys, improved date handling (I really wish they had just opted to break old Java code and fix the bloody java.util.Date object), simple and efficient localization (based on precompiled resource files), tremendous support for application internationalization, AppDomains (goodbye JNI C-language VM manipulation functions and ClassLoaders), ASP.Net (coming soon to an Apache web server near you), ridiculously easy web service support (.asmx files are great), simple native code invocation (for those who need such things), event delegates (I love 'em, as they suit 99% of all my event handling needs, without preventing me from using interface-based event handling when I need it), standardization of the core through the ECMA and IEEE, support for "shadow-copying" of assemblies, great documentation (something Microsoft is singularly good at), etc, and you have an environment which is a vast improvement over Java. Can Java be made to do many of the technical things .Net can do? Probably. But that doesn't mean that it is easy to do those things in Java, nor that toolmakers and programmers will be able to predict those features will always exist.

Of course, .Net is still a mostly Windows party, while Java offers the chance to work on a large number of platforms. As I've noted, however, Mono offers a complete implementation of the .Net Framework for Linux, and there are companies already who promote their .Net product's support for non-Microsoft systems. This support has nowhere to go but up, as technology innovators with an interest in non-Microsoft platforms see a business opportunity in offering Windows support alongside support for their favorite platform. It's certainly easier to make a business case for that client-side Linux startup when you can promote your products support for the large installed base of Windows users.

People have a number of reasons for favoring one programming environment over another. For those attracted by good technology, .Net is worth a look.

biography
John Carroll is a software engineer living in Ireland. He specializes in the design and development of distributed systems using Java and .Net. He is also the founder of Turtleneck Software.

Note: It is possible to determine the location from which a class was loaded. The method to use is:

java.lang.Class.getProtectionDomain().getCodeSource().getLocation()

This method returns a java.net.URL object.

  • Talkback
  • Most Recent of 1 Talkback(s)
how much did Microsoft pay for that?  marcinn | 06/11/04

What do you think?

advertisement
advertisement
advertisement
Click Here