[long] Why building Spindle is hard Pt.5

Geoff Longman <[email protected]> Mon, 13 Feb 2006 23:32:09 -0500
Newsgroups gmane.comp.ide.eclipse.spindle.devel
Message-ID <[email protected]>
A note: Perhaps this one is not as coherent as the previous ones. It's
because the problems are starting to pile up in combination and I'm
getting frustrated (again).


In Pt.4 I was talking about the SECOND THING (PROBLEM) that makes
building spindle hard. That problem was the fact that in Tapestry 4,
unlike it predecessors, a component id is a path rather than a simple
identifier.


[One might wonder why I've just been referring to components and not
pages w/respect to the SECOND THING? The discussion for pages would be
similar but a bit more complex as there are more "lookup rules" for
pages. Figured it would be better to stick to the simpler case]

Anywho, I made this wild statement in the last message:

"(having multiple names for a component)..is not really an "aliasing"
as Tapestry does not recognize these 3 possible namings as the same
component. It installs a new entry in the
namespace whenever a new component is reference even though they are
the same component."

Well, that's partly true and partly false. It is possible that one,
two, or all of these namings refer to the same component. They all
refer to the same .jwc file, but behind the scenes another feature new
to Tapestry 4 make it possible that one or all of these namings really
refer to unique components.

And that's the THIRD THING (PROBLEM) that makes building tools for
Tapestry 4 hard.

To begin we have to review exactly what makes a component a unique
entity in Tapestry.

A component has:

A name (/a/path/to/MyComponent) which is needed so that other
pages/components can refer to (ie use it).
A component java class - the "go to it" guy.
A Specification Object (xml file)- the blueprint needed to instantiate
and insert the component into a pages tree of components.
And, sometimes, it has a Template

If any of these change, (except sometimes the name as we saw in Pt.4)
then it's really not the same component.

[In the general discussion a lot is made of how some or all of these
are *optional*. In truth, except for the template, they are all
*required* at runtime. The *optional* part is possible as the Tapestry
implementation will provide any missing pieces at runtime]

The way Tapestry chooses to provide one *optional* piece, the
component class, when it is not explicitly defined by a Tapestry
developer is the THIRD THING. Obtaining a page class also falls into
this category - we will examine the page class case later - it is more
complex than the component case.

Before T4, developers had to explicitly tell Tapestry which java class
was the "implementation" of the component. The mechanism to do this
was via value bound to the required 'class' attribute of the tag
<component-specification>

[I had to rewrite this section. I'm not clear anymore if component
*must* have a .jwc file. The tapestry docs say yes, but I was under
the impression that they were optional. I'll follow the docs. AHA! The
.jwc file *is* optional if one takes a second look at the "lookup"
rules in ComponentSpecificationResolverImpl - naughty docs.]

The 'class' attribute and indeed the .jwc file is now optional in T4.

Making the attribute  and xml file optional was a greatly desired
feature. On a personal note I never had a problem with .jwc files,
after I built Spindle that is!

So, Tapestry has to build the blueprint. Tapestry Annotations came to
be in order handle all the xml'ly bits that disappeared when the .jwc
file became optional. But annotations can't take the place of the
'class' attribute since you need the class to get the annotations!

The choice was made to "lookup" (there's that word again, cringe) the
java class by using the mechanism developers had to reference the
component. That's right, the name.

Here are the rules:

    * As defined by the component specification (the 'class' attribute)
    * In any package defined by the containing namespace's
org.apache.tapestry.component-class-packages meta data property (if
any)
    * In the default package
    * BaseComponent is the final default


The first rule requires a .jwc file and the declaration is explicit.
The next two rules are based on the component name (big problem) and
the last is the fallback class. The fallback class is an innocent
bystander that gets caught up in the mayhem caused by the first two
rules.

In Pt.4 we had a component MyComponent in a layout like this:

The application specification exists and is located at:

/WEB-INF/servlet-name/spec/servlet-name.application

and MyComponent.jwc is here:

/WEB-INF/servlet-name/spec/MyComponent.jwc

[This is not the only layout where problems can occur but I figured
that since I alraedy used it, why not use it again.]

We saw that MyComponent could be referenced by three 'names':

MyComponent
spec/MyComponent
servlet-name/spec/MyComponent

Assume that MyComponent.jwc has no 'class' attribute in
<component-specification>. So the first rule for looking up component
classes does not enter the picture.

So the next rule is:

* In any package defined by the containing namespace's
org.apache.tapestry.component-class-packages meta data property (if
any)

One can define a list of packages and tapestry will append the 'name'
to each package in turn until a class is found.

Think about that, we have one file that is referencable by 3 names.
Which name is the 'right' name?

Given this:

<meta key="org.apache.tapestry.component-class-packages"
   value="com.foo"/>

Tapestry would look for 3 classes:

com.foo.MyComponent
com.foo.spec.MyComponent
com.foo.servlet-name.spec.MyComponent ( the '-' is not a legal package
fragment thing I think, oh well).

Hopefully only one class in the above list will exist as these are
names relating to the same component, but that's not necessarily true.

Let's say that com.foo.spec.MyComponent exists.

At this point in the lookup only spec/MyComponent has a valid class.

What happens with the other 'namings'? They do get a class too, a
different class due to the remaining two rules:

 * In the default package
  * BaseComponent is the final default

oi. I'm at a loss on how to handle this case. I say again I AM AT A
LOSS ON HOW TO HANDLE THIS CASE.

Since the namings may now refer to different classes, even though they
share a .jwc file they are NO LONGER THE SAME COMPONENT! Their
implementations are completely different. They may all use the same
template (I haven't gone into template "lookup -iiieee!" rules yet but
trust me). The fact that their classes are different means that each
will behave differently.

And it gets even weirder if the .jwc file does exist and annotations
are used to define aspects of the "blueprint" for the component. This
is legal as annotations *trump* entries in the xml file.

One "flavour" of the component will have parameters, properties,
meta's, injects, based on the xml and the annotations of one class.
Another may have a completely different set if another class is
selected. And some may be really dumb if the last rule (BaseComponent)
matches.

To be honest if the .jwc file does not exist then the multiple namings
problem does not really exist. Any naming in the namespace is not
related to a .jwc file, no lookup rules relate the naming to the same
.jwc file (as it does not exist) Each naming is completely independent
 and each is a distinct component.

So, I've just spent a few minutes looking at what I've just written
and realized that I've been approaching this from the Tapestry runtime
pov and not the static Spindle pov.

The real problem for Spindle is that a single .jwc file may be related
to by many names and many classes. If T4 was T3, without annotations,
this wouldn't be a real problem to Spindle as Spindle 4T3's handling
of the class was restricted to an "exists" check. If the class exists,
fine. If not, record an error problem. Now, there will never be a
"class not found" error as the last rule ensures that in all cases
there will always be a class. Maybe not a useful class, but one none
the less.

Still ignoring annotations, while it is not a hard problem for
Spindle, it's a bugger for an end user. At the very least the Jump
From Spec to Class action becomes a very confusing notion. User
selects JumpTo and instead of an editor opening on one class, a list
of class names appears and the user needs to pick one. Which one? Does
the user understand that the list is there because of the internal
implementation of Tapestry?

What if the user only ever refers to the component by one of the
possible names. Hopefully this is true, although we can't guarantee
it. That only makes things worse as the user would not expect JumpTo
to present a list of classes!

One could argue that Spindle could deduce the correct naming by
examining the references. If a particular naming is never referenced,
it is bogus and should be removed from consideration. Just made
Spindle more complex/slow/hard to incrementally validate projects.

And what about the case where a component exists in the namespace with
many names and many classes but is not yet referenced by any other
page or component? This happens a lot, usually right after a new
component is created. Spindle has no references it can use to cull the
list.


The multiple naming issue combined with the multiple class for the
same spec problem is a hard problem to solve.

If only Tapestry would not allow it to happen that a .jwc file has
multiple names!

Must take a break (deep breath) and ponder this.....

Geoff


-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://sel.as-us.falkag.net/sel?cmd=lnk&kid3432&bid#0486&dat1642