7

As part of a research I'm working on, I'm looking for public APIs that only work correctly when you apply a certain sequence of actions on them.

For example, the java.nio.channels.SocketChannel class, from the Java standard library, only works correctly with sequences such as open() -> connect() -> read() -> read() -> close(). A more complete demonstration if how it may be used may be represented in the following graph:

valid usage of SocketChannel

Additional examples of Java standard library APIs that require certain sequences are java.io.PrintStream (very similar to the one above) and java.util.Iterator (which requires a next() call between every two remove() calls, thus enforcing a certain sequence).

So, does you favorite API for doing X also behave that way? I would very much like to know about additional APIs that require a certain method sequence for correct usage; especially classes that are not part of the Java standard library. The more complex the sequence(s) required, the better.


Some APIs require a sequence that spans across multiple classes, for example:

X x = new X();
x.setup();
Y y = x.createNewY();
Z z = new Z(y);
z.doSomething();

These examples are also interesting, but I'm mostly looking for sequences that all appear in the same class.


EDIT added bounty for greater visibility. I'm sure many of you have encountered many APIs that will match this description - I would really appreciate some good examples.

12
  • 2
    If you're interested in this topic, The Pragmatic Programmer has a chapter on temporal coupling.
    – Nobody
    Nov 25, 2010 at 16:31
  • Your graph doesn't display in the latest version of Chrome Nov 25, 2010 at 16:39
  • @Martijn odd, it's just a png hosted on imgur... it should work on all browsers.
    – Oak
    Nov 25, 2010 at 16:40
  • @Oak Hmm, I'm not seeing it or a link to it. Nov 25, 2010 at 16:41
  • @Martijn: Eh? Works fine on my end
    – TheLQ
    Nov 25, 2010 at 16:53

8 Answers 8

6
+50

From the Spring framework

The Lifecycle interface forces the following action sequence:

start (isRunning)* stop

which is used in just about all the principal components that make up the framework. Fortunately, this lifecycle is managed by the container.

From the Hibernate framework

The Lifecycle interface supports the following action sequence:

(onDelete, onSave, onUpdate)* onLoad

From the Servlet API

My all-time favourite - the lifecycle of a servlet:

init service destroy

with service delegating to the doGet, doPost operations etc.

3

Maybe I'm misunderstanding, but would the following fit?

  • java.lang.Thread

    must call thread.start() before thread.stop()

  • InputStream and OutputStream

    should not call other methods after calling close()

1
  • You are not misunderstanding, that's the sort of thing I'm looking for - only, as I've said in the question, I would very much prefer classes outside the Java standard library. Also, the more complex the better!
    – Oak
    Nov 28, 2010 at 23:47
3

java.sql.ResultSet

contains operations which require a certain order:

move commands (absolute(int row) or next()),

read/write commands (getInt(int columnIndex) or updateInt(int columnIndex, int x)),

write-back-to-datasource commands (updateRow()),

release commands (close()).

1
  • As an added bonus to get at a ResultSet you need to go over several classes, beginning with: DataSource ds; Connection cn = ds.getConnection(); Statement st = cn.createStatement(); ResultSet rs = st.executeQuery(String query);
    – Ray
    Nov 29, 2010 at 11:35
2

An upcoming "best practice" to handle this problem in the initialization phase of objects in Java, is to use a Builder pattern which has a so-called builder on which the steps are taken, and then an object is requested built. If the steps are invalid, the builder fails.

From http://rwhansen.blogspot.com/2007/07/theres-builder-pattern-that-joshua.html:

Widget z = new Widget.Builder("3", 4.0).
                     manufacturer("333").
                     serialNumber("54321").build();

The Builder is a nested class to Widget, which then has methods called (returning the same builder object again) until the build() method is called, which creates and returns the Widget needed.

Can reduce complexity quite a bit.

2
  • What problem? I haven't mentioned any problems, I'm just looking for examples of complex, existing, sequence-requiring APIs.
    – Oak
    Nov 28, 2010 at 23:30
  • I'm not saying you have problems, but for complex classes this can get the "oh, we need another constructor with nine arguments" situation under control. Having many constructors each taking many arguments is a problem.
    – user1249
    Dec 1, 2010 at 6:22
2

What about the java.util.Calendar? It doesn't require a complcated action sequence, but it's a real PITA for the number of times you need to use it:

//1. get a new instance
Calendar cal=Calendar.getInstance();
//2. set the different fields
cal.set(Calendar.DATE, 12);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.YEAR, 1982);
//3. use it, for whatever
Date d=cal.getTime();

And, not to talk about the Java Transaction API, when Bean managed:

@Stateless
@TransactionManagement(BEAN)
public class ExampleBean {

    @Resource
    private SessionContext ctx;

    public void foo() {
        UserTransaction utx = ctx.getUserTransaction();

        // start a transaction
        utx.begin();

        // Do work

        // Commit it
        utx.commit();
    }
}

The JAXB marshalling

//1. get context
JAXBContext jc = JAXBContext.newInstance( Foo.class );
//2. create Marshaller instance
Marshaller m = jc.createMarshaller();
//3. set properties
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
  Boolean.TRUE);
//at last, marshall
m.marshal( foo, System.out );

and unmarshalling:

//1. get context
JAXBContext jc = JAXBContext.newInstance( Foo.class );
//2. create Unmarshaller instance
Unmarshaller u = jc.createUnmarshaller();
//3. optional: set properties, format validation, schema validation, etc
u.setValidating( true );
//4. unmarshall
Foo foo = (PurchaseOrder)u.unmarshal(
       new FileInputStream( "po.xml" ) );
1

The academic paper "ESP: path-sensitive program verification in polynomial time" includes examples for opening and closing files, in addition to verifying calls to fprintf. And the concept works with general FSMs, and this may be closer to what you are looking for.

The bonus is that the ESP system verifies that you actually obey these rules. Also related to this line of research is BLAST.

If you want requirements that are more explicit in the programming language, look into Foster's Flow-Sensitive Type Qualifiers. Which can be useful, for example, to check that a "tainted" string has been cleansed before being used in a SQL query.

Depending on the nature of your project, you should look into the classic push before a peek or a pop on a stack. I'm not sure how well the above approaches could handle that case, because counting the number of calls made is important.

2
  • Thank you; but I'm looking for actual, existing APIs, not papers that discuss how to analyze and/or verify them.
    – Oak
    Nov 28, 2010 at 23:31
  • @Oak: Please look deeper, I specify three APIs in my answer. Also, the papers could give you ideas. Perhaps you could explain your research project?
    – Macneil
    Nov 28, 2010 at 23:38
1

The C++ STL has a variety of rules about when iterators are invalidated. For example, adding an element to a vector may cause all the iterators into that vector to be invalidated.

Any container library must have special cases for empty containers.

I've dealt with a database api, IBPP, it required a ->Start() call to the transaction object, before creating any statements associated with the transaction. Eventually you would call ->Commit(); (or ->Rollback() if things didn't go well) Other APIs are similar, but probably a bit more complex because of issues such as autocommit.

I've certainly dealt with internal code that acted that way. However, I considered that a bug.

The pygame module in python requires that call .init() and then .display.set_mode() to setup a graphics mode.

Everything I can think of has relatively trivial versions of this. I can't think of any cases that has a really complex version like you really want.

1
  • Yes, I guess it's not easy to find - that's why I asked it here with a large audience. Also, I'm specifically looking for Java APIs, but looking for database APIs does look like a good idea.
    – Oak
    Nov 29, 2010 at 9:09
0

Like parsing an XML document?

DocumentBuilderFactory dbf = DocumentBuilderFactory.getInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new File("file.xml"));

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.