Fog Creek Software
Discussion Board




Not quite a singleton but...

I have an object that deals with a directory on disk.  Each object deals with one specific directory and each directory has a unique name that is a sequence of numbers.  I need to assure that at any given time, only one object exists in memory (in a J2EE app server but I don't think that should alter the answer) for any given directory, i.e. if more than one client needs access to the given directory, it should share the existing instance of the object that works with that particular directory.

Is there a name for this pattern?  I have implemented it using a static Hashtable and a synchronized clause for accessing that.  I was wondering if anyone knew a more elegant way.

name withheld out of cowardice
Wednesday, July 21, 2004

I would have used the same solution, but I'm interested to know if there's some other method.

muppet
Wednesday, July 21, 2004


I've done the same thing with loading rather large XML files across a network.

I believe this is the point of a Singleton.  I don't see where it significantly departs from that Pattern.

KC
Wednesday, July 21, 2004

It departs from a singleton because a singleton is when you want only a single instance of a class at any given time.  In this case you need many instances of this class at any given time but no two should be for the same directory.

BTW- I should also mention that I need to know when the instance for a given directory is no longer needed bacause the instance should be removed and some cleanup in the directory done.

name withheld out of cowardice
Wednesday, July 21, 2004

Could you modify the object's constructor to count it's instances and create a new object (and return that) if none exist, or return the existing object.

Perhaps
Wednesday, July 21, 2004

If you need another fancy pattern name, you'd use a "factory" to obtain your instances.
-tim

a2800276
Wednesday, July 21, 2004

I could use a factory pattern, or use the constructor to assure that only one instance for the given directory is created, but that just puts the hashtable in a different place.  It is now accessed within the factory method or constructor.  That's fine of course but is basically the way I am doing it now. 

name withheld out of cowardice
Wednesday, July 21, 2004

Single-parameter-keyed-cached-class-factory-with-a-modified-singleton-pattern?

Dennis Forbes
Wednesday, July 21, 2004

I would call this pattern a symbol table with the directory name as the key for lookup. Probably the lookup would be done with a hash but by looking at the underlying pattern as a symbol table instead of a hash its now abstracted from implementation. I don't see how sigleton fits into any of this - I'd stop using theat term altogether.

Dennis Atkins
Wednesday, July 21, 2004


So it's a Factory that implements a set of Singletons?

Singleton Set Factory (c)


Now, if any of you want to use this phrase, send me large sums of money.

In fact, whether you use the phrase or not, you can send me large sums of money.  I won't even bother you by sending it back.

KC
Wednesday, July 21, 2004

A singleton class containing a map to your directory entries. Each time you add a new directory, you check it already exists in the map, in which case you throw a checked exception.

Since you are running inside a J2EE container, it may be tempting to create an Entity Bean per directory. Don't do that; it's the fine grained entity bean anti-pattern.

Dino
Wednesday, July 21, 2004

More ... clustering: you load the singleton/map from a database or file or whatever. Then you have to figure out how much consistency is required accross the cluster.

If you have to be 100% consistent, you'll need to mark dirty all entries which are out of sync with your datastore and re-read them on the next access.

If your data changes a lot, you may want to re-think the entire problem again.

Dino
Wednesday, July 21, 2004

Dino-

So would you use a Stateful Session bean instead?  What would be the advantage?

Also, why have a singleton class contain the map?  Why not just make the map static and put it in a factory method of a plain ole java class?

Dennis Atkins- I agree, it is not a Singleton but I felt it helped the explanation.

It seems to me that most people are arriving at a similar solution, with discusson revolving around where to put the table (Hash or otherwise)

name withheld out of cowardice
Wednesday, July 21, 2004

Depends how you use the map.

If the map is internal to one of your classes, sure, make it static and that's pretty much the end of the story.

However, if the map in fact provides some sort of directory service you are better off with creating an interface for the service then implementing the interface with a singleton around your static map. In other words, hide all the internals behind an interface.

Since J2EE containers don't provide any support for singeltons, you have 3 choices:
1) Stateful beans.
2) Entity beans/BMP.
3) Roll your own. You will have to use synchronized and static inside the container - which may be a tricky thing to do.

Entity beans may be right choice :-/ since you are dealing with a shared object.

Dino
Wednesday, July 21, 2004

I don't see anything wrong with what you're doing, though I might be expected to say that as I've done it (and seen it done) quite a bit.

The pattern is called "Global Data".  Because that's what static data is.  :)

I'm unclear as to what you consider inelegant about this mechanism...?

Should be working
Wednesday, July 21, 2004

Since the original poster mentioned he's working in J2EE, and nobody seemed to be shocked outright from the question, you all might wish to know that communicating between EJBs through static data is wrong.  Sure, you can get away with it in most containers, but you're ignoring the underlying programming model, so when it bites you in the butt...

(See EJB spec.  C.1.2 Programming restrictions)

Murray
Wednesday, July 21, 2004

Murray:

You are quite right and it is one of the reasons I was asking about another method in the first place.

As for why I think it is inelegant, I don't necessarily.  It just seemed to me that a Hashtable is more the brute force way of keeping track of things.  I thought maybe there was a solution so simple I would exclaim "duh!" and slap my forehead.

Fortunately for me I don't need to cluster so this solution will probably work but what if I wanted to avoid the static variable (and synchronization too BTW.  We are supposed to let the container handle threading for us).

name withheld out of cowardice
Wednesday, July 21, 2004

This is still the Singleton pattern. You just have a registry of Singletons. It's in the book, no?

Thom Lawrence
Wednesday, July 21, 2004

Murray is right: the static and synchronized are forbidden by the specs. One can still use them ... but like I said, it could get tricky.

In this particular case, using an Entity bean as a singleton makes it ok to use a non-static map.

Dino
Wednesday, July 21, 2004

I think an important presumption of the EJB model is that the bean programmers will be using something like a relational database to handle the stuff that's too complicated for your average I.T. shop business application programmer.  So you're restricted to a subset of possibility that almost anybody can handle, but that's both a benefit and a problem.  And unfortunately you're expected to rely on discipline to stay away from the disallowed stuff, which is an unlikely mechanism to enforce the presumption.

I forgot to mention earlier that an EJB is also not allowed to work with files.  (The original poster knows about the restrictions already, so I add that as a general comment.)

If you want to do something complicated that lies outside the range of what a bean is allowed to do, J2EE has the Connector facility (JCA).  Essentially, it's like writing your own stripped down JDBC driver, minus the purely database things of JDBC.  That means you must manage your own deadlock detection if deadlock is a possibility, and any other potentially complicated resource management things that a database and application server combination usually takes care of for you.

A JCA Connector will let you do these things legally, but you're still facing the same essential design struggles of the original post.  At least the Connector will move you from implicit classloader-based context and discovery to explicit JNDI-based context and discovery.  If all your operations on these "directory" objects are atomic, deadlock is not likely.  The exclusivity you want is not true for a cluster, but you say you don't need a cluster.  Going to the bother of a Connector is a more complex arrangement than a sane person would hope for, but another potential advantage is that you're moving the possibly dangerous stuff into a region that lower-skilled people might be less inclined to muck with.

Murray
Wednesday, July 21, 2004

To answer the original question, this is most certainly still a Singleton, depending on how it's coded.

I remember quite clearly from the blue GOF book that the Singleton interface was defined thusly:

public Something GetInstance()
{
  // wherein you decide whether to return a "single"
  // instance everytime, or from a pool, or whatever.
}

Usually it's the single, but the book is explicit about using a method instead of a field or whatever so that you could control creation.

But they all overlap so much it's pointless to try and figure it out. It can just as easily be viewed as Factory or FlyWeight for that matter.

I'm curious about the restrictions in J2EE. Are you saying that the following is illegal?

public class DirectoryThing
{
  private static HashMap cache = new HashMap().Synchronized; (or however it's done in Java, can't remember)

  protected DirectoryThing(filename)
  {

  }

  public static DirectoryThing GetDirectoryThing(string filename)
  {
    synchronized (cache)
    {
      DirectoryThing thing = (DirectoryThing)cache[filename];

      if (null == thing)
        cache[filename] = thing = new DirectoryThing(filename);

      return thing;
    }
  }
}

Sorry if that code is all wrong, I've never been a professional java programmer. But you get the jist of the question. Is that dissallowed? I use that pattern all the time in .Net.

funky
Thursday, July 22, 2004

I'm not sure "Illegal" is quite the word for it.  I must admit I haven't read the specs (I really admire people who can stand to read specs) but in leanring EJBs all the books say you "shouldn't" or "aren't supposed to" or "don't" use static members and write the code in each bean as single threaded allowing the container to handle those issues for you.

The thing is, the container can't really stop you from doing these things.  It just assumes you aren't and if you are, some things might not work.  It seems to me that these things would mostly be issues when you have more than one container running.

The thing about EJBs not accessing files I am less sure of.  I think this might be a best practice rather than a restricion in the spec.  The poster obviously means that an EJB isn't supposed to access the file system directly because in interacting with a database, it is working with files.

I am actually using BerkeleyDb Java Edition.  This doesn't have a JDBC or other type of connector so it is pretty much direct file access.  In my particular app I am really only using EJBs as ways to implement RMI (I am not using their fancier aspects like transactions) so what I am doing is pretty safe.  The poster who raised these other issues is correct in most cases.

To those who say this still counts as a singleton, fine we have a name but is there a better way to implement it in Java and in EJBs specifically?

name withheld out of cowardice
Thursday, July 22, 2004

"The thing about EJBs not accessing files I am less sure of.  I think this might be a best practice rather than a restricion in the spec."

Wrong.  Go take 5 minutes and read the restrictions section in appendix C.  Jeez.

"The poster obviously means that an EJB isn't supposed to access the file system directly because in interacting with a database, it is working with files."

No it's not, it's talking to a database server through a supported interface.  What that server does on the other end with files is irrelevant.  If you're using a direct-file-writing library, you're breaking the rules, whether you do it directly or through a library of code.

Maybe you can try to break these rules, and discover that the container will not stop you.  That doesn't make it a good idea.  (By the way, yes it can stop you if it wants to.  Most don't.)  But if you're ++basing++ an application architecture on breaking these rules, you deserve all the pain you might suffer down the road.  The bean writer rules are not arbitrary.  They're there to give the container vendors broad space to write innovative implementations and solve serious scaling and reliability issues for enterprise applications.

Calabria
Thursday, July 22, 2004

Calabria,

I don't know of any server that does not manipulate files, does not listenes to sockets, does not use static nor synchronized, ... And I worked on quite a few by now.

Doesn't look using the recommended JCA solution like an overkill and disproportionate for the given problem?

If the specs say jump, I'll jump all right, but before I do that I need to understand the reason why; maybe I'll find a better/reasonable way to do the same thing.

In this case I suspect the specs try to prevent us from blocking server threads from within our code.

Dino
Thursday, July 22, 2004

Calabria:

Fine it is a restriction.  My apologies for exasperating you by not having read section C.  You are much cooler than I.  A little unsolicited advice on how not to come off as a dick in the future- "geez" was unecessary.

As for databases working with files, I think you are on the worng side of a semantic argument.  Any database you use stores its information in files.  If you interact with a database, even via a JDBC driver you are "working with files".  The issue is that an EJB isn't allowed to open a file.

I suppose you are correct that the proper way to accomplish my goal is to wirte a supported interface.  I may do that someday if the rest of the project is successful.

Congratulations on having read the spec.  I hope it helps you through your day.

name withheld out of cowardice
Thursday, July 22, 2004

Well I ++am++ a dick in some ways, so if I come off that way I deserve it.  One way I'm dickish is I'm harsh and a little demanding.  That causes the evil of hurt feelings and sometimes (almost never) the dismissal of somebody from a team.

One of the ways I'm not dickish, is that I make good effort to understand the tools I'm using, and use them right when I know how.  So a dickishness I'm missing is a kind that causes the evil of making other people suffer for months cleaning up messes after I'm gone.

Reading the spec doesn't make me cool or superior.  It also doesn't just help me through my day.  Knowing the basic restrictions and rules, and following them the best I can rather than rationalizing my choices is the least I owe to the people around me and the people who have to maintain my stuff later.  It helps them through ++their++ days.  Some poster above gave you a shortcut to the few pages you need, to know what is very wrong with your application.  My unsolicited advice is to take five minutes to pay back his kindness before responding with wrong assumptions it would clear up, and maybe avoid confusing other readers with those assumptions.  It's three pages.

You are not "working with files" when you use a database.  Another server works with files, almost always in another process, usually on another box, and usually not even in java land.  So that file work is not relevant to the restriction.

If it helps, think of it this way.  The thread running through your EJB must never call anything that writes to a file, except objects that the application server gives you, so the application server will get a good chance to know you're doing that.  All the other restrictions you can think of in the same way.

Calabria
Thursday, July 22, 2004

Man. What I wouldn't give to talk to some of Calabria's ex-clients and ex-coworkers.

disbeliever
Friday, July 23, 2004

Geez, no wonder EJB systems are such a mess.

The whole point of EJB is the specs.  If you think of the spec as being suggestions only then you are wasting your time.

This is the difference between EJB the technical solution and EJB the requirement imposed by management.

EJB the technical solution are used by those who read and understand the specs.  The following these specs closely they gain the benefits.

EJB the requirement imposed by management is used by programmers where the managments say 'we are using J2EE' so it is necessary to keep up the appearance of writing EJBs while really just carrying on writing code as you did before.

believer
Friday, July 23, 2004

Calabria:

You may decide, arbitrarily, that because the files are on another box you are not "working with them".  This is quite wrong.  You are confusing the point I was making , that databases work with files and therefore if you are working with databases you are working with files, with a conclusion I never posited, which is "therefore JDBC violates the EJB standard"

Anyway, at your urging I went to the EJB spec (my mistake, I first looked for this in the J2EE spec).  I thank thank you for urging me to so do because I am now convinced there is no problem with what I am doing.  As I stated before, I am not using EJBs for all their power.  I am just using them, in a sense, to handle RMI for me.  I just need to access some remote objects to write some data to a JE directory.  For this task, I see no problem in the restrictions in the spec, as long as I can assure that I am working with a single VM instance.  This places a slight restriction on poratbility but I currently know of no App server I would use that uses multiple VM instances on the same machine.

Inserted for everyone's viewing pleasure:


25.1.2 Programming Restrictions
This section describes the programming restrictions that a Bean Provider must follow to ensure that the
enterprise bean is portable and can be deployed in any compliant EJB 2.1 container. The restrictions
apply to the implementation of the business methods. Section 25.2, which describes the container’s
view of these restrictions, defines the programming environment that all EJB containers must provide.

• An enterprise bean must not use read/write static fields. Using read-only static fields is
allowed. Therefore, it is recommended that all static fields in the enterprise bean class be
declared as final.
This rule is required to ensure consistent runtime semantics because while some EJB containers may
use a single JVM to execute all enterprise bean’s instances, others may distribute the instances across
multiple JVMs.

• An enterprise bean must not use thread synchronization primitives to synchronize execution of
multiple instances.
This is for the same reason as above. Synchronization would not work if the EJB container distributed
enterprise bean’s instances across multiple JVMs.
[57] See [9] for restrictions.

Bean Provider’s Responsibilities Enterprise JavaBeans 2.1, Final Release Runtime Environment
563 11/12/03
• An enterprise bean must not use the java.io package to attempt to access files and directories
in the file system.
The file system APIs are not well-suited for business components to access data. Business components
should use a resource manager API, such as JDBC, to store data.le descriptor.


As you can see, it says files are not well suited and you should use JDBC.  It doesn't say you have to and the security settings specified for the latest J2EE allow read and write access to the file system.

So there it is.  I agree witrh you if I were writing a normal EJB application but, thinking outside the box a bit, and understanding how Java works, what I am doing will work just fien and solves many problems for me.

name withheld out of cowardice
Friday, July 23, 2004

Believer:

I am not using EJB just to say I am useing EJB.  I need RMI and I need a little asynchronous messaging on my server.  I am not writing an EJB with the intent that other people could use it on their projects.

What is wrong with using a container as a shortcut to an RMI server instead of writing a strict EJB application (which doesn't even really fit what I am doing)

name withheld out of cowardice
Friday, July 23, 2004

*  Recent Topics

*  Fog Creek Home