Rounded Rectangle: JNDI Service Provider for Windows® Registries






Jeff Lawson
 

Rounded Rectangle: Overview

·	Introduction to Windows® Registries

·	Windows® Registries are Naming Services

·	 Accessing System Settings

·	 Accessing User Settings

·	 Security

·	 Java™ Objects

·	 Federation

·	 Event Notification

·	 Summary
 

Rounded Rectangle: Introduction to Windows® Registries

·	Windows registries hold system and user configuration data

·	Available on:
§	NT-class systems: Windows NT/2000/XP
§	Down-level systems:  Windows 95/98/Me

·	Accessible locally and remotely 

·	Hierarchical database that is transactional on NT-class systems

·	Supports several data types:
§	REG_DWORD — 32-bit integer
§	REG_STRING — single-line string
§	REG_MULTI_SZ — multi-line string
§	REG_BINARY — any data, e.g. Java™ objects
 

Rounded Rectangle: Windows® Registries are Naming Services

·	Bindings are called registry values and take the form:

<name>	<type>	<data>
e.g.	JAVA_HOME	REG_SZ	E:\Java\jdk1.3\

·	Naming contexts are called registry keys; they contain values and subkeys (subcontexts)

·	Windows registries are not directory services — no attributes

·	Registry paths use backslash as a name component separator so they have strong separation in composite names:

…/MyApp\1.0\PrimaryDataSource/…
		actually:	…/MyApp\\1.0\\PrimaryDataSource/…
 

Rounded Rectangle: Accessing System Settings

·	System settings are held in:

		HKEY_LOCAL_MACHINE

which has parts aliased as:

	HKEY_CLASSES_ROOT
		HKEY_PERFORMANCE_DATA	(Windows NT/2000/XP only)
HKEY_DYN_DATA				(Windows 95/98/Me only)

·	System settings cover:
§	Hardware:	disk drives, network adapters, display,
mouse, print devices, memory, etc.
§	Security:	users and groups
§	Software:	applications, user interface, COM
§	System:		services, drivers, control, hardware profiles

Rounded Rectangle:
 

Rounded Rectangle: Sample Code

import java.util.*;
import javax.naming.*;
// …
try
{
    // Set up to use Winreg factory
    Hashtable env = new Hashtable(5, 0.75f);
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.cogentlogic.jndi.winreg.WinregInitContextFactory");
    env.put(Context.PROVIDER_URL, "winreg://localhost/HKEY_LOCAL_MACHINE");
    initctx = new InitialContext(env);
    System.out.println("Name in Namespace: " + initctx.getNameInNamespace());   // F.Y.I.

    String str;
    Object obj = initctx.lookup("SYSTEM\\CurrentControlSet\\Control\\
ComputerName\\ActiveComputerName\\ComputerName");
    if (obj instanceof String)	// known to be a string so no need to check!
    {
        str = (String)obj;
        System.out.println("ComputerName: " + str);
    }

    Context ctx = (Context)initctx.lookup("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters");
    System.out.println("HostName: " + (String)ctx.lookup("HostName"));		// cast not required
    System.out.println("Domain: " + ctx.lookup("Domain"));
    System.out.println("NameServer: " + ctx.lookup("NameServer"));

    ctx.close();
    initctx.close();
}										Name in Namespace: HKEY_LOCAL_MACHINE
catch (NamingException except)					ComputerName: BEAUTY
{										HostName: www
    except.printStackTrace(System.out);				Domain: cogentlogic.com
}										NameServer: 209.250.128.6 209.250.128.8

Rounded Rectangle: More Sample Code

// list
Hashtable env = new Hashtable(5, 0.75f);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.cogentlogic.jndi.winreg.WinregInitContextFactory");
env.put(Context.PROVIDER_URL, "winreg://localhost/HKEY_LOCAL_MACHINE\\SOFTWARE\\
Microsoft\\Windows NT\\CurrentVersion");
initctx = new InitialContext(env);
NamingEnumeration enum = initctx.list("Time Zones");
NameClassPair ncp;
while (enum.hasMore())
{
    ncp = (NameClassPair)enum.next();
    System.out.println(ncp);
}
initctx.close();


Afghanistan Standard Time: com.cogentlogic.jndi.winreg.WinregContext
Alaskan Standard Time: com.cogentlogic.jndi.winreg.WinregContext
Arabian Standard Time: com.cogentlogic.jndi.winreg.WinregContext
Atlantic Standard Time: com.cogentlogic.jndi.winreg.WinregContext
AUS Central Standard Time: com.cogentlogic.jndi.winreg.WinregContext
Azores Standard Time: com.cogentlogic.jndi.winreg.WinregContext
Bangkok Standard Time: com.cogentlogic.jndi.winreg.WinregContext
Canada Central Standard Time: com.cogentlogic.jndi.winreg.WinregContext
Caucasus Standard Time: com.cogentlogic.jndi.winreg.WinregContext
Cen. Australia Standard Time: com.cogentlogic.jndi.winreg.WinregContext
Central Asia Standard Time: com.cogentlogic.jndi.winreg.WinregContext
Central Europe Standard Time: com.cogentlogic.jndi.winreg.WinregContext
Central European Standard Time: com.cogentlogic.jndi.winreg.WinregContext
Central Pacific Standard Time: com.cogentlogic.jndi.winreg.WinregContext
Central Standard Time: com.cogentlogic.jndi.winreg.WinregContext
China Standard Time: com.cogentlogic.jndi.winreg.WinregContext
Dateline Standard Time: com.cogentlogic.jndi.winreg.WinregContext
E. Africa Standard Time: com.cogentlogic.jndi.winreg.WinregContext

Rounded Rectangle: Yet More Sample Code

// listBindings
Hashtable env = new Hashtable(5, 0.75f);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.cogentlogic.jndi.winreg.WinregInitContextFactory");
env.put(Context.PROVIDER_URL, "winreg://localhost/HKEY_LOCAL_MACHINE\\SOFTWARE\\
ODBC\\odbc.ini\\ODBC Data Sources");
initctx = new InitialContext(env);
enum = initctx.listBindings("");
Binding bd;
while (enum.hasMore())
{
    bd = (Binding)enum.next();
    System.out.println(bd.getName() + ": " + bd.getObject());
}
initctx.close();



AdvWorks: Microsoft Access Driver (*.mdb)
CertSrv: Microsoft Access Driver (*.mdb)
CogentLogicEmail: SQL Server
WBEM Source: WBEM ODBC Driver
Biblio: Microsoft Access Driver (*.mdb)
NWind: Microsoft Access Driver (*.mdb)
LocalServer: SQL Server
MQIS: SQL Server
configure: SQL Server

Rounded Rectangle: Remote Access

// Use anonymous context
System.out.println("TimeZone: " + new InitialContext().lookup("winreg://TESLA/HKEY_LOCAL_MACHINE\\
    SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\StandardName"));

// Set up to use Winreg factory
Hashtable env = new Hashtable(5, 0.75f);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.cogentlogic.jndi.winreg.WinregInitContextFactory");
env.put(Context.PROVIDER_URL, "winreg://TESLA/HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\
Windows NT\\CurrentVersion");
initctx = new InitialContext(env);
System.out.println("CSDVersion: " + initctx.lookup("CSDVersion"));
System.out.println("CurrentVersion: " + initctx.lookup("CurrentVersion"));
System.out.println("RegisteredOrganization: " + initctx.lookup("RegisteredOrganization"));
System.out.println("RegisteredOwner: " + initctx.lookup("RegisteredOwner"));
System.out.println("SystemRoot: " + initctx.lookup("SystemRoot"));
initctx.close();





TimeZone: Eastern Standard Time
CSDVersion: Service Pack 6
CurrentVersion: 4.0
RegisteredOrganization: Cogent Logic Corporation
RegisteredOwner: Jeff Lawson
SystemRoot: C:\WINNT.SBS

Rounded Rectangle: Writing System Settings

·	Applications ought to be storing data that isn’t user-specific in:

		HKEY_LOCAL_MACHINE\SOFTWARE\
<Company Name>\<App Name>\<version>\

Sample Code

env.put(Context.INITIAL_CONTEXT_FACTORY, "com.cogentlogic.jndi.winreg.WinregInitContextFactory");
env.put(Context.PROVIDER_URL, "winreg://localhost/HKEY_LOCAL_MACHINE\\SOFTWARE");
initctx = new InitialContext(env);
Context subctx = initctx.createSubcontext("Cogent Logic\\VPA\\1.0");

// Create Bindings:
subctx.bind("DeliveryPath", "\\\\BEAUTY\\VPA");                     // REG_SZ
subctx.rebind("SequenceNumber", new Integer(1234));                 // REG_DWORD
subctx.rebind("Tolerance", new Float(1234.567F));                   // REG_BINARY

// Read bindings
obj = subctx.lookup("DeliveryPath");
System.out.println("DeliveryPath: " + obj + "  (data type: " + obj.getClass() + ")");
obj = subctx.lookup("SequenceNumber");
System.out.println("SequenceNumber: " + obj + "  (data type: " + obj.getClass() + ")");
obj = subctx.lookup("Tolerance");
System.out.println("Tolerance: " + obj + "  (data type: " + obj.getClass() + ")");
subctx.close();
initctx.close();

Rounded Rectangle: Results

DeliveryPath: \\BEAUTY\VPA  (data type: class java.lang.String)
SequenceNumber: 1234  (data type: class java.lang.Integer)
Tolerance: 1234.567  (data type: class java.lang.Float)

Rounded Rectangle: Accessing User Settings

·	User settings are held in:

		HKEY_CURRENT_USER

also HKEY_USERS which holds:

.DEFAULT
other user hives

·	User settings cover:
§	Desktop and user-interface settings
§	Application preferences and other user-related details
§	Environment variables
§	Printers, mapped network drives, console settings, etc.

Rounded Rectangle:

Rounded Rectangle: Sample Code

Hashtable env = new Hashtable(5, 0.75f);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.cogentlogic.jndi.winreg.WinregInitContextFactory");
env.put(Context.PROVIDER_URL, "winreg:///HKEY_CURRENT_USER\\Volatile Environment");
initctx = new InitialContext(env);
System.out.println("User's LOGONSERVER: " + initctx.lookup("LOGONSERVER"));


User's LOGONSERVER: \\BEAUTY

Rounded Rectangle: Writing User Settings

·	Applications ought to be storing data that is user-specific in:

		HKEY_CURRENT_USER\SOFTWARE\
<Company Name>\<App Name>\<version>\


Sample Code

env.put(Context.INITIAL_CONTEXT_FACTORY, "com.cogentlogic.jndi.winreg.WinregInitContextFactory");
env.put(Context.PROVIDER_URL, "winreg://localhost/HKEY_CURRENT_USER\\SOFTWARE");
initctx = new InitialContext(env);
Context subctx = initctx.createSubcontext("Cogent Logic\\VPA\\1.0");

// Create Bindings:
subctx.rebind("EmailAddress", emailAddr);         // REG_SZ
subctx.bind("PreferredFont", font);			  // REG_BINARY

Rounded Rectangle: Roaming Profiles

·	Administrators can configure Windows NT/2000/XP global user accounts to have roaming profiles.

·	Data stored in HKEY_CURRENT_USER is then available wherever the user logs on interactively.

Rounded Rectangle: Security

·	Remote registry access for Windows 9x/Me requires enabling through direct administration—see Q141460.

·	Remote registry access for Windows NT/2000/XP is enabled by default but may require additional permissions to be set through direct administration—see Q153183.

·	When accessing Windows NT/2000/XP either locally or remotely, the JNDI Service Provider for Windows® Registries will either run in the security context of the invoking account or, if specified, will impersonate another security principal.

·	The security context is used to assign the owner of newly created resources and to check permissions when accessing existing resources.

Rounded Rectangle: Sample Code

Hashtable env = new Hashtable(5, 0.75f);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.cogentlogic.jndi.winreg.WinregInitContextFactory");
env.put(Context.PROVIDER_URL, "winreg://localhost/");       // default subtree is HKEY_LOCAL_MACHINE
initctx = new InitialContext(env);

// Use security context of the logged on user (caller)
subctx = initctx.createSubcontext("SOFTWARE\\Cogent Logic\\VPA\\1.0\\
CreatedInSecurityContextOfCaller");
subctx.close();
initctx.close();

// Impersonation
env.put(Context.SECURITY_PRINCIPAL, "Joe");        // or "<domain name>\\<user name>"
env.put(Context.SECURITY_CREDENTIALS, "joepw");
initctx = new InitialContext(env);

subctx = initctx.createSubcontext("SOFTWARE\\Cogent Logic\\VPA\\1.0\\Impersonating");
subctx.close();
initctx.close();

Rounded Rectangle:

Rounded Rectangle: Java™ Objects

·	A Java™ object may be bound in a Windows registry provided:
§	The object is serializable
§	The object’s class is in the classpath when it is looked up

Sample Code

public class MySerializableClass implements Serializable
{
    private int n;
    private String s;
    private float f;

    public MySerializableClass(int n, String s, float f)
    {
        this.n = n;
        this.s = s;
        this.f = f;
    }

    public String toString()
    {
        return "n = " + n + ";  s = " + s + ";  f = " + f;
    }
}

Rounded Rectangle: env.put(Context.INITIAL_CONTEXT_FACTORY, "com.cogentlogic.jndi.winreg.WinregInitContextFactory");
env.put(Context.PROVIDER_URL, "winreg://TESLA/HKEY_LOCAL_MACHINE\\SOFTWARE");    // remote!
initctx = new InitialContext(env);
subctx = initctx.createSubcontext("Cogent Logic\\VPA\\1.0");

// Create binding
MySerializableClass objMSC = new MySerializableClass(66, "Linda and Jeff :-)", 3.14159F);
subctx.rebind("MyObject", objMSC);

// Read binding
obj = new InitialContext().lookup("winreg://TESLA/HKEY_LOCAL_MACHINE\\
SOFTWARE\\Cogent Logic\\VPA\\1.0\\MyObject");
if (obj instanceof MySerializableClass)
System.out.println("MyObject looked up as:\n\t" + (MySerializableClass)obj);


MyObject looked up as:
        n = 66;  s = Linda and Jeff :-);  f = 3.14159

Rounded Rectangle: Federation

·	The JNDI Service Provider for Windows® Registries supports federated namespaces by supporting:
§	The role of terminal namespace
§	The role of intermediate namespace
§	Binding references: Winreg contexts implement Referenceable
§	Resolution through subinterfaces: Winreg contexts implement Resolver

Rounded Rectangle: Sample Code

// Current registry structure is:
//      HKEY_LOCAL_MACHINE\SOFTWARE\TestKey\
//                                          TestSubKey1\
//                                                      MyInteger
//                                                      MyNewestFloat
//                                                      MyObject
//                                          TestSubKey2\
// Bind Referenceable object and Reference object
System.out.println("\nUsing Federation:");
Referenceable refbleTestSubKey1 = (Referenceable)subctxTestSubKey1;    // WinregContext Referenceable
Reference refTestSubKey1 = refbleTestSubKey1.getReference();           // get a Reference
subctxTestSubKey2.bind("refbleTestSubKey1", refbleTestSubKey1);        // bind Referenceable object
subctxTestSubKey2.bind("refTestSubKey1", refTestSubKey1);              // bind Reference objects
// Either Referenceable object or Reference object may be used at any time.
// Lookup object in TestSubKey1 using federation with the Referenceable object
Object obj = subctxTestSubKey2.lookup("refbleTestSubKey1/MyInteger");
if (obj instanceof Integer)
    System.out.println("\tMyInteger from Referenceable object: " + ((Integer)obj).toString());
// Lookup object in TestSubKey1 using federation with the Reference object (and the initial context)
obj = initctx.lookup("TestKey\\TestSubKey2\\refTestSubKey1/MyNewestFloat");
if (obj instanceof Float)
    System.out.println("\tMyNewestFloat from Reference object: " + ((Float)obj).toString());
// Now, create a new subcontext via federation (using Reference object)
Context subctxTestSubSubKey =
initctx.createSubcontext("TestKey\\TestSubKey2\\refTestSubKey1/TestSubSubKey");
subctxTestSubSubKey.close();
System.out.println("\tTestSubSubKey created using federation");
// Create a value inside the new context via federation (using Referenceable object)
initctx.bind("TestKey\\TestSubKey2\\refbleTestSubKey1/TestSubSubKey\\MyNewString", "JNDI Rules!");
System.out.println("\tMyNewString created using federation");
// Lookup the new value using federation (using Reference object)
obj = initctx.lookup("TestKey\\TestSubKey2\\refTestSubKey1/TestSubSubKey\\MyNewString");
if (obj instanceof String)
    System.out.println("\tMyNewString looked up using federation as: " + (String)obj);

Rounded Rectangle: // Registry structure is now:
//      HKEY_LOCAL_MACHINE\SOFTWARE\TestKey\
//                                          TestSubKey1\
//                                                      MyInteger
//                                                      MyNewestFloat
//                                                      MyObject
//                                                      TestSubSubKey\
//                                                                    MyNewString
//                                          TestSubKey2\
//                                                      refbleTestSubKey1
//                                                      refTestSubKey1
// listBindings
System.out.println("\tlistBindings using federation:");
NamingEnumeration enum =
initctx.listBindings("TestKey\\TestSubKey2\\refbleTestSubKey1/TestSubSubKey");
Binding bd;
while (enum.hasMore())
{
    bd = (Binding)enum.next();
    System.out.println("\t\t" + bd.getName() + ": " + bd.getObject());
}
// Lookup using a composite name
Name name = new CompositeName();
name.add("TestKey\\TestSubKey2\\refbleTestSubKey1");
name.add("TestSubSubKey\\MyNewString");
obj = initctx.lookup(name);
if (obj instanceof String)
    System.out.println("\tMyNewString looked up, with a CompositeName, as: " + (String)obj);
// Lookup using a composite name with a URL
name = new CompositeName();
name.add("winreg://localhost/HKEY_LOCAL_MACHINE\\SOFTWARE\\TestKey\\TestSubKey2\\refbleTestSubKey1");
name.add("TestSubSubKey\\MyNewString");
obj = new InitialContext().lookup(name);
if (obj instanceof String)
    System.out.println("\tMyNewString from a CompositeName containing a URL: " + (String)obj);
// Destroy using federation
initctx.destroySubcontext("TestKey\\TestSubKey2\\refbleTestSubKey1/TestSubSubKey");
System.out.println("\tTestSubSubKey destroyed using federation");

Rounded Rectangle: Using Federation:
        MyInteger from Referenceable object: 5678
        MyNewestFloat from Reference object: 1234.567
        TestSubSubKey created using federation
        MyNewString created using federation
        MyNewString looked up using federation as: JNDI Rules!
        listBindings using federation:
                MyNewString: JNDI Rules!
        MyNewString looked up, with a CompositeName, as: JNDI Rules!
        MyNewString from a CompositeName containing a URL: JNDI Rules!
        TestSubSubKey destroyed using federation

Rounded Rectangle: Event Notification

·	The Windows registry supports event notification for Windows NT/2000/XP/98/Me, i.e. not for Windows 95!

·	Events are only generated locally.

·	Winreg naming contexts implement EventContext but only for:
§	EventContext.OBJECT_SCOPE
§	EventContext.SUBTREE_SCOPE

·	Simply follow the JNDI event notification guidelines:
§	Write a class that implements ObjectChangeListener
§	Instantiate your listener and add it to a context.
§	Let the listener do its stuff.
§	Remove the listener when finished.

Rounded Rectangle: Sample Code

class MyObjectChangeListener implements ObjectChangeListener
{
    public void namingExceptionThrown(NamingExceptionEvent evt)
    {
        System.out.println(evt);
    }

    public void objectChanged(NamingEvent evt)
    {
        System.out.println("\n****** Notification:  " + evt + "\n");
    }
}


//...

import java.util.*;
import javax.naming.*;
import javax.naming.event.*;

//...

// Switch on notification
EventContext ec = (EventContext)ctx;			// a context is also an EventContext!
MyObjectChangeListener ocl = new MyObjectChangeListener();
ec.addNamingListener("MyKey", EventContext.OBJECT_SCOPE, ocl);
System.out.println("\nEvent Notification successfully registered");

//...

// Switch off notification
ec.removeNamingListener(ocl);
System.out.println("\nEvent Notification successfully removed");

Rounded Rectangle: Results


Event Notification successfully registered

Updating my Registry objects:
	MyString unbound
	MyInteger rebound as 5678

****** Notification:
javax.naming.event.NamingEvent[source=com.cogentlogic.jndi.winreg.WinregContext@34a1fc]


****** Notification:
javax.naming.event.NamingEvent[source=com.cogentlogic.jndi.winreg.WinregContext@34a1fc]


****** Notification:
javax.naming.event.NamingEvent[source=com.cogentlogic.jndi.winreg.WinregContext@34a1fc]

	MyFloat renamed as MyNewestFloat

****** Notification:
javax.naming.event.NamingEvent[source=com.cogentlogic.jndi.winreg.WinregContext@34a1fc]


Event Notification successfully removed

Rounded Rectangle: Summary

·	The JNDI Service Provider for Windows® Registries supports:
§	All features possible for a naming service
§	Windows® NT/2000/XP and Windows® 9x/Me
§	The most widely used native registry data types
§	Java serializable objects
§	Local and remote access
§	NT-class security through impersonation
§	Federation
§	Event notification

Rounded Rectangle: These slides may be used freely provided:
·	They are presented as a complete set
·	They are not edited

Follow the Slide Presentation link at:

www.cogentlogic.com/jndi/



Contact:
jeff@cogentlogic.com
 

Rounded Rectangle: JNDI Service Provider for Windows® Registries


Great licensing! One license enables a single development group (i.e. any number of developers situated at the same geographical location) to use the Winreg service provider software on their computers. The software that you create MAY NOT BE A DERIVATIVE WORK. The software that you create MAY BE distributed freely with the JNDI Winreg provider software provided the JNDI Winreg provider software is not modified in any way.


Single development group license: $299 (Canadian; ~US$195)