X

Recent Posts

Sun

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.run asadmin setup-local-dcom -- It now comes automatically with the open source GlassFish 4.  It will write some critical registry entries for you. run asadmin validate-dcom to test dcom3.   When I ran validate-dcom on my Windows 7 network I saw the problem below:Successfully resolved host name to: gloin/10.28.51.10 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\Systemcreate this key, 32 bit word, with value == 1LocalAccountTokenFilterPolicy 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.exe6. This is where I discovered that McAfee virus scanner blocks all the NetBios shares!  It has to be disabled.

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...

Sun

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: 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. 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} 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 com.oracle.glassfish.miscreant.code [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.

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...

Sun

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");            logger.warning(msg);            report.setActionExitCode(ActionReport.ExitCode.FAILURE);            report.setMessage(msg);            return;        }        // Make sure Node is valid        theNode = nodes.getNode(node);        if (theNode == null) {            String msg = Strings.get("noSuchNode", node);            logger.warning(msg);            report.setActionExitCode(ActionReport.ExitCode.FAILURE);            report.setMessage(msg);            return;        }        if (lbEnabled != null && clusterName == null) {            String msg = Strings.get("lbenabledNotForStandaloneInstance");            logger.warning(msg);            report.setActionExitCode(ActionReport.ExitCode.FAILURE);            report.setMessage(msg);            return;        }                if (demo != null) {            String msg = Strings.get("demoOnly");            logger.warning(msg);            report.setActionExitCode(ActionReport.ExitCode.FAILURE);            report.setMessage(msg);            return;        }

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...

Sun

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 HighlightsTwo 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 Verify that the remote host is not the local machine. Resolves the remote host name Checks that the remote DCOM port is being listened on (135, 139) Checks that the remote host’s File Sharing is enabled (port 445) It copies a file (a script) to the remote host to verify that SAMBA is working and authorization is correct 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.

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...

Sun

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: WMI - Windows Management Interface 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 -vCaution: 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.

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...

Sun

Tip #13 java.io.File 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);        }    }} Output: Exists: trueAbsolute Path: D:\temp\..\temp\..\temp\..FileName: ..The Parent Directory of D:\temp\..\temp\..\temp\.. is D:\temp\..\temp\..\tempThe CANONICAL Parent Directory of CANONICAL D:\temp\..\temp\..\temp\.. is nullThe CANONICAL Parent Directory of ABSOLUTE D:\temp\..\temp\..\temp\.. is D:\tempCanonical 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].   Recommendations: (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, ".."); [1] http://bt2ws.central.sun.com/CrPrint?id=6687287

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...

Sun

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: ?       comm-util-3.1.2.save.jar?       d?       diffs.txt?       dome.bat?       qA       src\main\java\com\sun\enterprise\universal\process\WindowsCredentials.javaA       src\main\java\com\sun\enterprise\universal\process\WindowsException.javaA       src\main\java\com\sun\enterprise\universal\process\WindowsRemoteAsadmin.javaA       src\main\java\com\sun\enterprise\universal\process\WindowsRemotePinger.javaA       src\main\java\com\sun\enterprise\universal\process\WindowsRemoteScripter.javaA       src\main\java\com\sun\enterprise\util\io\WindowsRemoteFile.javaA       src\main\java\com\sun\enterprise\util\io\WindowsRemoteFileCopyProgress.javaA       src\main\java\com\sun\enterprise\util\io\WindowsRemoteFileSystem.javaM       pom.xmlM       src\main\java\com\sun\enterprise\universal\glassfish\TokenResolver.java to this:        jar cvfM comm-util-3.1.2.save.jar src\main\java\com\sun\enterprise\universal\process\WindowsCredentials.java src\main\java\com\sun\enterprise\universal\process\WindowsException.java src\main\java\com\sun\enterprise\universal\process\WindowsRemoteAsadmin.java src\main\java\com\sun\enterprise\universal\process\WindowsRemotePinger.java src\main\java\com\sun\enterprise\universal\process\WindowsRemoteScripter.java src\main\java\com\sun\enterprise\util\io\WindowsRemoteFile.java src\main\java\com\sun\enterprise\util\io\WindowsRemoteFileCopyProgress.java src\main\java\com\sun\enterprise\util\io\WindowsRemoteFileSystem.java pom.xml src\main\java\com\sun\enterprise\universal\glassfish\TokenResolver.java 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. 

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...

Sun

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("no.host"));        host = resolver.resolve(notFinal);        notFinal = auth.getUserName();        if (!ok(notFinal))            notFinal = System.getProperty("user.name");        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());    }

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...

Sun

Tip #4: Stop and Think before you make that Class public

I run into this time-wasting situation fairly frequently: I need to change the signature of a Java class, in GlassFish,  that has been declared public.  Uh-oh!  It's public so I can't just change it.  So -- my first step is to grep through every single java file in GlassFish.  That means  7,772 files currently! Now I have to wonder -- is the class being used from modules outside of GlassFish?  Uh-oh -- now I have to run massive automated tests to make sure I don't break something. Ultimately you can never be totally sure that public class is not being used somewhere.  E.g. say the name of the class is FooGooHoo.  What if there is code doing a Class.forName("Foo" + "Goo" + "Hoo") ?  I'll never find it with a simple search.  This is all expected stuff with the public keyword.  But what if the class is exclusively used inside of its own package?  Then I just  wasted a whole lot of my employer's money chasing down non-existent references.  On the other hand if the class had its visibility set to pkg-private in the first place, all I had to do was to search inside that one package for uses.  Java guarantees no other package can see it.  And if other code somehow subverts that policy -- tough!! Moral of the Story: Only mark classes and methods as public when you are absolutely positively sure that it must be public.  When in doubt make it pkg-private and avoid protected too.

I run into this time-wasting situation fairly frequently: I need to change the signature of a Java class, in GlassFish,  that has been declared public.  Uh-oh!  It's public so I can't just change it.  So...

Sun

Tip #3: Make Life Easier for Your Code Reviewer

There are probably a hundred applications that will package up code changes in various cool ways.  You could also write your own -- unfortunately it's one of those cases where the time you save using the tool will never approach the time you spent making the tool.  I get code review requests fairly often and they are almost always like this:  Below are the diffs for my change.  Please review  And as promised the output of some diff tool is below in the email.  What if the context around the diffs isn't big enough?  What if I hate the diff tool formatting?  What if I want to compile and run the actual changes in my environment? I can't do any of the above quickly and easily with the raw diffs embedded in the email.  Even copying and pasting them is usually a big pain because of the prepended plus signs.  Here are my requirements for code review submitters (Please?!?) Send out the actual changed source files Make it very very easy to get those source file into the right directory.  Don't make me type in commands with endlessly long paths! Send me the diffs as a file and have it appear directly in the email (maybe the change is easy and I don't need to waste time dealing with file attachments) And here is the solution I use.  It is simple and old-fashioned and works great:  Create the following script (Windows version).  I use this script constantly when I'm working on source code.  That's why I named it "s.bat".  Usually I don't use the "dome.bat" file but I always create it just in case.  I sort the output to get all the modified files together.svn status | sort | tee dome.bat To submit the changes to a code reviewer, I want him or her to get the diffs file, and all changed files.  I collect the diffs in a file like so (make a script out of it!)svn diff > diffs.txt Here is the trick.  Edit the dome.bat file from step 1 above.  Delete the uninteresting lines and QUICKLY edit the Modified or Added lines to do this:jar cvfM mychanges.jar diffs.txt c:/some/gigantic/ugly/long/path/foo.java c:/some/even/uglier/gigantic/long/path/foo2.java Now I attach mychanges.jar to an email and also copy the diffs to the email message.  I tell the reviewer which directory to change to and how to unpack the source files.  E.g."cd to core/kernel and run jar xvf mychanges.jar to overlay my changes in your installation" It sounds like a big deal but it shouldn't take more than a couple minutes and it makes life more pleasant for the reviewer.  Note how the reviewer can do this: jar cvfM temp.zip srcjar xvf mychanges.jarrun his or her favorite diff toolscompile and build, look at the code in a debugger or whateverwhen review is complete, jar xvf temp.zip

There are probably a hundred applications that will package up code changes in various cool ways.  You could also write your own -- unfortunately it's one of those cases where the time you save using...

Sun

Tip #2 Step Through Every Line of Code in a Debugger

This is so simple.  The place where I catch most of my bugs -- before the code is even checked-in.   Drum-roll: Step Through Every Line of Code You Write in a Debugger  I'm frequently amazed at what I bump into during this pass-through.  I've found all sorts of embarrassing problems.  You never see them, though, because I caught them before checking in. Nobody writes bug-free code.  But you can check-in bug-free (or nearly so) code. Some people may counter with: "Oh ho!  I have no time to step through the code in a debugger!"  My answer is that the time it takes to  step through the code in a debugger is normally a tiny percentage of the time it takes to do all of these things: Think up what to write Write it Fix compile errors etc. Fix more obvious errors from simple tests write unit tests write dev tests close an issue in Issue Tracker check-in comments Ask for a code review, get comments, respond. make changes And I mean every line of code.  Modern java debuggers allow you to change values of variables, etc., to force your execution path into error handling code. If you start do this zealously it may force you into picking up other good development habits too, that make it easier to step-through all of your code.

This is so simple.  The place where I catch most of my bugs -- before the code is even checked-in.   Drum-roll: Step Through Every Line of Code You Write in a Debugger  I'm frequently amazed at what I...

Sun

Dtrace of Clusters in GlassFish - A Quick Tutorial

This is the second blog in the series about DTrace and GlassFish 3.1.1  You should read the first blog before this one. Continuing where I left off in the previous blog I would like to analyze the usage of MonApp in 2  different instances.  Specifically I did this: undeploy from DASasadmin undeploy MonApp create a clusterasadmin create-cluster c1 create two clustered instancesasadmin create-local-instance --cluster c1 i1asadmin create-local-instance --cluster c1 i2 deploy to the clusterasadmin deploy MonApp.war start the instancesasadmin start-cluster c1 OPTIONAL - turn the levels up to HIGH for all Monitoring Modules as in the previous blog.  Just add the args --target c1 turn-on DTrace supportasadmin enable-monitoring --target c1 --dtrace Load both off the URLs in a browser in 2 different tabs:http://localhost:28080/MonApphttp://localhost:28081/MonApp Verify DTrace "sees" the MonApp Probes dtrace -l | grep foo39785 fooblog20527           samples                      ProbeServlet myProbe39841 fooblog20544           samples                      ProbeServlet myProbe Run list-instances to get the instance pids so you can tell the probes apartasadmin list-instances --longNAME  HOST       PORT   PID    CLUSTER  STATEi1    localhost  24848  20527  c1        runningi2    localhost  24849  20544  c1        running If you had a load balancer setup (I don't) you could start hammering the App and see which instances are servicing the calls.  What I do is start the dtrace script:dtrace -n 'fooblog*::: { printf("PID:%d APP:%s %s", pid, execname, copyinstr(arg0)); }' Now I sit in the browser and randomly reload the 2 pages for a while and look at DTrace output:dtrace: description 'fooblog*::: ' matched 2 probesCPU     ID                    FUNCTION:NAME  0  39785             ProbeServlet:myProbe PID:20527 APP:java Hello #3  0  39785             ProbeServlet:myProbe PID:20527 APP:java Hello #4  0  39785             ProbeServlet:myProbe PID:20527 APP:java Hello #5  0  39841             ProbeServlet:myProbe PID:20544 APP:java Hello #3  0  39841             ProbeServlet:myProbe PID:20544 APP:java Hello #4  0  39841             ProbeServlet:myProbe PID:20544 APP:java Hello #5  0  39785             ProbeServlet:myProbe PID:20527 APP:java Hello #6  0  39841             ProbeServlet:myProbe PID:20544 APP:java Hello #6  0  39785             ProbeServlet:myProbe PID:20527 APP:java Hello #7  0  39785             ProbeServlet:myProbe PID:20527 APP:java Hello #8  0  39841             ProbeServlet:myProbe PID:20544 APP:java Hello #7  0  39841             ProbeServlet:myProbe PID:20544 APP:java Hello #8  0  39841             ProbeServlet:myProbe PID:20544 APP:java Hello #9  0  39841             ProbeServlet:myProbe PID:20544 APP:java Hello #10  0  39785             ProbeServlet:myProbe PID:20527 APP:java Hello #9

This is the second blog in the series about DTrace and GlassFish 3.1.1  You should read the first blog before this one. Continuing where I left off in the previous blog I would like to analyze the...

Sun

Introducing DTrace in GlassFish 3.1.1

This is the first in a series of blogs about Dtrace in GlassFish.  I will present concrete examples  in upcoming blogs.  This blog is an overview of this powerful new capability. An entire book could be (and has been) written just to describe DTrace itself.   There are many many useful documents on the internet about DTrace and its usage.  At the end of this blog I've referenced a few good ones that I've read. DTrace is a tool available currently on Solaris 10 and Mac OS X that will dynamically instrument already-running code  for the purposes of seeing what is going on inside software.  This includes the OS itself.  You can probe into kernel-mode in addition to user-mode.  GlassFish automatically supports DTrace.  For every Probe that is registered in GlassFish, a corresponding DTrace probe is generated and made available to DTrace.  This includes any probes that you create yourself such as in your Applications.  See  [1] for a tutorial on this. In order for the DTrace probes to be available you need to do 3 things from the GlassFish end: GlassFish must be running in JDK 7 Dtrace must be enabled.  Simply run this command: asadmin enable-monitoring --dtrace You must have glassfish-dtrace.jar copied to the GlassFish modules directory.  Update center will set things up for you by doing the following You must use an official distribution: Open Source Distribution Oracle GlassFish Server Distribution Official Oracle GlassFish Server page is located here Run: <installdir>/bin/updatetool to bootstrap update clients. Run:  <installdir>/bin/pkg install glassfish-monitoring-dtrace@3.1.1 to install the DTrace package Of course you also have to turn on the monitoring levels for what you are interested in.  To turn Monitoring up full-blast for everything run these commands (you can make one huge command out of it and stuff it into a script like I do): asadmin enable-monitoring --target server --modules deployment=HIGHasadmin enable-monitoring --target server --modules connector-connection-pool=HIGHasadmin enable-monitoring --target server --modules connector-service=HIGHasadmin enable-monitoring --target server --modules ejb-container=HIGHasadmin enable-monitoring --target server --modules http-service=HIGHasadmin enable-monitoring --target server --modules jdbc-connection-pool=HIGHasadmin enable-monitoring --target server --modules jms-service=HIGHasadmin enable-monitoring --target server --modules jvm=HIGHasadmin enable-monitoring --target server --modules orb=HIGHasadmin enable-monitoring --target server --modules thread-pool=HIGHasadmin enable-monitoring --target server --modules transaction-service=HIGHasadmin enable-monitoring --target server --modules web-container=HIGHasadmin enable-monitoring --target server --modules jersey=HIGHasadmin enable-monitoring --target server --modules jpa=HIGHasadmin enable-monitoring --target server --modules security=HIGHasadmin enable-monitoring --target server --modules web-services-container=HIGH Obviously you have to be on an OS that has dtrace! You can quickly and easily see that everything is registered correctly and available for running in DTrace scripts with this command: dtrace -l | grep glassfish This will show 151 or so built-in GlassFish probes.  Here is one line of the output: 39462 glassfish20383               web                        web-module webModuleStartedEvent20383 is the Process ID of the GlassFish Server.  Whenever a web module is started the DTrace probe will be called with some arguments like the name of the web-module, etc. The beauty of DTrace is that the DTrace probe inside of GlassFish is a no-op unless a DTrace script happens to be running.  In that case and in only that case the DTrace probe code gets dynamically instrumented to call into the OS's DTrace framework.  When the script ends, the probe gets un-instrumented.  There is almost no overhead unless a DTrace script is running. There are limitless applications for this technology.  You can create on-the-fly scripts that attach to an already-running GlassFish server.  Everything can be enabled dynamically - the server never needs to be restarted for the magic to happen.  DTrace is so powerful it has its own programming language named "d".  It is beyond the scope of this blog to do more than chip at the surface of the DTrace engine.   An example might be choosing a pair of bookend probes.  E.g. a start-transaction/end-transaction pair.  Or a HTTP service startRequest/endRequest pair.  You can easily have a DTrace script measure the time between the 2 calls and print out this information.  Since it is a programming language you can even save them into variables and crunch the data at the end of the script.  Another example might be that you want to see every file that is opened - but only between a bookend pair (i.e. you are filtering the deluge of file openings to those that happen to occur during the time-slice of your bookend). Create or download the app from [1].  Now add something more interesting to the webapp like, for instance, a form.  Now call a probe everytime the form is processed.  Pass a String the user enters in the form to the Probe.  That String will be available in real-time to a DTrace script!  This is a lot easier than it sounds.  I deployed the app (MonApp) from the blog[1] and then ran a super-simple DTrace script.  What the App does is call the probe method each time you refresh it.  wget is an easy way to do the refresh. It increments a counter and calls the probe with a string like so:  "Hello #XX". I didn't even bother writing a script file - I just ran it from a command line: dtrace -n 'fooblog*::: { printf("PID:%d APP:%s %s", pid, execname, copyinstr(arg0)); }' dtrace: description 'fooblog*::: ' matched 1 probe CPU     ID                    FUNCTION:NAME   0  39554             ProbeServlet:myProbe PID:20383 APP:java Hello #22  0  39554             ProbeServlet:myProbe PID:20383 APP:java Hello #23  0  39554             ProbeServlet:myProbe PID:20383 APP:java Hello #24  0  39554             ProbeServlet:myProbe PID:20383 APP:java Hello #25  0  39554             ProbeServlet:myProbe PID:20383 APP:java Hello #26  0  39554             ProbeServlet:myProbe PID:20383 APP:java Hello #27 I got one output line every time I refreshed MonApp in a browser.  This is incredibly powerful!  A string was sent from the user in a browser to a Java WebApp which then sent it off to a native program, DTrace, that was looking for it with a sophisticated scripting language.  All of this can be done without ever restarting the GlassFish Server.  There are truly endless possibilities.  And once you kill the script -- all the instrumentation code is removed.  In case you are wondering about fooblog*:::  -- fooblog is the main name I gave it.  The * is needed because the Monitoring Framework automatically appends the PID of the server (very handy if you are DTracing with multiple GlassFish servers simultaneously).  The ::: means match ANY probe that has the main name that starts with fooblog.  Whew.  Hard to explain in English, easy to explain with one command: ~/gf_other/value-add/monitoring/dtrace/dtrace-samples/dtrace-scripts>dtrace -l | grep fooblog 39554 fooblog20383           samples                      ProbeServlet myProbe To be completely specific in the earlier command would be: dtrace -n 'fooblog20383:samples:ProbeServlet:myProbe { ..... } Dtrace uses the quadruple of names to make the namespace less unwieldy and easier to filter. References  [1] My blog about adding Monitoring probes to a WebApp DTrace Cheatsheet Mac OS X Tutorial on DTrace Handy One-Liners Official GlassFish Documentation on DTrace Java Doc

This is the first in a series of blogs about Dtrace in GlassFish.  I will present concrete examples  in upcoming blogs.  This blog is an overview of this powerful new capability. An entire book couldbe...

Sun

Tip #-1 How Does GlassFish Pick the JVM to Run In?

 If you start a GlassFish Server by using asadmin, then you may be interested in precisely how the JVM that will run GlassFish Server is chosen.  Note that if you restart via the Admin Console (GUI) you are indirectly using asadmin to restart the server and the following rules apply as well.  If you start the Server some other way, like java -jar glassfish.jar then you are in charge of choosing the JVM yourself. In order of precedence from high to low: The jdk location specified in domain.xml in the java-config  ("java-home") The contents of AS_JAVA in the asenv property file (in glassfish/config) Whatever the env. variable, JAVA_HOME, is pointing at. The java.home system property is used like so: Parent directory of java.home -- this is because sometimes the JRE's java is asadmin's JVM and the JDK may be in the directory above. Contents of java.home In every case I guarantee a valid java.  E.g. you can set 1,2,3 to garbage and we'll still find a java to use. Note that we never explicitly use java from the path -- if there is one.  It may be implicitly used though by using #4 above since asadmin itself is definitely running inside of a valid JVM. p.s.  If you are wondering where the code is -- 90% of it is inside AsenvPropertyReader.java 10% is in GFLauncher.java -- AsenvPropertyReader can't access domain.xml.  GFLauncher can.  GFLauncher's job is to see if (1) above applies.  If not he defers to AsenvPropertyReader. Clear?

 If you start a GlassFish Server by using asadmin, then you may be interested in precisely how the JVM that will run GlassFish Server is chosen.  Note that if you restart via the Admin Console (GUI)...

Sun

Test Driven Development in a Large Team

I had a problem to work out.  I know of plenty of wrong-headed things that Monitoring does.  I want to clean up this behavior for GlassFish 3.2  But I want to use the tenets of Test Driven Development.  Namely -- tests FIRST, implement SECOND.  Normally that would mean - add some tests now.  The tests will fail every time until we get around to fixing the code.  Eventually the tests will all start passing as we add in all the fixes.  Overtime we see lots of failures dropping to zero failures. But the problem is that we can't do this is a multiple-developer project with continuous automated runs of the enormous suites of tests.  We can't add tests that will fail (at least not for more than just one cycle).  And I don't want to maintain yet another Hudson job that runs a subset of tests just for monitoring.  Plus it just doesn't feel right.  The tests ought to pass ALL THE TIME. An excellent solution was provided by Carla Mott.  Simple and elegant: 1) Create a test for what you want the new behavior to be.2) Now set the results of that test to the converse of the actual results -- i.e. if they pass, report as a failure and vice versa Result:  The tests will pass every time until you fix the issue.  Then it will fail every time until you fix the test.  We can add lots of these tests for new features, now.  When we implement these fixes when we are under the steaming pressure head of deadlines and milestones we won't have to 'remember' to add Dev Tests.  They are already done and will break like popcorn popping as we complete tasks.  It's impossible to not have working devtests upon completion.

I had a problem to work out.  I know of plenty of wrong-headed things that Monitoring does.  I want to clean up this behavior for GlassFish 3.2  But Iwant to use the tenets of Test Driven Development....

Sun

CLI Logfile and DevTests

Recently a colleague added a test to the Admin Development Tests.  This is a huge suite of tests that we developers use as a sanity test that exercise the administration of a running GlassFish server. here is the symptom of the problem -  The test failed on her machine.The test failed on my machineThe test succeeded on the Hudson build that runs it automatically -- it passed 100% of the time I finally tracked this problem down today with the help of an invaluable tool for asadmin.  I always set this variable in my environment: AS_LOGFILE=D:\\glassfish3\\glassfish\\cli.log When this is set -- every asadmin command is written into the logfile.  It includes the full command with all arguments, the time-stamp and the return value. I quickly figured out the problem by looking in this file on my platform, Windows, and on the Hudson platform, Linux.  Here it is: Command inside the test itself:  asadmin list -m \* Command inside cli.log 03/22/2011 21:55:27 EXIT: 1 asadmin --user admin --passwordfile D:\\gf\\v2\\appserv-tests/config/adminpassword.txt --host localhost --port 4848 --echo=true --terse=true list -m .svn apps build build.xml byron derby.log dome.bat foo foo2 foo2.bat hudson.sh Jira.java mon.bat nbproject pom.xml q qqq resources seconddb src  OOPS!!  The star is special in Windows calling the asadmin script -- even from Runtime.exec().  The star was replaced with the names of every file that happened to be sitting in the directory that the tests are running in.  Solution:  In the code use "\\"\*\\"" for Windows and '\*' otherwise

Recently a colleague added a test to the Admin Development Tests.  This is a huge suite of tests that we developers use as a sanity test that exercise the administration of a running GlassFish server. h...

Sun

Monitoring Data -- How To Open The Firehose

Are you interested in getting raw Monitoring Data without using JavaScript or Dtrace?  That's why we include the special command: asadmin get -m Looks can be deceiving.  It appears that the -m is just some command line option.  Not so.  That turns on a huge pile of code that plows through the run-time tree of monitoring data.  This data can be accessed from instances, clusters of instances and DAS -- in fact ALL the data from all of them can be combined and accessed all at the same time! This command was available in V3.0  Unfortunately it was very slow if you wanted to collect everything (what I call Firehose Mode).  So what was done was a lot of regular expression parsing to narrow down the matching data in order to get things going faster. I reworked this command for GlassFish 3.1 to support the clustering feature.  I started DAS (Domain Administration Server) and one instance.  I ran asadmin get -m "\*"  // Firehose output for DAS and the instance Then I waited.  And waited.  And waited and waited.  About 90 seconds later the server got an out-of-memory error.  I never saw any output at all.  Oops! I discovered the performance bottle-neck.  It was unbelievable what the problem is.  If you are interested I've blogged about it here. We spent a lot of time trying to get the get -m command to handle regular expressions well.  Below are some examples.  My environment: I have a cluster, c1.  c1 has 2 instances, i1 and i2.  Both instances are running with monitoring-levels all set to HIGH.  DAS is also running.  All servers are running on the same machine so I don't muddy the water with network latency etc. asadmin get -m c1 # this retrieves ALL monitoring data for every running instance in c1 (~14,000 lines of output) asadmin get -m c1.\* # does exactly the same thing as above asadmin get -m i2.web.servlet.activeservletsloadedcount-current  # Example drill-down. i2.web.servlet.activeservletsloadedcount-current = 6 asadmin get -m "\*" | wc -l # returned 20,000+ lines.  It took around 1 second on my laptop.   asadmin get -m \*.web.servlet.activeservletsloadedcount-currentserver.web.servlet.activeservletsloadedcount-current = 2  #DASi1.web.servlet.activeservletsloadedcount-current = 6   i2.web.servlet.activeservletsloadedcount-current = 6 The command is so incredibly fast you can simply collect everything in a file and then run text processing commands on that file and avoid calling the command multiple times: asadmin get -m "\*" > output grep hello output # just an example

Are you interested in getting raw Monitoring Data without using JavaScript or Dtrace?  That's why we include the special command: asadmin get -m Looks can be deceiving.  It appears that the -m is...

Sun

Automatic Starting of Servers in GlassFish 3.1

Note: At the end of this blog are links to older blogs from V3.0 about this feature.  You may want to look them over as well. The way we offer the ability to automatically start GlassFish servers is via "services" on the platform.  "Services" are an ancient technology, available on all of our supported platforms (and I would imagine is available on every serious OS).  Services allow applications to run automatically when a computer boots up.  Nobody needs to login -- the service just starts automatically.  A simple example of this is the FTP server.  When you boot up your computer you can access FTP from any other computer without touching the FTP computer.  This is very important in the event of a power failure.  On Windows you can setup automatic security updates and Windows will automatically reboot your computer.  If you have a Subversion server that is not configured as a service and you are halfway around the world depending on it -- you will become a Services Specialist in the near future when you return home! GlassFish 3.1 Platform Services now supports all Linux versions, Windows and Solaris10/SMF Services can be quite complex.  For instance you might want to have it do this: Automatically start a GlassFish server upon booting If the server crashes (no way!) restart itWhat if it crashes every time?  The machine will be in trouble with an infinite loop so: Try to restart 3 times and then give up. Setting up this level of services-granularity is very difficult and expensive to implement perfectly.  For one - we are supporting several platforms and they all do these things completely differently. The hard part is setting up services at all to do the basic things.  Once that is complete you can easily use the platform's native tools for adjusting things just the way you like.  What we support is the classic services model -- which is to start the service upon booting, unattended. I worked hard to make it easy to setup services.  Here's how you would create them for an installation that has one Domain: asadmin create-service If you want to make sure it would work but you aren't yet ready to pull the trigger, or you just want to see what it would do -- then run this command: asadmin create-service --dry-run If your domain is named, say. domain1 then the service's name will be domain1.  Simple.  After the service is created you are greeted with a platform-specific message giving you the details on how to start the service.  We do NOT automatically start it.  I personally recommend rebooting immediately -- and it will start. Windows is particularly easy and flexible to work with.  You can manage the GlassFish service(s) by: GUI -- right-click on Computer/Manage/Services sc.exe  very handy tool for querying/starting/stopping/restarting etc. In the bin directory of the domain or instance run the your-service-nameService.exe application that we put in there.  How to setup automatic starting for an instance? Easy!  Simply give the name of the instance as the final argument to create-service.  The following command will create a service for myinstance: asadmin create-service myinstance There is an undocumented, unsupported command that will delete a service for you.  It is very very easy to delete a service on SMF and Windows.  On Linux it can be tedious.  I've personally tested the command successfully but it has not been through the merciless testing of QA at Oracle.  Use it at your own risk. asadmin _delete-service  Important blog for making sure GlassFish doesn't stop when you logout. I have another blogwith implementation details if you are interested. Some older blogs that pertain to V3.0: V3.0 Platform Services for Windows and SMF DIY Cookbook for Configuring Linux Services How to Run on Linux as a Non-Root User

Note: At the end of this blog are links to older blogs from V3.0 about this feature.  You may want to look them over as well. The way we offer the ability to automatically start GlassFish servers is...

Sun

A Taste of Monitoring in GlassFish 3.1

Ok, so you've installed the Oracle GlassFish Server that you got from here.  You've created a cluster with a couple of instances.  The instances seem to be getting a bunch of traffic.  At least there are a lot of flashing lights on the ethernet cards and disk light is getting hammered.  But how can you find out what's really going on?  That's the whole point of Monitoring.  We have provided a rich platform for getting Monitoring information in GlassFish.  You can ask for a trickle by zeroing-in on exactly the scraps of data you are interested in (e.g. please tell me every time the web-container creates a new thread) or turning the fire hose on and getting every monitored-event as it happens.How do you want to see the data?  In a browser? -- no problem, use either the Admin GUI or REST. You are running in Solaris 10+ and you want to use DTrace?  We support it -- all monitorable events can be seen via native DTrace. You want all of your Applications to get added into this cool Monitoring framework so you can access the data just like the built-in GlassFish Monitoring data?  No sweat, we have provided an easy way to add Monitoring probes to your applications. Not good enough?  Too generic?  You want to be able to collect the data dynamically and structure it some other way using a JavaScript program?  Again, no problem.  You can run a JavaScript program, access as much or as little data as you want, dynamically,  and go crazy massaging the data any way you like. There are a lot of facets to Monitoring in GlassFish 3.1  We will present many blogs with the details to get you going.  As those blogs are completed I'll circle back here and add the links.  In the meantime -- here is a very simple example of a "What-If" question and how to get the answers quickly. How many classes have been loaded by the Domain Administration Server's JVM and what happens with the count when an app is deployed and then accessed? asadmin get -m server.jvm.class-loading-system.totalloadedclass-count-countserver.jvm.class-loading-system.totalloadedclass-count-count = 3887asadmin deploy hello.warApplication deployed with name hello.asadmin get -m server.jvm.class-loading-system.totalloadedclass-count-countserver.jvm.class-loading-system.totalloadedclass-count-count = 5979wget http://localhost:8080/helloasadmin get -m server.jvm.class-loading-system.totalloadedclass-count-countserver.jvm.class-loading-system.totalloadedclass-count-count = 6816 Wow!  That's a lot of classes.  Probably the jump from 3887 to 5979 was loading the web-container (this server had no apps deployed yet) and the next big pile of classes were jsp and servlet classes.  Let's do a sanity check by deploying another simple app: asadmin get -m server.jvm.class-loading-system.totalloadedclass-count-countserver.jvm.class-loading-system.totalloadedclass-count-count = 6819asadmin deploy Math.warApplication deployed with name Math.asadmin get -m server.jvm.class-loading-system.totalloadedclass-count-countserver.jvm.class-loading-system.totalloadedclass-count-count = 6902wget http://localhost:8080/Mathasadmin get -m server.jvm.class-loading-system.totalloadedclass-count-countserver.jvm.class-loading-system.totalloadedclass-count-count = 6906That's semi-interesting.  Deploying a simple web module (with a servlet and jsp)  results in 83 classes getting loaded.  Running the app results in 4 classes being loaded. Monitoring Blogfest Running Monitoring JavaScript Programs on Clusters and Instances

Ok, so you've installed the Oracle GlassFish Server that you got from here.  You've created a cluster with a couple of instances.  The instances seem to be getting a bunch of traffic.  At least there...

Sun

GlassFish 3.1 Scripting of Monitoring Data for Clusters and Instances

Monitoring Scripting is a value-add feature and is available only in the Oracle GlassFish server which is available here. GlassFish 3.1 introduces Clusters and Server Instances.  Monitoring now includes full support of these new features.  In this blog I'll demonstrate a simple application of monitoring-scripting in a clustered environment.  First we need to setup a cluster and start everything: Start DAS (Domain Administration Server)asadmin start-domain Create a cluster with 2 instances -- they will all run on this same machineasadmin create-cluster c1asadmin create-local-instance --cluster c1 i1 asadmin create-local-instance --cluster c1 i2 Set the monitoring level to HIGH for the cluster.  By default it is OFFasadmin enable-monitoring --modules web-container=HIGH --target c1 Start the cluster of 2 instancesasadmin start-cluster c1 Check and make sure everything is running OKasadmin list-domains domain1 runningasadmin list-instances --long    NAME  HOST       PORT   PID   CLUSTER  STATE    i1    localhost  24848  2464  c1        running    i2    localhost  24849  5188  c1        running Deploy a simple app to the clusterasadmin deploy --target c1 hello.war "Hit" the Hello app on both instanceswget http://localhost:28080/hello wget http://localhost:28081/hello Now we have 3 servers running: the DAS and 2 clustered instances.  The web-container is sending events when interesting things happen.  Notice that we really have not done anything special for monitoring except the one enable command.  This looks complicated -- but heck you now have a running cluster with a deployed app etc.  with just a few quick commands.  Not bad!  We want to monitor our Hello app.  I'm especially interested in seeing if, say, my Load Balancer is distributing client calls to Hello equally.  The first step is to get a list of all the probes.  I won't show the list here -- there are 136 probes.  Just run the command and you can see all of them.  I'm interested in the event that fires just before a servlet is run.  So I run this command:  asadmin list-probes | grep servlet | grep before glassfish:web:servlet:beforeServiceEvent (java.lang.String servletName, java.lang.String appName, java.lang.String hostName) This describes one probe.  Everything you need to listen to this probe's event is in this one line.  So now we create a simple JavaScript program.  I'll just enter it here, JavaScript is documented in the official Oracle GlassFish Server and elsewhere.  It's pretty obvious what's going on by reading the program's source code. function requestStartEvent(servletName,appName, hostName) {        client.print( 'requestStartEvent called on App: ' + appName +                      ', Servlet: ' + servletName + '\\n');}params = java.lang.reflect.Array.newInstance(java.lang.String, 3);params[0]="servletName";params[1]="appName";params[2]="hostName";scriptContainer.registerListener('glassfish:web:servlet:beforeServiceEvent', params, 'requestStartEvent'); I saved the script as servlet.js  Now I run this script against the cluster and I start hitting hello in each instance (28080, 28081) sort of randomly just to get some output.   We see output every time Hello (or any servlet) is accessed.  Notice how it shows which server is affected: D:\\gf_other\\value-add\\monitoring\\scripting\\samples>asadmin run-script --target c1 servlet.jsListening to i1 on host localhost and port 24848Listening to i2 on host localhost and port 24849[i1] requestStartEvent called on App: hello, Servlet: jsp[i1] requestStartEvent called on App: hello, Servlet: default[i1] requestStartEvent called on App: hello, Servlet: jsp[i1] requestStartEvent called on App: hello, Servlet: jsp[i2] requestStartEvent called on App: hello, Servlet: jsp[i2] requestStartEvent called on App: hello, Servlet: default[i2] requestStartEvent called on App: hello, Servlet: jsp[i2] requestStartEvent called on App: hello, Servlet: jsp[i2] requestStartEvent called on App: hello, Servlet: jsp[i2] requestStartEvent called on App: hello, Servlet: jsp[i2] requestStartEvent called on App: hello, Servlet: jsp[i2] requestStartEvent called on App: hello, Servlet: jsp[i2] requestStartEvent called on App: hello, Servlet: jsp[i2] requestStartEvent called on App: hello, Servlet: jsp[i2] requestStartEvent called on App: hello, Servlet: jsp[i2] requestStartEvent called on App: hello, Servlet: jsp[i1] requestStartEvent called on App: hello, Servlet: jsp[i1] requestStartEvent called on App: hello, Servlet: jsp[i1] requestStartEvent called on App: hello, Servlet: jsp[i1] requestStartEvent called on App: hello, Servlet: jsp[i2] requestStartEvent called on App: hello, Servlet: jsp[i2] requestStartEvent called on App: hello, Servlet: jsp[i1] requestStartEvent called on App: hello, Servlet: jsp[i2] requestStartEvent called on App: hello, Servlet: jsp[i1] requestStartEvent called on App: hello, Servlet: jsp The beauty of this is that once you have the clusters and everything setup and running you can run scripts on all sorts of probes very quickly.  You don't even have to compile.  Simply edit the script and call run-scriptFor a nice demonstration watch the video that Tom Mueller created here.

Monitoring Scripting is a value-add feature and is available only in the Oracle GlassFish server which is available here. GlassFish 3.1 introduces Clusters and Server Instances.  Monitoring now...

Sun

Automatic Starting Implementation Details for GlassFish 3.1

Process Nuts and Bolts When you start a GlassFish 3.1 Server Service notice that there are 2 JVM processes running.  The 2 process are these: The GlassFish Server A JVM running asadmin start-[local-instance|domain] --verbose Why?  We want to leverage the start command.  Asadmin does a great deal of work for you when you start a server.  The end-product of that work is mainly (but not only) the generation of a big complex JVM invocation command to start the server with.  I could have implemented the Services to call asadmin and have asadmin exit.  But then the Platform would see that asadmin exited and would report the service as "stopped".  It would not know in the future when the server really stops.  When you start a server with the --verbose flag then the asadmin process waits for the server to die before exiting.  When the server stops -- asadmin stops and the Platform will update the state to "stopped". Note that restart-[domain|instance] will still work perfectly.  In that case the server process dies but the asadmin process does not - not even for a moment.  The platform will not "see" anything happening. Linux I discovered that there seems to be a special way to create services for every different flavor of Linux.  And they are all different from each other.  Basically all of these different ways end up with writing out special files into a special area.  This one common denominator is to use the ancient UNIX way of setting up services which is, not surprisingly, editing lots of configuration files in a special area.  Even the exact details on the special area is different among the different flavors.  The code is flexible and will handle all known Linux flavors. The script can be found in /etc/init.d and links to it in the runlevel directories:  /etc/init.d/rc?.d

Process Nuts and Bolts When you start a GlassFish 3.1 Server Service notice that there are 2 JVM processes running.  The 2 process are these: The GlassFish Server A JVM running asadmin...

Sun

Local Strings in GlassFish - A Proposal

There are 2 heavily used classes that help with obtaining localized strings at runtime.  The strings themselves are maintained in one properties file per package.  Usually what happens is that every class in the package will create a static string helper class instantiation.  Since they are static they will last forever once the class is loaded.  If the package has a lot of classes then there will be a lot of these instances.  But the instances are all really the same thing.  They all point at the same properties file in the package.  My proposal is to have an extremely light-weight helper class, in every package that uses localized strings.  This one class has only 2 simple static methods that return strings from that package's properties file.  The class is copied around to every package and, literally, only one line needs to be changed -- the package declaration. Classes in the package need not import anything -- it is already in the package. Everything in the class is package-private -- no public or protected.The class is naturally thread-safe Classes simply use it like so: String msg = Strings.get("labelHere", "arg1", "arg2"); I have 2 goals with this proposal Make it easier to localize strings in GlassFish code.  I don't know how to make it any easier! Avoid Code Duplication Example Implementation.  You literally copy, paste and change the package name.  This implementation  uses LocalStringsImpl as the workhorse.  You could change things around  bit to use LocalStringManagerImpl instead. package com.sun.enterprise.util.cluster;import com.sun.enterprise.universal.i18n.LocalStringsImpl;/\*\* \* Strings -- Get your Strings here. \* One file with Strings \* So one class for messing with them! \* Nothing in here is public or protected.  Only for use by this one java package. \* @author Byron Nevins \*/final class Strings {    private Strings() {        // no instances allowed!    }    final static String get(String indexString) {        return strings.get(indexString);    }    final static String get(String indexString, Object... objects) {        return strings.get(indexString, objects);    }    final private static LocalStringsImpl strings = new LocalStringsImpl(Strings.class);}

There are 2 heavily used classes that help with obtaining localized strings at runtime.  The strings themselves are maintained in one properties file per package.  Usually what happens is that every...

Sun

GlassFish V3.1 Offline Configuration

Clustering support is available now in pre-release GlassFish 3.1  In this blog I will show you how to perform Offline Configuration in GlassFish 3.1 I've blogged about  why and how to do Offline Configuration here. One big difference between GlassFish V2 and GlassFish 3.1 clustering is that node agents are not provided and used in GlassFish 3.1.  Instead ssh is utilized.  Using ssh in GlassFish 3.1 is the subject of a different future blog.  In this blog I'll demonstrate how to setup a distributed GlassFish 3.1 system without node-agents or new ssh features. The Desired Environment DAS running on improvident One cluster The cluster has one instance DAS and the instance run on different machines Notes The names are just the names of the machines I happened to use. This is as simple a distributed system as possible for demonstration purposes.  machine1 = samskritam machine2 = improvident install the same  GlassFish 3.1installation files on each machine.  DAS (domain1) is used on samskritam.  The other machine never runs DAS. improvident has this set in its environment -- This makes it easy to run asadmin commands. AS_ADMIN_HOST=samskritam In the Procedure section I'm using these conventions: I put the name of the machine where the command is running at the beginning of the line - you wouldn't type that in. Comments are in italics Output from asadmin is bold Procedure [samskritam] asadmin start-domain [samskritam] asadmin create-cluster mycluster [samskritam] asadmin create-node-config --nodehost improvident imp [samskritam] asadmin create-instance --cluster mycluster    --node imp mycluster_i1 [improvident] asadmin create-local-instance --node imp mycluster_i1 [improvident] asadmin start-local-instance mycluster_i1 Output On Samskritam: samskritam% asadmin start-domainWaiting for the server to start ....Successfully started the domain : domain1domain location: /home/kedar/glassfishv3/glassfish/domains/domain1Log File: /home/kedar/glassfishv3/glassfish/domains/domain1/logs/server.logAdmin Port: 4848samskritam% asadmin create-cluster myclustersamskritam% asadmin create-node-config --nodehost improvident impsamskritam% asadmin create-instance --cluster mycluster    --node imp mycluster_i1remote failure:Successfully created instance mycluster_i1 in the DAS configuration, but failed to create the instance files. Please run:asadmin --host samskritam.SFBay.Sun.COM --port 4848 create-local-instance --node imp mycluster_i1on improvident to complete the transaction.____________________________________________________ On improvident: ~>asadmin create-local-instance --node imp mycluster_i1Attempting to rendezvous with DAS on host samskritam port 4848Uptime: 1 minutes, 31 secondsThe instance has rendezvoused with the DAS and will be using host samskritam port 4848 for future communication.servers.server.mycluster_i1.config-ref=mycluster-configservers.server.mycluster_i1.lb-weight=100servers.server.mycluster_i1.name=mycluster_i1servers.server.mycluster_i1.node=impservers.server.mycluster_i1.node-agent-ref=improvidentservers.server.mycluster_i1.property.rendezvousOccurred=true ~>asadmin start-local-instance mycluster_i1Waiting for the server to start ......................................Successfully started the instance: mycluster_i1instancelocation: /export/home/bnlocal/glassfishv3/glassfish/nodeagents/improvident/mycluster_i1Log File: /export/home/bnlocal/glassfishv3/glassfish/nodeagents/improvident/mycluster_i1/logs/server.logAdmin Port: 24848~>asadmin list-clustersmycluster running~>asadmin list-instances --verboseInstance Name   Host Name     Admin Port   Cluster     Current State---------------|-------------|------------|-----------|--------------------------------|mycluster_i1    improvident      24848      mycluster  Uptime: 15 minutes, 11 seconds

Clustering support is available now in pre-release GlassFish 3.1  In this blog I will show you how to perform Offline Configuration in GlassFish 3.1 I've blogged about  why and how to do Offline...

Sun

Run GlassFish V3 as a non-root Service on Linux Ubuntu/Debian

Background I already showed you how to setup GlassFish V3 as a Service on Linux here.  In that blog I used root as the GlassFish "owner" for simplicity.  In this blog we will do the same thing except with a non-root user.  If you already have a user and/or you have V3 installed you can skip some of the earlier steps.  Once again my main motivation is to get these procedures worked out carefully so that I can implement it automatically.  Currently we support Windows and Solaris 10.  For each step I'll also show you how to undo the change in case you want to rollback everything. 1. Create a user I decided to create my own GlassFish user that exists solely to run GlassFish.  You could use your own existing account as well.  I also created a new group for use only by this user.  I.e. I don't want this user to have any Linux admin privileges. sudo groupadd glassfishsudo useradd -s /bin/bash -d /home/glassfish -m -g glassfish glassfish  UNDO: sudo userdel glassfish sudo groupdel glassfish 2. Login as the new user in a terminal window and set a password (if desired) sudo passwd glassfishsudo -i -u glassfish 3. Install GlassFish V3 using user glassfish cd ~wget  http://download.java.net/glassfish/v3/release/glassfish-v3.zipunzip glassfish-v3.ziprm glassfish-v3.zip UNDO: rm -rf ~/glassfishv3 4. Exit the shell from step 2 5. Copy the script to /etc/init.d  and configure it as a Service sudo cp the-script /etc/init.d/glassfish sudo update-rc.d glassfish defaults UNDO: sudo rm /etc/init.d/glassfishsudo update-rc.d glassfish remove All Done You can start, stop or restart GlassFish V3 like so.  Note that you must do it with an account that has admin privileges.  The user "glassfish" ironically can not do this even though the server will run as "his" process. sudo /etc/init.d/glassfish start|stop|restart How to Allow GlassFish V3 to use ports less than 1024  This technique configures the firewall to send all port 80 traffic to port 8080.  You can do the same thing for any other ports you need that are less than 1024.  I don't know how to undo it. iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080 iptables -t nat -A PREROUTING -p udp -m udp --dport 80 -j REDIRECT --to-ports 8080 Service Script #!/bin/sh# Platform Services for GlassFish# GF_USER=glassfishGF_HOME=/home/$GF_USER/glassfishv3/glassfishASADMIN=$GF_HOME/bin/asadminSU="su --login  $GF_USER --command  " case "$1" instart)    $SU "$ASADMIN start-domain > /dev/null 2>&1 &"    ;;stop)    $SU "$ASADMIN stop-domain > /dev/null 2>&1 &"    ;;restart)    $SU "$ASADMIN restart-domain > /dev/null 2>&1 &"    ;;\*)    echo "usage: $0 (start|stop|restart|help)"esac

Background I already showed you how to setup GlassFish V3 as a Service on Linux here.  In that blog I used root as the GlassFish "owner" for simplicity.  In this blog we will do the same thing...

Sun

How to Run GlassFish V3 as a Service on Linux Ubuntu/Debian

We already support running GlassFish V3 as a service on Solaris 10 and Windows platforms (see my blog).  I have been investigating how to provide support for automatically starting GlassFish V3 as a service on Linux.  Of course before I can hope to do that -- I must be able to set it up manually.  In this blog I will take you through the manual steps needed to run GlassFish V3 as a service on Linux. This procedure was worked out on my Linux system which happens to be Ubuntu.  Other flavors of Linux may have slightly different procedures. One decision you need to make right up front is what Linux user should "own" GlassFish V3.  Typically root is used as the owner.  If you choose root as the user you get the advantage that you can use ports < 1024 without complex configuration changes to the system.  For this blog I used root.  Here are the steps  -- the file named "glassfish" in step 4 is the simple init script which appears at the end of this blog. Install JDK 6 if needed Have root install GlassFish like so: cd /opt wget  http://download.java.net/glassfish/v3/release/glassfish-v3.zip unzip glassfish-v3.zip rm glassfish-v3.zip cd /etc/init.d cp glassfish . update-rc.d glassfish defaults OPTIONAL /etc/init.d/glassfish start OPTIONAL Make sure GlassFish is running OK reboot -- you are done! To start, stop, restart GlassFish simply run these commands: sudo /etc/init.d/glassfish startsudo /etc/init.d/glassfish stopsudo /etc/init.d/glassfish restart #!/bin/sh ## glassfish init script for Linux # Simplest possible case -- no password file, one default domain# it would be simple to add such optionsGLASSFISH_HOME=${GLASSFISH_HOME:-"/opt/glassfishv3/glassfish"}case "$1" instart)    $GLASSFISH_HOME/bin/asadmin start-domain >/dev/null    ;;stop)    $GLASSFISH_HOME/bin/asadmin stop-domain >/dev/null    ;;restart)    $GLASSFISH_HOME/bin/asadmin restart-domain >/dev/null    ;;\*)    echo "usage: $0 (start|stop|restart|help)"esac

We already support running GlassFish V3 as a service on Solaris 10 and Windows platforms (see my blog).  I have been investigating how to provide support for automatically starting GlassFish V3 as...

Sun

GlassFish v2 Offline Configuration

Review of Clustering Features in GlassFish v2 A typical GlassFish v2 enterprise installation consists of one administration domain controlled by the Domain Administration Server (DAS) which handles all of the administration duties of the domain.  The  domain provides a common  authentication and administration point for a collection of Java EE server instances. Each JavaEE server instance gets it's configuration from DAS and has its lifecycle controlled by a Node Agent.  A Node Agent is a very light-weight process that DAS interacts with.  Node Agents and remote Java EE server instances synchronize with DAS during startup to get the latest configuration from the central repository managed by DAS. GlassFish v2 supports the concept of cluster wheremultiple Java EE server instances can be grouped for horizontalscalability. EachJava EE server instance in a cluster shares the same set of applications and configuration information. Typical Configuration Say you have a running DAS (Domain Administration Server) and you wish to add a cluster, a few instances and a Node Agent running on a separate machine.  Here is how you would do an online configuration: Login to the new Node Agent machine asadmin create-node-agent NA-Name asadmin create-cluster asadmin create-instance (probably need to run this command a few times) asadmin start-node-agent  You can see how if you have a lot of machines this can become a headache.  Note that create-instance has many required parameters that I'm not showing here. Offline Configuration Offline Configuration lets you do all of the configuration right from the DAS machine.  On each Node Machine you run two very simple commands: asadmin create-node-agent NA-Name asadmin start-node-agent NA-Name There are several good reasons for developing scripts for offline configuration of complex GlassFish installations: You can develop scripts that will exactly recreate your system from scratch.  I'm talking about deploying your applications, setting complicated jvm-options, configuring database connections, setting up multiple clusters and instances -- the works!  This is very powerful.  I have a personal website that has been running v2 for 4 years or so.  I can recreate the entire site anytime I like on any new machine that has v2 installed.  It has a ton of applications, a database, etc. You need the complicated configuration information to be used on just one machine, DAS, in a multiple machine installation. You can replace a Node easily at any time No restarts are needed during the creation of the instance, cluster and node-agent configuration since it is all being done offline.  Once ALL of the configuration is complete everything is started at once and no restarts will be needed.  This is a key difference with online configuration. Faster to automate a multi-node GlassFish cluster setup withdesired configuration. It works! Example Offline Configuration Session Generally one would want to edit a script and run the script.  Here is a an example session to show you how to do it from a command line: (For clarity the credentials such as --user and --passwordfile are left out of the commands) asadmin start-domain asadmin create-cluster c1 asadmin create-node-agent-config na1 asadmin create-node-agent-config na2 asadmin create-instance --cluster c1 --node-agent na1 i1_1 asadmin create-instance --cluster c1 --node-agent na2 i2_1 asadmin create-instance --cluster c1 --node-agent na2 i2_2 We didn't start anything.  All of the commands changed the configuration in the domain.xml.  Namely it created 1 new cluster with 2 node agents and a total of 3 instances. To get everything running we do this: For each machine (in this case 2 separate remote machines with v2 binaries installed) asadmin create-node-agent na1 or na2 asadmin start-node-agent na1 or na2 note: the Node Agent name must match exactly the name in create-node-agent-config above.  Otherwise you will get a new Node Agent created! Example Script Kedar Mhaswade created  the attached example shell script.  The script demonstrates how you can automate building a four-machine Enterprise GlassFish v2 Installation. References: GlassFish v2 Clustering Article GlassFish Clustering Under 10 Minutes(Screencast) GlassFish v2 Architecture This blog was prompted by the recent fixing of this bug

Review of Clustering Features in GlassFish v2 A typical GlassFish v2 enterprise installation consists of one administration domain controlled by the Domain Administration Server (DAS) which handles all...

Sun

How to make GlassFish 3.1 Platform Services Survive Logoff

Refer to my other blog for general details about setting up Platform Services A running JVM does not survive the user logging off unless you wave a magic wand over the JVM startup parameters.  It is very simple.  If you give the -Xrs option then the JVM will completely ignore logoff events (as well as others).  The solution in V3 is very simple but first let me give you a little background.  Skip to the end of  this blog to see the solution if you are in a hurry.  In V2 all you needed to do was add -Xrs as a jvm-option to domain.xml and you were all set.  If you tried this on V3 you'll have noticed that it does not work.  The reason is that V3 running as a service is really two separate JVM's.  There is an asadmin "watchdog" JVM and the V3 JVM.  This arrangement is exactly like running asadmin start-domain --verbose at a command line.  These 2 JVMs go through life together.  If one dies then the other is automatically killed.  That's the problem.  You can set the -Xrs flag in domain.xml but if the asadmin JVM does not also have it set, then logging off will kill the asadmin JVM which, in turn, will automatically take the V3 JVM down with it.  The solution is simple: set -Xrs on both JVMs.  I verified that V3 running as a service will only survive a logoff if both JVM's have it set.  I tested all 4 combinations:  domain.xml   -Xrs ?  asadmin   -Xrs?  Survives Logoff event?  No  No  No  Yes  No  No  No  Yes  No  Yes  Yes  Yes My recommendation is to set -Xrs for asadmin once and then forget about it.  You can always adjust the behavior exclusively from domain.xml.  Solution asadmin create-jvm-options -Xrs edit install-root/bin/asadmin[.bat] and add the -Xrs option to the java command To turn off the behavior run this command: asadmin delete-jvm-options -Xrs

Refer to my other blog for general details about setting up Platform Services A running JVM does not survive the user logging off unless you wave a magic wand over the JVM startup parameters.  It is...

Sun

Mort Learns How To Use Monitoring in a WebApp

 This blog is a follow-up of my earlier monitoring blog, and I recommend reading that one first. This time we will setup probes inside of a user application.  We will not be in the internal GlassFish environment.  We need to use the Monitoring tools available from GlassFish OSGi.  But -- we will be in a plain vanilla web module, not an OSGi module.  Oh no!  How can we access the Habitat inside GlassFish?  JavaEE 6 comes to the rescue with the @Resource annotation!     @Resource    private ProbeProviderFactory probeProviderFactory;    @Resource    private ProbeClientMediator listenerRegistrar; These 2 variables are what we need to register a probe and hook up the probe with a listener. The web app consists of the usual boilerplate song and dance needed for any web app.  The business end of this web app is in two classes: The Servlet class -- ProbeServlet.java The Probe Listener class -- MyProbeListener.java The servlet class has this method: @Probe(name="myProbe")public void myProbeMethod(String s) { System.out.println("inside myProbeMethod " + "called with this arg: " + s); } and it has this annotation at the class level: @ProbeProvider( moduleProviderName="fooblog", moduleName="samples", probeProviderName="ProbeServlet") That's all you need to do to turn this servlet class into an official GlassFish V3 Probe! To get the Probe registered with GlassFish you need to add one line of code that needs to run before you use the probe (I added it to the init method): probeProviderFactory.getProbeProvider(getClass()); I made the servlet painfully simple.  Whenever you load or reload the servlet it calls myProbeMethod().  Of course all of this would be pointless without a listener class that is hooked-up to the probe.   The init code in the servlet hooks up the listener with this one line of code: listenerRegistrar.registerListener( new MyProbeListener()); But wait!  How in the world is that listener class going to be connected to the probe class?!?  This is where the magic of annotation processing comes in.  The listener class is super-simple.  Here it is in it's entirety: public class MyProbeListener { @ProbeListener("fooblog:samples:ProbeServlet:myProbe")  public void probe1(String s) {  System.out.println("PROBE LISTENER HERE!!!!");  }} Note how the strings in the ProbeProvider annotation are used in the listener to identify the correct probe. This is a very simple example but you can see how you can create listeners in their own separate apps and have probes in many apps.  To see the output simply tail the server log.  When you write to System.out from a Listener - it will appear in the server log. The app is available in open source as a maven web-app.  It can be checked out using this URL: https://svn.java.net/svn/glassfish~svn/trunk/v2/appserv-tests/devtests/admin/cli/apps/MonApp Note:  If you make changes to the Listener class you should restart the server after redeploying. Sample output from loading the app in a browser: ....|PROBE LISTENER HERE.  Called with this arg: Hello #1|#]....|inside myProbeMethod called with this arg: Hello #1|#]

 This blog is a follow-up of my earlier monitoring blog, and I recommend reading that one first. This time we will setup probes inside of a user application.  We will not be in the internal...

Sun

Mort Learns Monitoring and Admin Commands for GlassFish

Monitoring is a powerful feature in GlassFish V3. Admin Commands are a powerful feature in GlassFish V3.   In this blog I'll show you how to create an Admin Command that exercises the Monitoring Facilities. Glossary: ProbeProvider - A class or interface that has methods (Probes) that can be called at runtime. Probe - A method that can be called at runtime that in turn will call any Listeners that are registered Listener - A method that is registered to receive "events" coming from a Probe Admin Command - An easy to call command running on GlassFish V3.  You can access it via REST, HTTP or asadmin.  You could easily do this whole tutorial inside a servlet instead.  I chose to use an Admin Command so you can see how to create and use commands. Background In this tutorial we will work with a ProbeProvider interface.  We write an interface with the methods (Probes) that we wish to call at runtime.  We never create an implementation of this interface.  Instead we hand it off to GlassFish.  GlassFish will magically create an implementation class for the interface and return an instance of that implementation.  Under the hood, GlassFish has automagically inserted code into your methods that will call any Listeners that you subsequently register. Using an interface is a fairly unusual case.  The much fancier and more usual case is that you give GlassFish an instance of any POJO that has the proper annotations.  GlassFish will then rewrite the actual bytecode of the class and add calls to the Listeners! Admin Command The command should setup the Probes and Listeners correctly the first time the command is run Each subsequent call should fire the appropriate probe  The complete class is here You provide LCPP and LCListener.  LCPP is the Probe Provider interface and LCListener is the Listener class.  The 2 lines that do all the registering and magic are here: probe = probeProviderFactory.getProbeProvider(LCPP.class);listenerRegistrar.registerListener(new LCListener()); That's all!  You now have a probe object that you can call methods on that will automatically call your listener class. Probe Provider Interface The interface is here.  As you can see it is mostly  a bunch of annotations and 2 methods: void ping();void ping2(@ProbeParam("message") String s); Note that they must return void   You should make all parameters primitives or String to avoid trouble. Probe Listener  The source is here.  Now you can see how the Listener gets hooked up with the Probe.  The Listener needs the values from the ProbeProvider annotation in the Probe Provider class.  It's a lot easier to see how to do it by looking at the source then for me to explain it. How to Test Take the files and drop them into a GlassFish extension project.  If you have GlassFish source just do what I did -- drop them into the core/kernel module.  Or you can just use the files as a guide and, say, create a Servlet instead of using an Admin Command. build and deploy the jar start the server tail the server log (even better -- run  asadmin start-domain --verbose) call asadmin ping <optional-string-here>   Look for the listener messages in the log goto 5

Monitoring is a powerful feature in GlassFish V3. Admin Commands are a powerful feature in GlassFish V3.   In this blog I'll show you how to create an Admin Command that exercises the Monitoring...

Sun

Platform Services Available in V3

Platform Services have just been rolled out for the first 2 platforms: Solaris  Management Facility (SMF) Windows In the simplest case where you have one default domain and you want to run it as a service you run this command: asadmin create-service Here are all of the options: [--passwordfile password-file] [--name service-name] [--serviceproperties (name=value)+] [--dry-run=false] [--domaindir domain_parent_directory] [domain_name]  Once you have created the service it can be controlled in various ways by operating system and native tools.   Windows We use Windows Service Wrapper as the tool for installing the service.  It can be used to start stop and uninstall the service.  It can be found in the bin subdirectory of the domain directory.  In the default case the name of the executable will be domain1Service.exe  The directory also contains the configuration file, domain1Service.xml.  Below are the available commands: domain1Service start domain1Service stop domain1Service uninstall domain1Service install You can also manage the GlassFish service with Windows tools:  Services snap-in and the net command line program. Solaris  Management Facility (SMF) You create the service exactly the same as WIndows.  One big difference for most users is that on Windows most users have administration privileges.  I.e. everyone is super-user.  Not so on Solaris.  In order to create a service you must have SMF privileges.  How to set that up is beyond the scope of this blog, but root definitely has these privileges by default   Important: If root creates a service then only root can start that domain from then on.  The best way to set this up is to install and/or create the domain as root and then create the service as root. Once you have created the service you need to start it yourself.  Here are the most typical Solaris commands of interest: /usr/bin/svcs  -a | grep domain1  // status /usr/sbin/svcadm enable domain1 // start /usr/sbin/svcadm disable domain1 // stop /usr/sbin/svccfg delete domain1 // uninstall Future Directions If there is interest, demand and time we will add support for controlling the service from CLI: start stop uninstall restart

Platform Services have just been rolled out for the first 2 platforms: Solaris  Management Facility (SMF) Windows In the simplest case where you have one default domain and you want to run it as a...

Sun

GlassFish V3 Remote Restart Now Available

GlassFish V3 is now sporting a brand new capability:  Remote Restart. This feature is particularly handy for environments where the server machine is secured and difficult to get to.  With the right credentials you can now restart the server from anywhere in the world -- as well as from the same machine.  It is very easy to use.  As of today there are two ways to call the restart-domain command with the third method coming online soon (1) Use a URL in a browser:  http://yourhost:4848/__asadmin/restart-domain (2) Use asadmin like so:    asadmin --host yourhost restart-domain (3) Coming soon:  Admin Console GUI support for the commandThe asadmin command, restart-domain, is what I like to call a "hybrid" command.  It is both a local and a remote command.  The local portion of the command's job is to block until it verifies that the server has completed its restart and is online and ready to go.  The remote portion does the actual restarting. Details There are 3 main flavors of starting non-embedded V3.  Restart-domain works with all three: Starting the server with the launcher (i.e. asadmin start-domain).  Restarting will stop the running server and once the JVM process is guaranteed to have exited the server will restart.  There are no special "watchdog" processes involved.  The server itself does the work itself in what I like to call "reincarnation".  This is easy to see by running jps during the restart.  You will see the process id change.  You can also watch the server log as the server restarts. Starting the server with the launcher in verbose mode (i.e. asadmin start-domain --verbose).  The key point here is that we have to preserve the console that asadmin owns here.  So we do the restart a little differently.  Since the asadmin process is also running  on the server machine, we ask the already running asadmin process to restart the server for us.  asadmin does all the heavy lifting here. Starting the server in implanted mode (e.g. java -jar glassfish.jar).  A new jvm will be started with exactly the same commandline arguments.  Note that if the server owns the console -- i.e. is running "in the foreground" and mirroring log messages -- the new server will lose control of the console.  We can not absolutely guarantee a clean shutdown without literally closing down the JVM itself.  Once that is done the console is out of reach. Give it a try!

GlassFish V3 is now sporting a brand new capability:  Remote Restart. This feature is particularly handy for environments where the server machine is secured and difficult to get to.  With the right...

Sun

Simple Embedded GlassFish App using Maven

Today's blog demonstrates how to create a very simple GFE (GlassFish Embedded) application.  The application requires no manual downloads.  GlassFish need not be installed and no GlassFish files of any kind need to be present. The application uses a very simple web app named, appropriately, simple.war.  The simple.war file has been checked into Subversion for this project.  This breaks the usual rules of checking in only source code.  But I wanted to make this application as simple as possible for you to use.  You could replace simple.war with your own not-so-simple web app by renaming it to simple.war and overwriting the original. Here is how to checkout and build the sample project: svn co https://svn.dev.java.net/svn/glassfish-svn/branches/embedded_v3_prelude_release/embedded/samples/SimpleMaven cd SimpleMaven mvn You can run the GFE application by executing r.sh(\*NIX) or r.bat(Windows).  If you are on \*NIX don't forget to make r.sh executable (chmod +x r.sh) What Does this Sample GFE Do? Create a GFE server Create a HTTP listener at port 7777 Start the GFE server Deploy simple.war to the GFE server Send a request to simple at port 7777 and print the results Wait for user to kill the server (\^C)  Details Maven downloads the GFE jar to your local repository The Maven  Dependency plugin is used to copy the GFE jar from your local repository to the target directory.  Why?  So the run script will work in all scenarios -- since I don't know where your local repository lives.  It isn't strictly necessary,  you could point the classpath to the location of the file in your local repository. The pom.xml for this project is as simple as possible.  The copying over of the GFE jar is the messiest part of the pom.xml.  Take a moment to examine pom.xml There is one java file for this project.  Take a look at it.  Change the port from 7777 to 12345 or your favorite port number.  Have it deploy 2 or 3 more web apps.  Play around with it. Next Steps It would be nice if we didn't have to use the run scripts.   It would be nice to have Maven run the app.  In the next installment in this series I will show you just how to do that with the GFE plugin!  https://svn.dev.java.net/svn/glassfish-svn/branches/embedded_v3_prelude_release/embedded/samples/SimpleMaven

Today's blog demonstrates how to create a very simple GFE (GlassFish Embedded) application.  The application requires no manual downloads.  GlassFish need not be installed and no GlassFish files of...

Personal

JDK - GetAbsolutePath doesn't

I just finished fixing a bug and I decided to share it so you can avoid the misery of finding it yourself.JDK's java.io.File is not that smart about Files vs. String Paths.   You may use getAbsolutePath and getAbsoluteFile because you think it will really give you an absolute path.  Not true at all.  It merely fills in the beginning of the path for you.  It does nothing about trailing dots. Say your current directory is /foo.  Let's say you have a file named x in the current directory. String s = new File("x").getAbsolutePath();this returns "/foo/x".  Perfect!Now say you do something crazy like String s = new File("../foo/./x").getAbsolutePath();this returns "/foo/./x"  -- doesn't look absolute to me!What the JDK means by absolute is only that the absolute path will unambiguously point at a file -- without needing the location of the current directory.  Period.   It does most definitely not imply that that you are getting a path with no relative elements in it.getCanonicalFile and getCanonicalPath are highly under-used methods in my experience.  These methods guarantee to return a 1:1 mapping with the file.  I.e. there is one and only one unique Canonical path for every file on disk.  There are an infinite number of Absolute paths for a given file. String s = new File("../foo/./x").getCanonicalPath();this returns "/foo/x" -- just what you wanted.Now here is where I got into trouble.  I'm given a ABSOLUTE  path to a jar file.  I need to get the parent directory of the directory that contains the jar file.  So I innocently did the following:given:  File f  which internally has this path "/foo/lib/./x.jar" File grandparent = f.getParentFile().getParentFile();String s = grandparent.getPath();I expected the String to be "/foo"It wasn't though, it was "/foo/lib"! JDK says the parent is "/foo/lib/.", and the parent of the parent is "/foo/lib"JDK is not treating "." specially but, rather, like it's a regular file in this context!My code was working perfectly until the caller decided to drop a dot in the middle of the path and then suddenly my code broke.SOLUTION:Use CanonicalPath and CanonicalFile.  But wait -- they might throw an IOException.  What a hassle!!That's no big deal.  I've been using them for years and I have never seen an Exception get thrown.  JDK is paranoid because these methods call into native code to get the right path.  I've written this following snippet of code way, way too many times.  I highly recommend it -- but add it into your utility code, write it once and call it a gazillion times. public static File sanitize(File f) {    if(f == null) {        return null;    }    try {        return f.getCanonicalFile();    }    catch(Exception e) {        return f.getAbsoluteFile();   }}Here is some sample code you can try, along with the output:public class Main{    public static void main(String[] args)    {        File f = new File(System.getProperty("java.io.tmpdir") + "/foo");        f.mkdirs();        String foo = f.getPath();                foo += "/./././././.";        f = new File(foo);        // f is now "c:/tmp/foo/./././././."                while((f = f.getParentFile()) != null) {            System.out.println("PARENT: " + f);        }    }  }  Output:PARENT: c:\\tmp\\foo\\.\\.\\.\\.\\.PARENT: c:\\tmp\\foo\\.\\.\\.\\.PARENT: c:\\tmp\\foo\\.\\.\\.PARENT: c:\\tmp\\foo\\.\\.PARENT: c:\\tmp\\foo\\.PARENT: c:\\tmp\\fooPARENT: c:\\tmpPARENT: c:\\ 

I just finished fixing a bug and I decided to share it so you can avoid the misery of finding it yourself.JDK's java.io.File is not that smart about Files vs. String Paths.   You may use...

Personal

I Want To See My JSP's Generated Servlet Source!!

It is difficult to see the servlets that get generated from  your JSP files.If you politely ask NetBeans it will tell you something like "You have to run the file first".  And this is after you run the file!Anyways once you know how -- it is easy.  Read on...Background:When you deploy a web module (or a Web App that has a web module in it) by default it will not compile the jsp's as part of the deployment process.  Instead, the jsp will be compiled "just in time" by the web container the first time the web module is accessed long after deployment completes.We need to tell the jsp-compiler to keep the generated files instead of deleting them.  This is the "keepgenerated" option to the jsp-compiler.  You set this option by editing the default-web.xml file in the domain's config directory.  Search for "keepgenerated" and you will see the xml that needs editing just below the enormous comment.  It should look like this when you're done editing   <servlet>    <servlet-name>jsp</servlet-name>    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>    <init-param>      <param-name>keepgenerated</param-name>      <param-value>true</param-value>    </init-param>    <load-on-startup>3</load-on-startup>  </servlet>You would think that that is enough to get your generated source, but it is not.  The web-container orchestrated jsp compile is either ignoring the keepgenerated option -- or the generated files are well-hidden.But it will work if you ask the GF Deployment code to do the compiling for you like so:asadmin deploy --precompilejsp=true some.war ALL of your jsp generated servlet source will be located in:your-domain-dir/generated/jsp/j2ee-modules\\YourModule/org/apache/jsp___________________________In summary:(1) setup the keepgenerated option in default-web.xml and then forget about it(2) For every deployment use the --precompilejsp=true optionI spent far too much time figuring this out so I am sharing my results here.  As I was stepping through the deployment source code I thought "Wow, this is pretty nice code".  Then I realized "HEY!  I wrote this code!  It's been about 5 years but there it still is!" 

It is difficult to see the servlets that get generated from  your JSP files. If you politely ask NetBeans it will tell you something like "You have to run the file first".  And this is afteryou run the...

Personal

New Backup Restore for V3

We are considering significantly improving the Backup and Restore abilities in GlassFish for V3.  If you have desires/needs/suggestions on Backup Restore features, now is the time to let us know.  Just leave a comment! Increase granularity -- i.e. allow selecting one or more of the 4 kinds of deployed "things"backup JavaEE modulesbackup  JavaEE appsbackup lifecycle modulesbackup mbeansAlso:backup configurationbackup nodeagents and instancesbackup EVERYTHING -- the entire GlassFish installationCustomized Rules -Exclude certain files and/or directories from the backupSpecify whether or not to backup symbolic link directories recursivelyDefine other things to backup -- e.g. databasesIncremental BackupsThis is very useful when you have a big GlassFish system that doesn't change too often.  You can have the security of frequent backups without using up huge amounts of disk space. Automatic BackupsContinuous Configuration Backup - backup domain.xml every time it changes and keep the last, say, 10 versionsAutomatically backup the previous version of every app and moduleBackup GUISpecifying the above details via, say, an xml file could be rather painful.  We can develop a GUI for doing customized Backup or Restore  immediately.  Even better, the GUI would make it easier to specify everything and then produce an xml file that can be used in an automated manner.

We are considering significantly improving the Backup and Restore abilities in GlassFish for V3.   If you have desires/needs/suggestions on Backup Restore features, now is the time to let us know. ...

Personal

Mort Learns JDBC Realm Authentication for GlassFish

Here is another good blog on this subject.In my last blog I showed you how to make a jdbc-resource that you can use for accessing a database.Now I'll explain how to use that jdbc-resource to setup JDBC Realm Authentication and Authorization.Realm BackgroundThe job of a realm is to maintain a repository of user information.  Each user has one password and 0 or more groups that he belongs to.At runtime a Realm is initially given a username and password and the realm then figures out if the user is authentic by checking the password.  It checks for authorization by seeing if the user's list of groups is authorized to use a resource (more on this later).How to Create The Realm for userauth Using Admin GUI navigate to Configuration/Security/Realms.  Press the "new" buttonPick the classname that ends in JDBCRealm.  Use the jndi name of your jdbc-resource -- if it isn't userauth.I'm assuming that you are starting from scratch with no user database.  If you already have such a database, you need to make sure your database table and column names are entered correctly and that your tables correspond to what JDBCRealm needs.  Such details are coming up...Tip: Use the names in the screen-shot for the 2 table names and 3 column names.  These names are as good as the next.  If you standardize on these names you can use some tools I've developed for help administering and testing the realm.Database user and password -- I'm not so sure about this.  The connection you get from the jndi name already has the username and password for that database.  I put the username and password from my database here and everything worked fine...Digest AlgorithmYou have to decide whether to save passwords as clear-text or encrypted.  If you want clear-text, leave the edit field blank.  If you want your passwords encrypted set this field to MD5.My recommendation is to use MD5 for the passwords.  I have some tools with the code you need to convert a plain text password to an encrypted string in the right format for JDBCRealm.On the other hand you can set it to no encryption -- and it will be much easier to seed the tables with test user info.   You can always change it to MD5 later when you have everything working.All of the GlassFish administration work is now done.Now you need to add some tables to your database.  You can run this sql script and it will do all the work for you.  The script also adds one user with username=admin and password=admin. The easy way to do this is to run "ij" -- a javaDB  sql console -- there is a copy here: <gf>/javadb/binij> connect 'jdbc:derby://localhost:1527/userauth;user=APP;password=APP;create=true';ij> run 'createdb.sql';Now it's time to try out a protected web module.   What we want here is the World's Simplest Web Module. In NetBeans, create a new web module.  The web module consists of one hello world jsp file.  Perfect.  If you don't use NetBeans then create some sort of ultra simple web module.We have to add quite a bit of stuff to web.xml.  Netbeans makes fast work of it: Here are the additions to web.xml (generated by NetBeans)<security-constraint>        <display-name>Constraint1</display-name>        <web-resource-collection>            <web-resource-name>protected</web-resource-name>            <description/>            <url-pattern>/\*</url-pattern>            <http-method>GET</http-method>            <http-method>POST</http-method>            <http-method>HEAD</http-method>            <http-method>PUT</http-method>            <http-method>OPTIONS</http-method>            <http-method>TRACE</http-method>            <http-method>DELETE</http-method>        </web-resource-collection>        <auth-constraint>            <description/>            <role-name>ADMINISTRATORS</role-name>            </auth-constraint>        </security-constraint>    <login-config>        <auth-method>BASIC</auth-method>        <realm-name>userauth</realm-name>        </login-config>    <security-role>        <description/>        <role-name>USERS</role-name>    </security-role>    <security-role>        <description/>        <role-name>ADMINISTRATORS</role-name>    </security-role>    </web-app>I have 2 roles named "ADMINISTRATORS" and "USERS".  I use these same names as the groupid values in the database table.  This makes the role-mapping a bit easier because you use the exact same name on both ends.You must setup the roll-mapping in sun-web.xml  The easiest way to do it so directly edit the file and add these lines:  <security-role-mapping>    <role-name>USERS</role-name>    <group-name>USERS</group-name>  </security-role-mapping>  <security-role-mapping>    <role-name>ADMINISTRATORS</role-name>    <group-name>ADMINISTRATORS</group-name>  </security-role-mapping>   Build and deploy this web module and then run it.  It will ask you for authentication info.  If you enter "admin" "admin" you should be allowed in to see the jsp page.If you enter the name and password for someone that does not belong to the group "ADMINISTRATORS" then you will get an access violation error.If there is interest, I'll follow up with some tools you can use to add users dynamically and to manage the database itself.

Here is another good blog on this subject. In my last blog I showed you how to make a jdbc-resource that you can use for accessing a database. Now I'll explain how to use that jdbc-resource to setup...

Personal

Mort Learns JDBC for Glassfish

 I was intrigued by a problem and I set about solving it.  I finally did solve it.  It was a long difficult trail, but now that I know how to  do it it seems fairly easy.If you are interested in Glassfish, JDBC, authentication and/or realms then read on.The Problem:  I now have 3 home made web modules doing useful things.  They all have authorization and authentication using file-based authentication.  That works fine but what if I want to add a new user?  It means I have to get the information and then create the right command to get the information into the key-file.  Or I figure out how to call Glassfish and have it put the username and password in for me.  Also -- what if I want the user's email address?  I can't put it in the key-file.  What about deleting a user?  Uh-oh.  Sounds complicated.  Plus I'm going to have to have some other data storage for the other user info.  I might as well use a real database -- the database gives me an easy way to add/edit/delete users at runtime (allowing users to create their own account unattended).  The database solves the problem of where to put the extra user info as well.The Solution:  Switch to JDBC Realm AuthenticationThe Trail Using JDBC and JavaDB in GlassFish is easy.  You can go from no DB at all to a formed DB ready for your first SQL commands in 10 minutes or less.There are a few traps waiting along for the unwary and I'll reveal them along with some tips. JavaDB Essential Information JavaDB is based on Derby.  A JavaDB database appears as a directory.  The directory's name is the database name.  When JavaDB opens up a database, that's it -- no other JavaDB runtime is now allowed to connect to that database.  Tip: If you have connection problems look in the directory where the database is supposed to be.  Is it there? If you use an embedded JavaDB database then what happens is that GlassFish itself is the JavaDB runtime that has that database locked.  As a result you can NOT look at the database anywhere else like, e.g. a SQL command processor.  If you want to issue SQL commands that way, you have to take down GlassFish to be able to access the database.  That's a disadvantage.  The advantages are it is super-secure since there are no ports open for accessing the database.  GlassFish is in charge of  security for accessing the databaseIt is simpler to setup than the networked client The other choice is using the Derby Network Server.  This is just the classic client server database setup.  Derby runs one network server instance which is the "owner" of the databases embedded into it.  You can work on this database via SQL tools while GlassFish is connected to it.  It's not as simple.  You have to separately start and stop the JavaDB server.  GlassFish makes this easy for you with an asadmin command.  asadmin takes care of all the details -- environmental variables, classpath, etc.I recommend the Network client mode.  It's no big deal, it's just another command that you use before starting GlassFish.  I figured out a way to make it a service in Windows as well (perhaps a future blog?)Note: You can easily change an embedded client or a network client back and forth. asadmin start-database -- dbhome <path-to-database-parent-dir>Here's the first trap.  You don't have to specify the --dbhome option but I highly recommend always using it.  Short Primer on Where the Heck is My Database on Disk?!?If you run a stand-alone java program that uses embedded JavaDB, and you tell it to open a database named "foo", it will look for a directory named "foo" in the directory you ran the program from.   If you start a networked server -- it's the same deal, it will look in the directory that you started the server in.  GlassFish determines the all-important location of your databases on disk as follows and in this orderuse the --dbhome path as the root of all the databases  Done!else look in the current directory if there is a file named "derby.log" then make the current directory the root.else use a standard location:  <gf>/databasesIf you don't use the --dbhome option then you need to be aware of whether or not derby.log is in your current directory. Let's Get This JDBC Party Started AlreadyYou need to create two items in Glassfish in order to access a database.The first is a JDBC Connection Pool.In the Admin GUI navigate to Resources/JDBC/Connection PoolSet the easy stuff.  Note that "name" is the name of the pool.  This pool is for a network client.  The configuration is a bit different for embedded databases.  I have pictures at the end of this blog for the embedded case.Here is the first page of mysterious properties.  If you are an experienced DB person you'll know what to do.  If you're like me you'll happily take the defaults.  This is where all the action is.  You don't want to make any mistakes here.  Here is the default layout:And here is what it should look like.Note that DataSource has no value.Tip: set connectionAttributes to ";create=true".  Now you can make GlassFish create the database for you!  And here is the new Connection Pool.  Click on it and then press the ping button and the (empty) database will be created. The next step is to create a JDBC Resource.  Armed with this jndi name you can get a connection to the database at runtime.Navigate to Resources/JDBC/JDBC Resources and press the "new" button.  That's all.  Glassfish is ready to serve up database connections.  From a servlet this code will do the job:             InitialContext ctx = new InitialContext();            DataSource ds = (DataSource) ctx.lookup("jdbc/userauth");            Connection connection = ds.getConnection();

 I was intrigued by a problem and I set about solving it.  I finally did solve it.  It was a long difficult trail, but now that I know how to  do it it seems fairly easy. If you are interested in...

Sun

Monitored System.setProperty

System.setProperty() can be an evil call.  It is 100% thread-hostileIt contains super-global variablesGF is very heavily dependent on these variablesIt is extremely difficult to debug when these variables mysteriously change at runtimeI added a super-simple class to Glassfish that wraps System.setProperty() and System.setProperties().The class is named GFSystem.  It is an all-static class and it lives in appserv-commons. If you always call the wrapper instead of the JDK method you get the following services:Every call is logged - by default the Level is FINE but it can be changed with a method callYou have a place to set a breakpoint when debugging a mysterious System Property bug Example code: import com.sun.enterprise.util.system.GFSystem .....GFSystem.setProperty("com.sun.aas.instanceRoot", "/somewhere"); -- The class is pretty tiny so I added it below.In answer to Kedar's comment -- by default it is set to FINE level to keep the noise down.To set it to, say, INFO you do this:GFSystem.setLevel(Level.INFO); -- to reset to the default level:GFSystem.resetLevel(); note that setLevel() is not synchronized because it would be pointless... /\* \* GFSystem.java \* \* Created on August 21, 2007, 11:37 AM \* \* To change this template, choose Tools | Template Manager \* and open the template in the editor. \*/package com.sun.enterprise.util.system;import com.sun.enterprise.util.\*;import com.sun.logging.\*;import java.util.\*;import java.util.logging.\*;/\*\* \* This is a simple class that wraps evil calls to System.setProperty. System.setProperty \* is evil because it's very hard to debug, it's thread-unsafe, it's super-global and it is \* over-used in GF. \* To use it -- simply call GFSystem.setProperty() instead of System.setProperty() \* To debug -- you can turn up the logging level with setLevel() and restore with resetLevel() \* @author bnevins \*/public class GFSystem{ private GFSystem() { } public static void setProperty(String name, String value) { System.setProperty(name, value); log(stringy.get("set.property", name, value)); //SystemPropertyConstants.INSTANCE_ROOT_PROPERTY; } public static void setProperties(Properties props) { System.setProperties(props); log(stringy.get("set.properties", props)); } public static void setLevel(Level newLevel) { level = newLevel; } public static void resetLevel() { level = DEFAULT_LEVEL; } private static void log(String s) { if(logger.isLoggable(level)) logger.log(level, s); } private static final Logger logger = LogDomains.getLogger(LogDomains.UTIL_LOGGER); private static final Level DEFAULT_LEVEL = Level.FINE; private static Level level = DEFAULT_LEVEL; private static final LocalStringsImpl stringy = new LocalStringsImpl(GFSystem.class);}

System.setProperty() can be an evil call.  It is 100% thread-hostile It contains super-global variables GF is very heavily dependent on these variables It is extremely difficult to debug when these...

Sun

Chapter 1 - A Standalone Dean Edell Downloader

This chapter can be downloaded here. This zip file has the entire Chapter1 NetBeans project in it. I highly recommend using NetBeans 5.51 for this tutorial.And of course you are going to need GlassFishThe first thing that we need to get working is the automatic downloading of the Dean Edell mp3 files. We're going to make a simple stand-alone Java SE application to do the downloading. We will then create a simple script to run the java application. After testing it to make sure all is well we'll get the operating system to call it every Monday through Friday night at 11:30 PM PDT.The Java Technology Portion The source consists of two files:HTTPDownloader.javaA simple class that takes a URL string and a filename string. It fetches the file that the URL is pointing to and writes it to the filename. This is where Jaca Technology really pays off. It's ridiculously easy to do.DeanEdellDownloader.javaThis class is also pretty simple. The most difficult part is assembling a distinctive filename based on the date. DeanEdellDownloader uses HTTPDownloader to fetch the current Dean Edell mp3 file. It refuses to run on weekends. The URL and the location to write the mp3 files is hard-coded here. That's OK in this scenario because we are going to build it once and forget about it.You will need to change the value of one variable in DeanEdellDownloader. The last line of the file contains the target directory from my GlassFish installation. Replace it with your path: private final static String DEFAULT_DIR_HTTP = "C:/as/domains/domain1/docroot/DeanEdellFiles";The Script NetBeans automatically put a manifest file pointing to the correct main in the jar file. On my Windows system I put a script in DeanEdell.bat in a scripts directory. The command in the script is: java -jar path-of-jar-fileRun the script. A 10.5 MB mp3 file should appear in [domain]/docroot/DeanEdellFiles (unless it is the weekend!)Calling the Script Automatically Forever If you are on UNIX or Linux you are on your own here. You need to create a chron job that runs the script Monday through Friday around 11:30 PM PDT. It's OK to run it on weekends too -- it won't do anything. On Windows this is super easy to do: Go to Control Panel and then run Scheduled Tasks. It will take you by the hand and guide you in making a chron job. Just have it call the batch file every Monday through Friday around 11:30 PM PDT. Make sure you enter your account password. And that's all there is to Chapter 1. We now have DeanEdell mp3's appearing automatically in a folder under docroot inour domain.Next Installment: Chapter 2 - Create a Web Application to serve up the files

This chapter can be downloaded here. This zip file has the entire Chapter1 NetBeans project in it. I highly recommend using NetBeans 5.51 for this tutorial. And of course you are going to need GlassFis...

Sun

Let's Get This Glassfish Party Going!

This is the first chapter in a n-chapter tutorial on how to exploit Glassfish capabilities. I learned long ago that the only way I can really cement into my head a hunk of technology is to just do it. I came up with a useful application for web technology. In this series we will be building an application that will slowly but surely use these areas of javaee. They are in the approximate order that we will tackle in the project.HTTP File downloading (HyperText Transfer Protocol)ServletsJSPs (Java Server Pages)User Authentication - Basic, then File Realms, then JDBC RealmsDerby DatabaseJNI (Java Naming Interface)EJB 3.0 (Enterprise Java Beans)JPA (Java Persistence API)EJB Timer ServiceStruts JSP Tag LibrariesMDB (Message Driven Beans) Chapter 0: The Application Description Dr. Dean Edell has an interesting radio talk show on KGO radio in San Francisco. His show is from 1 to 2 PM Monday through Friday. KGO posts an mp3 file for the show once a day. KGO takes it down, forever, after 24 hours. KGO does not maintain an archive of old shows. I like to burn the shows onto CDs and listen to them in my car. What this application will do is:Automatically download the mp3 at 11:38 PM every night, Monday through Friday and save them to a subdirectory of docroot on my Glassfish Application Server.Maintain user accounts for people that wish to download the files. New accounts will be accepted and added to the list on demand.The application will persist which files have been downloaded for each user. When a user is authenticated he will see his own custom list of programs he has yet to download.A list of all available programs will also be available in case of trouble (like the dog eating the Dean Edell CDs)This sounds like a lot of overkill for such modest sounding requirements. But making it 100% automatic is a bit challenging. Besides, the whole point of this is to create an application - any application -- in order to learn how to do all this stuff. We will start simple but thorough and correct. We will constantly change and modify it to use the cutting edge Java EE technology as the tutorial progresses. Stay Tuned for the next installment, Chapter 1: Write a stand alone Java application that will download the mp3 file. The OS will be in charge of running this application via a chron/at job.

This is the first chapter in a n-chapter tutorial on how to exploit Glassfish capabilities. I learned long ago that the only way I can reallycement into my head a hunk of technology is to just do it....

Sun

Start and Stop Scripts

A little known fact: there are scripts for starting and stopping the 3 different kinds of Glassfish servers. The three kinds of servers are:Domain Administration Server (the only server available in a development profile)Node Agent ServerInstance ServerThese scripts have always been there but were never officially supported.  They were difficult to use.  E.g. you had to know to type in username, password and master password into the void at the command window for strtserv to work.  The scripts were used internally in pre-V2 versions.  They are not used at all in V2.  They are there for your use exclusively now.Where Are These Scripts?They are named:   Start Script Stop Script Windows startserv.bat stopserv.bat Not Windows startserv stopserv In my own personal default environment, they are here: Domain Administration Serverc:/as/domains/domain1/binNode Agent Serverc:/as/nodeagents/na/agent/binInstance Serverc:/as/nodeagents/na/i1/bin   How Do I Use Them?To start a server run the appropriate startserv script.  It will ask you for the administrator's username, pssword and the master password.  If you don't know what a master password is -- just enter changeit.  This is not really needed for the Domain Administration Server in a developer profile, but the script does not yet have the smarts to know whether or not the server is secure.  A future release may fix this problem. To stop a server simply run the stopserv script.  No authentiction information is needed or asked for. Features The scripts are relocatable.  I.e., if you use asadmin backup-domain and asadmin restore-domain to clone a domain to a different location -- the scripts will still work.Shutdown is very fast and efficient.This is the only way you can start an instance with no running Domain Administration Server and no running Node Agent Server.You can take over the lifecycle management of one or more Instance Servers.  If you start the Instance Server with the script then the Node Agent Server will not automatically stop it when the Node Agent Server is stopped.

A little known fact: there are scripts for starting and stopping the 3 different kinds of Glassfish servers. The three kinds of servers are: Domain Administration Server (the only server available in...

Sun

Glassfish: Great AppServer or Greatest AppServer?

Fish for a Flat Screen TVBlog about GlassFish for a chance to win a 52" LCD HD TV.» MoreI'm a developer for Glassfish.  My area is Administration.  I am also a glassfish user.  I have a real-world web site that's been running continuously for 2 yearsNow when I try to do something in a different area of the Appserver like Web Applications, I'm just as much of a helpless newbie as anyone else.I developed a semi-cool way to publish lots and lots of pictures on my website with little manual intervention.  It works great.  One day I downloaded a ton of pictures  from my camera to the website.  I put the "magic URL" that causes a servlet to layout the pictures in a URL which worked fine.  When you click on any of these small pictures it displays  a large version of the picture.  But, wait!  I''d click and instead of seeing a picture, I'd get a download dialog from Firefox!  After looking around on the filesystem I located the problem.  The camera saves the pictures with an extension of JPG while all of my other pictures had an extension of jpg.I posted a comment about it. Jan Luehe (super web-server guru) saw it, figured out the problem right away and filed a bug.  the bug was fixed in the very next build of glassfish.  Now that's service!So -- Glassfish is fast, reliable, free, it has great clustering capability, it's open-source and there are very smart knowledgeable people listening in on all the posts and ready to jump into action to help you.  What else do you need?!?This is why Glassfish gets my vote as World's Greatest Appserver. _uacct = "UA-1764433-1";urchinTracker();

Fish for a Flat Screen TV Blog about GlassFish for a chance to win a 52" LCD HD TV. » More I'm a developer for Glassfish.  My area is Administration.  I am also a glassfish user.  I have a real-world web...

Sun

Tip #-3 How to Debug Clustered AppServer Instances

There used to be a big problem in trying to attach a debugger to a clustered server instance in Glassfish.  As of today (build 45), it is a snap to do it! The problem was that a cluster config could only specify one debugging port.  This would work if you started one and only one server instance.  As soon as you tried to start a second instance it would try to use the same jdwp port and it would fail to launch.  It was (almost) impossible to debug 2 instances on the same machine at the same time. The solution is to defer the actual port number selection.  I.e. the instance needs to choose its own port.  Each instance specifies a different port and, voila, problem solved. Here is how to do it: 1. Enable debugging support for the cluster We are using a cluster named c1.  First make sure that debugging is enabled for the cluster: asadmin set c1-config.java-config.debug-enabled=true 2. Set a variable debugging port The syntax is ugly.  Don't bother memorizing just do a get to see it, edit it and then do a set on the result like so:  asadmin get c1-config.java-config.debug-options c1-config.java-config.debug-options = -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9009asadmin set c1-config.java-config.debug-options="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=${DEBUG_PORT}" Don't forget the double quotes, and no spaces around the equals sign!  Another Tip:  asadmin get "\*" > afile is handy.  You can then grep for 'debug' in the file.  I use this technique all the time.  What human being wants to memorize this sort of crushing detail? 3. Set the instances' debugging ports  In this case we have 2 instances, i1 and i2.  We will make the debugging ports 11111 and 22222 respectively: GlassFish v2.x: asadmin set i1.system-property.DEBUG_PORT=11111 i1.system-property.DEBUG_PORT = 11111asadmin set i2.system-property.DEBUG_PORT=22222 i2.system-property.DEBUG_PORT = 22222 The above does NOT work in GlassFish 3.X.  Instead use the following commands: asadmin create-system-properties --target i1 DEBUG_PORT=11111asadmin create-system-properties --target i2 DEBUG_PORT=22222 That's it.  You're ready to debug multiple instances.

There used to be a big problem in trying to attach a debugger to a clustered server instance in Glassfish.  As of today (build 45), it is a snap to do it! The problem was that a cluster config could...

Sun

AppServer Launch Changes in 9.1

Appserver launching has changed significantly as of build 26. It is now far easier to understand and debug. In the beginning...Before build 26 of 9.1 all server launches involved running shell scripts in external processes. There were a number of reasons for doing this which aren't worth getting into. 4-7 processes were involved in both starting and stopping servers. Here is a simple diagram of how that workedLegend:pX == process #xss is the startserv scriptcli is asadminPL is ProcessLauncher class running in its own JVMAS is a DAS, NodeAgent or InstanceASL is appservLauncher, a "C" programASX is appserv, appservDAS, or appservAgent -- all "C" programsNon-Native Start or Stop:P1-cli ---> p2-ss ---> P3-PL ---> P4-ASNative Start or Stop:P1-cli ---> p2-ss ---> P3-ASL ---> P4-ASX ---> P5-ss --->P6-PL ---> P7-ASImagine how difficult this was to debug! One had to echo messages from the scripts to a file, add java debug arguments to the java invocations in the scripts, change the C-code to force it to break so a debugger could be attached, etc., etc. I.e. it was virtually impossible to debug the startup or shutdown end to end!9.1Non-Native Start or Stop:P1-cli ---> P2-ASNative Start or Stop:P1-cli ---> P2-ASL ---> P3-ASX ---> P4-ASasadmin no longer uses any scripts (i.e. startserv) to start and stop servers the startserv scripts are now fully functional and supported for use from a commandline the startserv scripts can get the username and passwords directly from the user Any server can be started from arbitrary java code directly (look in the startserv script to see how) The domains are completely relocatable to a different location on the same machine or to a different machine altogether. This automatically makes Appserver Backup and Restore more useful as well. Native launching is temporarily broken (set native launching to false in install-dir/config/asenv.bat or asenv.conf). It works fine on Windows though. Shutdown has been dramatically improved. It used to require between 2 and 6 external processes (for non-native and native respectively) to be started. Now it doesn't start any external processes so it is much faster. To compare new with old, set OLD_LAUNCHER=true in your OS environment. In this case, the scripts will run in multiple processes as before but the scripts are pointing at new code instead of old code. This only works for startup -- shutdown always uses new code.Performance CheckingProcedureI used ancient technology -- a stopwatch -- which is exactly the kind of time we want to measure. I.e. how long is the user sitting there looking at a blank screen. In the case of stopping a node agent it was so fast that I added code to do the timing internally in the java code. Notes:The table appears at the very end of this blog, I don't know why.All times are the average of at least 3 separate trials.The tests were performed on Solaris10-SparcThe domain startup became slower from build 19 to build 26 because of other modulesin AS. Look at the times between Build 26 and Build 26 with scripts. This compares the all-java startups with java and script startups in the same build.Observations and Conclusionsstop commands are dramatically fasterThe new startup shaves 1-2 seconds off the total time. This is much more obvious when you look at start-node-agent which is much more lightweight than DAS.The new code is much easier to understand and debug.Build 19Build 26Build 26 with Scriptstart-domain26.231.232.2stop-domain11.87.1NAstart-node-agent7.76.1NotDoneYetstop-node-agent5.90.82NotDoneYet

Appserver launching has changed significantly as of build 26. It is now far easier to understand and debug. In the beginning... Before build 26 of 9.1 all server launches involved running shell scripts...

Sun

Interesting Bug

I've been scratching my head over this bug for a LONG time and I finally nailed it down today. Here is the non-executive (i.e. wirehead) summary:I call an external process and parse the stdout that the process generates. I have dozens of such calls in the code. The other calls are relatively slow (seconds to minutes). This one is very fast -- it just returns a chunk of text with its version information.The bug is that the process returns an empty string instead of the expected 1000 bytes or so.Clues:The bug always appears on UNIX -- never on Windows.The bug never appears when stepping through the debuggerThe fact that the code worked perfectly in the debugger and always broke without the debugger was perplexing. And then I thought -- "what's the difference?". TIME!! When I'm stepping through the code it is like geological time passing as far as the code is concerned. So I added a 2 second sleep after calling the process but before reading the saved stdout. Instantly, the bug went away.So what must have been happening is that the process returned from the waitFor() but the threads that are reading the process's output and error streams didn't get the text yet. My final solution will probably be to put in a poll --while(myprocess.getStdout().length() == 0) ; // hang around a bitI came up with a much better fix. I already had this:process.waitFor()Two threads are running draining stdout and stderr. They eventually get a null back from the read's they are doing in a (blocking) loop, and they exit. So I just added these 2 lines:outThread.join();errThread.join();

I've been scratching my head over this bug for a LONG time and I finally nailed it down today. Here is the non-executive (i.e. wirehead) summary:I call an external process and parse the stdout that...

Sun

Bracing Opinions On Coding Style

I catch complaints, now and then, about my putting left braces on a line by themselves. I originally got this habit because my CS professor would give us 0% if we didn't do that religously! Now I have a hard time reading code because the braces don't line up. Furthermore, I keep seeing bizarre indenting which I think is a far more serious problem.IMHO we should allow the left braces to be on their own line, or not, depending on the taste of the programmer -- keeping in mind Bill Shannon's rule #0 about formatting (match the existing style). Here is an example of what I mean. This comes from the very beginning of the most public class we have in AppServer -- PELaunch if(args[0].trim().equals(STOP)) { // check if instance is already running if (isInstanceRunning()) { PEMain.shutdown(); return; } else { getLogger().log(Level.INFO, "instance.notRunning"); return; } }Why are the "return"s indented out? Why are two closing braces at the same level of indent (I see this constantly)I think the way I would formatted it is clearer: (let's not even go there about the else being pointless!). When you line up the braces this way you never have the odd "lined-up closing braces" appear because it would stick out like a sore thumb. if(args[0].trim().equals(STOP)) { // check if instance is already running if (isInstanceRunning()) { PEMain.shutdown(); return; } else { getLogger().log(Level.INFO, "instance.notRunning"); return; } }

I catch complaints, now and then, about my putting left braces on a line by themselves. I originally got this habit because my CS professor would give us 0% if we didn't do that religously! Now I have...