Monday Oct 19, 2015

WLST Support for Dynamic Clustering

Credits - Developed by:

Rehana Tabassum
Byron Nevins

The Value of WebLogic Dynamic Clustering

Dynamic Clusters

Today we would like to talk about a cool new feature that we added to WebLogic.You will definitely want to know all about it if you are interested in working with Dynamic Clusters but without the hassle.


Sometimes you would like to have multiple managed servers in a cluster. All of these servers can have identical configurations – other than, say, the specific host machines, port numbers and so on.It’s time-consuming to do the dull and error-prone work of adding configuration manually for identical servers. In WebLogic 12.1.2 Dynamic Cluster capability was added to address these concerns. Dynamic Clusters allow you to specify any number of servers in a cluster with the minimum amount of individual configuration.It also added support to add servers (expand the cluster/scaleUp) and remove servers (shrink the cluster/scaleDown). This can be done in the Admin Console GUI. Servers in the Dynamic Cluster can be started and stopped just like regular servers.

Elasticity Service

A great new feature available in WebLogic 12.2.1 is the Elasticity Service.ADD LINK HERE The Elasticity Service leverages the Dynamic Cluster Technology by expanding and shrinking the Dynamic Clusters. And it does it completely automatically based on usage or many other criteria you can choose from.

WLST Support

What we are introducing is the ability to use WLST to easily expand and shrink dynamic clusters and to start and stop servers quickly.


A Use Case

You have a Corporate App for Taxes that results in a large increase in traffic between March 31 and April 30. The rest of the year it is active but only 20% as active.

Let’s say you have a Dynamic Cluster, taxCluster, that you’ve setup for 2 managed servers. Which works fine for 11 months of the year. On March 31 you want to scaleUp the cluster to 10 servers.

  • Startup WLST and connect (see References for details)
  • Run the scaleUp command to increase from 2 to 10 servers in the dynamic cluster:
  • scaleUp(‘taxCluster’, 8, true) See Examples

The result is that the cluster is permanently scaled upfrom 2 to 10 servers. The 8 new servers are all automatically started. On May 1 you restore the cluster to 2 servers

  • Startup WLST and connect (see References for details)
  • Run the scaleDown command to decrease from 10 to 2 servers in the dynamic cluster:
  • scaleDown(‘taxCluster’, 8, true) See Examples

New Functionality

New commands have been added to WLST that have made all of these actions easy to perform:

  • Start Servers in the Cluster
    • Start 1 or more or even all servers that are not running currently
    • Create new server(s) and start them
  • Stop Servers in the Cluster Gracefully
    • Shutdown a given number of servers
    • Shutdown a given number of servers and also permanently remove them -- i.e. shrink the cluster

WLST Commands

To do these actions two new commands were added to WLST.

note: arguments inside square brackets are optional. Defaults are noted

scaleUp (clusterName, numServers, [updateConfiguration=false], [block=true], [timeoutSeconds=600], [type='DynamicCluster'])

clusterName Name of the dynamic cluster
numServers Number of servers to start
updateConfiguration Boolean value specifying whether WLST should increase the maximum size of the cluster if there are not enough non-running servers already configured.
block Boolean value specifying whether WLST should block user interaction until the servers finish starting.
timeoutSeconds Time (in seconds) that WLST waits for the server(s) to start before canceling the operation
type If specified, the argument value must be DynamicCluster This is for future enhancements.

scaleDown(clusterName, numServers, [updateConfiguration=false], [block=true], [timeoutSeconds=300], [type='DynamicCluster'])

clusterName Name of the dynamic cluster
numServers Number of servers to shutdown
updateConfiguration Boolean value specifying whether WLST should both stop the give number of servers and decrease the maximum size of the cluster
block Boolean value specifying whether WLST should block user interaction until the server(s) complete shutdown
timeoutSeconds Time that WLST waits for the server(s) to shutdown before canceling the operation
type If specified, the argument value must be DynamicCluster. This is for future enhancements.


Below are example code snippets on how to perform scaling actions by invoking the scaleUp and scaleDown commands.
Since they are online commands you must first connect to the administration server (see References for instructions).

Start One Existing Server

wls:/...>scaleUp('mydyncluster', 1)
Remote ScaleUp started successfully after 25 seconds.
Waiting for 1 servers to reach the running state. The timeout is 600 seconds.
All servers are now running.


Even if all the servers under the dynamic cluster are already running, you can add one or more new server(s) to the cluster and automatically start them. Thus you can expand the size of the cluster dynamically if needed. To do so you need to specify the value of updateConfiguration as true in the scaleUp command.
Important: The cluster will be expanded only if needed. In the following example if there are 2 servers configured that are not running, they will be started and the configuration won't change. On the other hand if all servers in the cluster are already running then 2 servers will be added permanently to the cluster.

Scaleup and Start 2 New Servers

wls:/...>scaleUp('mydyncluster', 2, true)
Remote ScaleUp started successfully after 25 seconds.
Waiting for 2 servers to reach the running state. The timeout is 600 seconds.
All servers are now running.


The following example shows that the scaleUp command fails when there are not enough non-running servers allocated in the configuration and the updateConfiguration attribute is set to false. In this example the scaleUp command is asking to start 2 servers, but only 1 non-running server is available in the configuration.

Not Enough Servers Available

There are 2 server(s) in cluster: mydyncluster
States of the servers are
wls:/... > scaleUp('mydyncluster', 2)
... (stack trace removed for clarity)
WLSTException: Error occurred while performing scaleUp : There are not enough shutdown servers available in the cluster (1) to scaleUp by 2 -- rerun the command with the updateConfiguration flag set to true.


The command will succeed when updateConfiguration is set to true. The config will be expanded by the number of servers needed. In this example 1 server is added.

Expand By 1 Server

There are 2 server(s) in cluster: mydyncluster
States of the servers are
wls:/... > scaleUp('mydyncluster', 2, true)
Remote ScaleUp started successfully after 39 seconds.Waiting for 2 servers to reach the running state. The timeout is 300 seconds.
All servers are now running.
wls:/> state('mydyncluster')
There are 3 server(s) in cluster: mydyncluster
States of the servers are


To gracefully shutdown n servers, you can invoke the scaleDown command. If updateConfiguration is set to false (the default), the configuration will not be changed. In that case a scaleDown command will simply shutdown servers. In this example 2 servers are shutdown gracefully.

Shutdown 2 Servers

There are 5 server(s) in cluster: mydyncluster
States of the servers are
wls:/... > scaleDown('mydyncluster', 2)
Remote ScaleDown started successfully after 2 seconds.
The servers were stopped successfully.
wls:/... > state('mydyncluster')
There are 5 server(s) in cluster: mydyncluster
States of the servers are


If you wanted to shrink the cluster in additrion to stopping 2 servers, you can make the same call except this time set updateConfiguration to true. This will shutdown the servers and remove them from the configuration. I.e. this will shrink the cluster. Notice that 2 servers are gracefully shutdown and removed from the dynamic cluster configuration.

Shutdown 2 Servers and Shrink Cluster

There are 5 server(s) in cluster: mydyncluster
States of the servers are
wls:/... > scaleDown('mydyncluster', 2)
Remote ScaleDown started successfully after 2 seconds.
The servers were stopped successfully.
wls:/... > state('mydyncluster')
There are 5 server(s) in cluster: mydyncluster
States of the servers are



Start an interactive WLST session
Initializing WebLogic Scripting Tool (WLST) ...
Welcome to WebLogic Server Administration Scripting Shell
Type help() for help on available commands

Connnect to an administration server using WLST

wls:/offline> connect('weblogic','welcome1234','t3://localhost:7001')
Connecting to t3://localhost:7001 with userid weblogic ...
Successfully connected to Admin Server "admin" that belongs to domain "dynClusterScalingDomain".

Thursday Oct 31, 2013

Clustering in GlassFish with DCOM on Windows 7

I've discovered that Windows 7 makes it very difficult to use DCOM and, mainly, the GlassFish clustering commands that rely on DCOM.  I spent a few days trying to solve the problems.  I don't yet have a cookbook for making DCOM work on Windows 7.  But here are a few tips and advice I've found.

  1. run asadmin setup-local-dcom -- It now comes automatically with the open source GlassFish 4.  It will write some critical registry entries for you.
  2.  run asadmin validate-dcom to test dcom

3.   When I ran validate-dcom on my Windows 7 network I saw the problem below:

Successfully resolved host name to: gloin/ Successfully connected to DCOM Port at port 135 on host gloin.

Successfully connected to NetBIOS Session Service at port 139 on host gloin.

Successfully connected to Windows Shares at port 445 on host gloin.

Can not access the remote file system.  Is UAC on? : Access is denied.


I discovered the actual problem is that Windows 7 no longer has the "C$" Administrative file share available by default. If "C$" isn't available then nothing will work. Here is how to expose the "C$" share:

  • Registry Change -- this change allows “C$” to be accessed.  As soon as I set it -- the file copying started working!  [1]

    • regkey: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System

    • create this key, 32 bit word, with value == 1

  • LocalAccountTokenFilterPolicy

    4.  Turn on the Remote Registry Service -- This is critical and it's easy to do. Windows 7 has it turned off by default. MyComputer-right click, manage, services, then turn on Remote Registry Service and set it to start automatically in the fture.

    5. Turn off UAC: %systemroot%\system32\UserAccountControlSettings.exe

    6. This is where I discovered that McAfee virus scanner blocks all the NetBios shares!  It has to be disabled.


Monday Dec 10, 2012

Tip #19 Module Private Visibility in OSGi

I hate public and protected methods and classes.  It requires so much work to change them in a huge project like GlassFish.  Not to mention that you may well have to support those APIs forever.  They are highly overused in GlassFish.  In fact I'd bet that > 95% of classes are marked as public for no good reason.  It's just (bad) habit is my guess.

private and default visibility (I call it package-private) is easier to maintain.  It is much much easier to change such classes and methods around. 

If you have ANY public method or public class in GlassFish you'll need to grep through a tremendous amount of source code to find all callers.  But even that won't be theoretically reliable.  What if a caller is using reflection to access public methods?  You may never find such usages.

If you have package private methods, it's easy.  Simply grep through all the code in that one package.  As long as that package compiles ok you're all set.  There can' be any compile errors anywhere else.  It's a waste of time to even look around or build the "outside" world.

 So you may be thinking: "Aha!  I'll just make my module have one giant package with all the java files.  Then I can use the default visibility and maintenance will be much easier.  But there's a problem.  You are wasting a very nice feature of java -- organizing code into separate packages.  It also makes the code much more encapsulated.  Unfortunately to share code between the packages you have no choice but to declare public visibility.

What happens in practice is that a module ends up having tons of public classes and methods that are used exclusively inside the module.  Which finally brings me to the point of this blog:

 If Only There Was A Module-Private Visibility Available

Well, surprise!  There is such a mechanism.  If your project is running under OSGi that is.  Like GlassFish does!  With this mechanism you can easily add another level of visibility by telling OSGi exactly which public you want to be exposed outside of the module.  You get the best of both worlds:

  • Better encapsulation of your code so that maintenance is easier and productivity is increased.
  • Usage of public visibility inside the module so that you can encapsulate intra-module better with packages.

How I do this in GlassFish:

  1. Carefully plan out at least one package that will contain "true" publics.  This is the package that will be exported by OSGi.  I recommend just one package.
  2. Here is how to tell OSGi to use it in GlassFish -- edit osgi.bundle like so:
    -exportcontents:     org.glassfish.mymodule.truepublics;  version=${project.osgi.version}
  3. Now all publics declared in any other packages will be visible module-wide but not outside the module.

There is one caveat:

Accessing "module-private" items outside of the module is controlled at run-time, not compile-time.  The compiler has no clue that a public in a dependent module isn't really public.  it will happily compile it.  At runtime you will definitely see fireworks.  The good news is that you don't have to wait for the code path that tries to use the "module-private" items to fire.  OSGi will complain loudly when that module gets loaded.  OSGi will refuse to load it.  You will see an error like this:

remote failure: Error while loading FOO: Exception while adding the new configuration : Error occurred during deployment: Exception while loading the app : org.osgi.framework.BundleException: Unresolved constraint in bundle [115]: Unable to resolve 115.0: missing requirement [115.0] osgi.wiring.package; (osgi.wiring.package=org.glassfish.mymodule.unexported). Please see server.log for more details.

That is if you accidentally change code in module B to use a public that is really a "module-private" in module A, then you will see the error immediately when you try to test whatever you were changing in module B.

Tuesday Jul 17, 2012

Tip #18 Debug Mode in GlassFish

GlassFish -- both client (asadmin) and server look for an environmental variable.  If it is set to true then you get more detailed verbose information at runtime.  This is not related to the reporting level in the loggers.


The environmental variable has to exist AND it has to be set to a String that Boolean.parseString() will see as "true". 


Asadmin will dump out much more information.  E.g. if you have it set and run "asadmin start-domain" you will see how that command actually verifies that the domain has started.

Flashlight's job is to instrument classes.  It does this by creating new source code with ASM, compiling it and then replacing the existing class bytes with the new ones.  If AS_DEBUG is true -- it will save the new .class files to disk in an obvious location:


There are several Server-side commands that look at AS_DEBUG.  Which ones and what they do is left as an exercise for the reader!

Sunday May 20, 2012

Tip #17 Don't Be Lazy #2

I was debugging some GlassFish code today.  This one Admin Command needed to find out if a given node was local or remote.  It is (obviously, clearly)  impossible for the node to change this attribute during this command call.  The code calls this method:


Now if you write a final getter method this is perfectly OK because the compiler will simply inline the code so that it becomes a simple variable access.

But NO WAY is that happening in this case.  The "node" object is a proxy. The value needs to get processed through code that resolves tokens, etc.  The stack shows 8 calls to get this value.  So it is an expensive call.

 I had a breakpoint in this method.  It was called over TWENTY times by the same command!  That's 152 or so pointless method calls.

What it needed was just ONE line of code:

boolean isLocal = node.isLocal();

Saturday May 19, 2012

Tip #16 Don't Be Lazy

Hmmm.  What's wrong with the code below?

I don't know if I've ever seen code screaming out louder for re-factoring.  Obviously there should be ONE method with the 4 lines that are repeated over and over and over and over.  What happens when one of the lines changes?  Well, then FOUR lines will have to change.  Of course if these copy&pasted lines are spread around in a huge file you'll probably miss a few. 

The only reason this can possibly happen is because copy&paste exists.  If we had to type in those identical blocks again and again -- THEN we would re-factor into a method call!

       if (!env.isDas()) {
            String msg = Strings.get("notAllowed");

        // Make sure Node is valid
        theNode = nodes.getNode(node);
        if (theNode == null) {
            String msg = Strings.get("noSuchNode", node);

        if (lbEnabled != null && clusterName == null) {
            String msg = Strings.get("lbenabledNotForStandaloneInstance");

        if (demo != null) {
            String msg = Strings.get("demoOnly");

Thursday Apr 12, 2012

Tip #15: How To Debug Unit Tests During Maven Builds

It must be really really hard to step through unit tests in a debugger during a maven build.  Right?


Here is how i do it:

1) Set up these environmental variables:

MAVEN_OPTS=-Xmx1024m -Xms256m -XX:MaxPermSize=512m
MAVEN_OPTS_DEBUG=-Xmx1024m -Xms256m -XX:MaxPermSize=512m  -Xdebug (no line break here!!)  -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9999
MAVEN_OPTS_REG=-Xmx1024m -Xms256m -XX:MaxPermSize=512m

2) create 2 scripts or aliases like so:






 To debug do this:

  1. run maveny.bat
  2. run mvn install
  3. attach your debugger to port 9999 (set breakpoints of course)
  4. When maven gets to the unit test phase it will hit your breakpoint and wait for you.

When done debugging simply run mavenn.bat


  1. If it takes a while to do the build then you don't really need to set the suspend=y flag.
  2. If you set the suspend=n flag then you can just leave it -- but only one maven build can run at a time because of the debug port conflict.

Thursday Mar 15, 2012

GlassFish Clustering with DCOM on Windows

DCOM - Distributed COM, a Microsoft protocol for communicating with Windows machines.

Why use DCOM?

  • In GlassFish 3.1 SSH is used as the standard way to run commands on remote nodes for clustering.  It is very difficult for users to get SSH configured properly on Windows.  SSH does not come with Windows so we have to depend on third party tools.  And then the user is forced to install and configure these tools -- which can be tricky.
  • DCOM is available on all supported platforms.  It is built-in to Windows.
The idea is to use DCOM to communicate with remote Windows nodes.  This has the huge advantage that the user has to do minimal, if any, configuration
on the Windows nodes.

Implementation Highlights

Two open Source Libraries have been added to GlassFish:
  • Jcifs – a SAMBA implementation in Java
  • J-interop – A Java implementation for making DCOM calls to remote Windows computers.  

Note that any supported platform can use DCOM to work with Windows nodes -- not just Windows.
E.g. you can have a Linux DAS work with Windows remote instances.

All existing SSH commands now have a corresponding DCOM command – except for setup-ssh which isn’t needed for DCOM.  
validate-dcom is an all new command.

New DCOM Commands

  • create-node-dcom
  • delete-node-dcom
  • install-node-dcom
  • list-nodes-dcom
  • ping-node-dcom
  • uninstall-node-dcom
  • update-node-dcom
  • validate-dcom
  • setup-local-dcom (This is only available via Update Center for GlassFish 3.1.2)

These commands are in-place in the trunk (4.0).  And in the branch (3.1.2)

Windows Configuration Challenges

There are an infinite number of possible configurations of Windows if you look at it as a combination of main release, service-pack, special drivers, software, configuration etc.  Later versions of Windows err on the side of tightening security be default.  This means that the Windows host may need to have configuration changes made.
These configuration changes mostly need to be made by the user.  setup-local-dcom will assist you in making required changes to the Windows Registry.  See the reference blogs for details.

The validate-dcom Command

validate-dcom is a crucial command.  It should be run before any other commands.  If it does not run successfully then there is no point in running other commands.
The validate-dcom command must be used from a DAS machine to test a different Windows machine.  
If  validate-dcom runs successfully you can be confident that all the DCOM commands will work.  Conversely, the opposite is also true:  If validate-dcom fails, then no DCOM commands will work.

What validate-dcom does

  1. Verify that the remote host is not the local machine.
  2. Resolves the remote host name
  3. Checks that the remote DCOM port is being listened on (135, 139)
  4. Checks that the remote host’s File Sharing is enabled (port 445)
  5. It copies a file (a script) to the remote host to verify that SAMBA is working and authorization is correct
  6. It runs a script that it copied on-the-fly to the remote host.

Tips and Tricks

The bread and butter commands that use DCOM are existing commands like create-instance, start-instance etc.   All of the commands that have dcom in their name are for dealing with the actual nodes.

The way the software works is to call asadmin.bat on the remote machine and run a command.  This means that you can track these commands easily on the remote machine with the usual tools.  E.g. using AS_LOGFILE, looking at log files, etc.  It’s easy to attach a debugger to the remote asadmin process, “just in time”, if necessary.

How to debug the remote commands:
Edit the asadmin.bat file that is in the glassfish/bin folder.  Use glassfish/lib/nadmin.bat in GlassFish 4.0+
Add these options to the java call:
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=1234
  Now if you run, say start-instance on DAS, you can attach your debugger, at your leisure, to the remote machines port 1234.  It will be running start-local-instance and patiently waiting for you to attach.

Thursday Mar 01, 2012

GlassFish DCOM Configuration Utility

Version 3.1.2 of GlassFish adds support for communicating with Windows remote hosts over DCOM.  DCOM is a communications protocol from Microsoft.  All Windows versions that GlassFish supports come with DCOM support built-in.  

In these days of high-security on Windows,  using DCOM may well require a few configuration steps.  One of the more challenging steps is to edit the Windows Registry.

We are using DCOM to run GlassFish processes on the remote Windows machines (we call them nodes).  What we do is the same thing command-line users do -- run asadmin on the remote machine.  Asadmin.bat is a script and in order to remotely run scripts you must have permissions set in the Windows Registry.  In fact you need two Registry entries set to give permission to the Administrators group.  These two are:

  1. WMI - Windows Management Interface
  2. WBEM Scripting

The problem with these 2 registry keys is that in many versions of Windows they are owned by an account named TrustedInstaller.  And by default the Administrators group have no permissions at all.  (Yes , I said the owner of the key -- Registry keys have owners with access control lists exactly analogous to files).  In my humble opinion this is a Windows Bug! 

Setting-up the registry keys correctly is fairly involved.  There are significant complications for 32 bit versus 64 bit Windows.  Windows does automatic redirection of Registry Keys.  You're probably thinking -- "This is just too painful to bear!".  And you are right.  That's why I wrote a C++ Windows program that does all of the registry changes for you.  But that's not all!  I embedded this C++ program inside a jar file that also contains an asadmin extension command.  In order to do the editing of the registry keys you simply need to deploy the extension command and run it one time on each Windows machine.  And then only if you need to run it.

The name of the command is setup-local-dcom.  You can get it from Update Center under contributions.  See my other blog for instructions on exactly how to get it from Update Center.

Instructions for running setup-local-dcom

  • Backup the Registry just in case.
  • Run the command on the Windows machine that will be used as a remote node for GlassFish
  • You need to be logged in to an account that is a member of the Administrators group.
  • run the following to see the manual page:
    asadmin setup-local-dcom --help

  • Run the command to edit the registry keys, if needed.  Use the --verbose option to get a report of what it did.
  • Note that the command makes you type in yes and hit return to give you one last chance to change your mind.  If you find that annoying use the --force option and it will silently run.
  • If the command was successful then go to any other computer that can access it and run the validate-local-dcom command against the machine you just ran setup-local-dcom on.  If validate-local-dcom runs successfully then all clustering commands should work fine in your distributed environment.  If validate-local-dcom fails then see another blog that describes further configuration steps you may need to make on the Windows node.

Example Output of setup-local-dcom --verbose

d:\>asadmin setup-local-dcom -v
Caution: This command might modify the permissions of some keys in the Windows registry.
Before running this command, back up the Windows registry.
The modification allows the Windows user full control over these keys.

Are you sure that you want to edit the Windows registry? If so, type yes in full:  yes
>>>>>>>>>>>>>                          <<<<<<<<<<<<<
>>>>>>>>>>>>>   Set to Verbose Mode    <<<<<<<<<<<<<
>>>>>>>>>>>>>                          <<<<<<<<<<<<<
Administrators group SID: [S-1-5-32-544]
Key: [CLSID\{72C24DD5-D70A-438B-8A42-98424B88AFB8}]  Owner: [S-1-5-32-544]
Key: [CLSID\{76A64158-CB41-11D1-8B02-00600806D9B6}]  Owner: [S-1-5-32-544]
Redirected Key: [Wow6432Node\CLSID\{72C24DD5-D70A-438B-8A42-98424B88AFB8}]
Redirected Key: [Wow6432Node\CLSID\{76A64158-CB41-11D1-8B02-00600806D9B6}]
No need to adjust the Scripting Registry Key.
No need to adjust the WMI Registry Key.
>>>>>>>>>>>>>                          <<<<<<<<<<<<<
>>>>>>>>>>>>>   Set to Verbose Mode    <<<<<<<<<<<<<
>>>>>>>>>>>>>                          <<<<<<<<<<<<<
Administrators group SID: [S-1-5-32-544]
Key: [CLSID\{72C24DD5-D70A-438B-8A42-98424B88AFB8}]  Owner: [S-1-5-32-544]
Key: [CLSID\{76A64158-CB41-11D1-8B02-00600806D9B6}]  Owner: [S-1-5-32-544]
Redirected Key: [Wow6432Node\CLSID\{72C24DD5-D70A-438B-8A42-98424B88AFB8}]
Redirected Key: [Wow6432Node\CLSID\{76A64158-CB41-11D1-8B02-00600806D9B6}]
No need to adjust the Scripting Registry Key.
No need to adjust the WMI Registry Key.

Command setup-local-dcom executed successfully.

How to Setup Update Center in GlassFish 3.1.2 in Windows

1. start glassfish3\bin\updatetool.bat

Get a cup of coffee -- step 1 will take a while the first time it is called as it bootstraps itself.!

2. Run the newly created updatetool.exe application

The GUI appears after a lengthy wait.  Click on Available Add-ons on the left side of the window and go get another cup of  coffee.  It's going to take a long time.

3. How to get the  DCOM Configuration Command

If you came here from my other blog about setting up DCOM for GlassFish you will need to get the binaries from Update Center.

  1. Click on available updates
  2. Choose the one named setup-local-dcom asadmin subcommand
  3. Accept the license
  4. Update Center will download and install it for you.
  5. It is ready to use now!

Friday Jan 06, 2012

Tip #14 Symbolic Links on Windows?!?

Windows does have real UNIX-like symbolic links.  They are called junctions.  There are no built-in Windows tools for using them though. 

SysInternals has a great tool for using them.  Note that Microsoft owns SysInternals now.

Try it:

Thursday Nov 10, 2011

Tip #13 Surprises

There is an assumption that I've seen in code many times that is totally wrong.  And this assumption can easily bite you.  The assumption is:

File.getAbsolutePath and getAbsoluteFile return paths that are not relative.

 Not true!  Sort of.  At least not in the way many people would assume.  All they do is make sure that the beginning of the path is absolute.  The rest of the path can be loaded with relative path elements.  What do you think the following code will print?

public class Main {
    public static void main(String[] args) {
        try {
            File f = new File("/temp/../temp/../temp/../");
            File abs  = f.getAbsoluteFile();
            File parent = abs.getParentFile();
            System.out.println("Exists: " + f.exists());
            System.out.println("Absolute Path: " + abs);
            System.out.println("FileName: " + abs.getName());
            System.out.printf("The Parent Directory of %s is %s\n", abs, parent);
            System.out.printf("The CANONICAL Parent Directory of CANONICAL %s is %s\n",
                        abs, abs.getCanonicalFile().getParent());
            System.out.printf("The CANONICAL Parent Directory of ABSOLUTE %s is %s\n",
                        abs, parent.getCanonicalFile());
            System.out.println("Canonical Path: " + f.getCanonicalPath());
        catch (IOException ex) {
            System.out.println("Got an exception: " + ex);


Exists: true
Absolute Path: D:\temp\..\temp\..\temp\..
FileName: ..
The Parent Directory of D:\temp\..\temp\..\temp\.. is D:\temp\..\temp\..\temp
The CANONICAL Parent Directory of CANONICAL D:\temp\..\temp\..\temp\.. is null
The CANONICAL Parent Directory of ABSOLUTE D:\temp\..\temp\..\temp\.. is D:\temp
Canonical Path: D:\

Notice how it says that the parent of d:\ is d:\temp !!!The file, f, is really the root directory.  The parent is supposed to be null.

I learned about this the hard way! getParentXXX simply hacks off the final item in the path. You can get totally unexpected results like the above. Easily.

I filed a bug on this behavior a few years ago[1].  


(1) Use getCanonical instead of getAbsolute.  There is a 1:1 mapping of files and canonical filenames.  I.e each file has one and only one canonical filename and it will definitely not have relative path elements in it.  There are an infinite number of absolute paths for each file.

(2) To get the parent file for File f do the following instead of getParentFile:

File parent = new File(f, "..");


Wednesday Oct 12, 2011

Tip#12 Waste of time setting instance variables to their default.

I see this code frequently:

class foo {

private String s1 = null;
private boolean b1 = false;
int i1 = 0;

This is a waste of time.  Those variables are NOT on the stack.  They are always guaranteed to be equal to the default that is defined for that data type.  By setting them to a value, special code has to be written and run automatically when the instance is instantiated.  E.g. the String is initially set to null automatically.  Then code is run which once again sets it to null.


class foo {
private String s1;
private boolean b1;
int i1;


On the other hand you have to set initial values for local variables.  There storage space is allocated on the fly and they are on the stack.  Therefore they are initialized to whatever garbage happens to be on the stack.

Tuesday Oct 04, 2011

Tip #11 Subversion Low-Tech Safety Net

Have you ever lost a significant  amount of source code?  If you have you probably already have multiple layers of safety nets.  This stuff is just too hard to do to take a chance on hardware failures, hickups, etc.  

E.g. I remember once I thought I was in my temp directory.  I entered this command:

rm -rf *

Oops.  I was in the root directory!  I.e. stuff indeed happens. 

Today's excruciatingly simple tip:

When you are actively developing code but it is not yet ready to be checked-in.  Yet you have spent a significant chunk of time on it.  I do this:

svn status | sort | tee dome.bat

I edit the dome.bat file and change this:

?       d
?       diffs.txt
?       dome.bat
?       q
A       src\main\java\com\sun\enterprise\universal\process\
A       src\main\java\com\sun\enterprise\universal\process\
A       src\main\java\com\sun\enterprise\universal\process\
A       src\main\java\com\sun\enterprise\universal\process\
A       src\main\java\com\sun\enterprise\universal\process\
A       src\main\java\com\sun\enterprise\util\io\
A       src\main\java\com\sun\enterprise\util\io\
A       src\main\java\com\sun\enterprise\util\io\
M       pom.xml
M       src\main\java\com\sun\enterprise\universal\glassfish\

to this:

       jar cvfM src\main\java\com\sun\enterprise\universal\process\ src\main\java\com\sun\enterprise\universal\process\ src\main\java\com\sun\enterprise\universal\process\ src\main\java\com\sun\enterprise\universal\process\ src\main\java\com\sun\enterprise\universal\process\ src\main\java\com\sun\enterprise\util\io\ src\main\java\com\sun\enterprise\util\io\ src\main\java\com\sun\enterprise\util\io\ pom.xml src\main\java\com\sun\enterprise\universal\glassfish\

Now  I simply run the script and email the jar file to my work email account.  My company will be happy to guarantee safety for my jar file. 

Friday Sep 30, 2011

Tip#10 Technique for making your class Immutable

Immutable classes are great.  You never have to worry about concurrency problems.  It also makes the code more readable - if a variable is final you don't have to look around for the other places where it gets modified -- there aren't any. Also the compiler will help you.  If you forget to assign a final variable it's a compile error.  It's also an error to try and reassign it.

Here is a simple trivial technique for setting final variables from a constructor where you need to do processing first.  The point is that you use temp variables to get your final values all lined up.  Then you assign the final values once.

I'll just let the code write the rest of this blog:

public final class DcomInfo {
    private final WindowsCredentials credentials;
    private final Node node;
    private final String password;
    private final String host;
    private final String user;
    private final String windowsDomain;
    private final String remoteNodeRootDirectory;

    public DcomInfo(Node theNode) throws WindowsException {
        node = theNode;

        if (node == null)
            throw new WindowsException(
                    Strings.get("internal.error", "Node is null"));

        if (!isDcomNode(node))
            throw new WindowsException(Strings.get("not.dcom.node",
                    getNode().getName(), getNode().getType()));

        SshConnector conn = node.getSshConnector();
        if (conn == null)
            throw new WindowsException(Strings.get("no.password"));

        SshAuth auth = conn.getSshAuth();
        if (auth == null)
            throw new WindowsException(Strings.get("no.password"));

        String notFinal = auth.getPassword();
        if (!ok(notFinal))
            throw new WindowsException(Strings.get("no.password"));

        password = DcomUtils.resolvePassword(notFinal);

        notFinal = node.getNodeHost();
        if (!ok(notFinal))
            notFinal = conn.getSshHost();
        if (!ok(notFinal))
            throw new WindowsException(Strings.get(""));
        host = resolver.resolve(notFinal);

        notFinal = auth.getUserName();
        if (!ok(notFinal))
            notFinal = System.getProperty("");
        if (!ok(notFinal))
            throw new WindowsException(Strings.get("no.username"));
        user = resolver.resolve(notFinal);

        notFinal = node.getWindowsDomain();
        if (!ok(notFinal))
            notFinal = host;
        windowsDomain = resolver.resolve(notFinal);

        notFinal = node.getInstallDirUnixStyle();
        if (!ok(notFinal))
            throw new WindowsException(Strings.get("no.lib.dir"));

        if (!notFinal.endsWith("/"))
            notFinal += "/";

        notFinal += SystemPropertyConstants.getComponentName();
        remoteInstallRoot = StringUtils.quotePathIfNecessary(notFinal);
        notFinal += "/lib";
        notFinal = StringUtils.quotePathIfNecessary(notFinal);
        notFinal = notFinal.replace('/', '\\');
        nadminParentPath = notFinal;
        nadminPath = notFinal + "\\nadmin.bat";

        String notFinal2 = node.getNodeDirAbsolute();

        if (notFinal2 == null) {
            // no special nodedir -- use the defaults
            notFinal2 = remoteInstallRoot;  // e.g. "d:/glassfish3/glassfish"
            notFinal2 += "/nodes";
        notFinal2 = notFinal2.replace('/', '\\');

        if (!notFinal2.endsWith("\\"))
            notFinal2 += '\\';

        remoteNodeRootDirectory = notFinal2 + node.getName();

        credentials = new WindowsCredentials(getHost(), getWindowsDomain(),
                getUser(), getPassword());




« July 2016