If you haven't, would you mind putting this up on the WIKI?
Jamie
On Jul 12, 2005, at 1:13 PM, Filip Balas wrote:
It seems to me that no where on the internet is this whole
process explained in enough detail to make it easy to
understand in under 15min. So here is my best attempt.
I assume:
a) You know what a Squeezer is and how to use it.
If you do not, visit:
http://wiki.apache.org/jakarta-tapestry/DataSqueezer
b) You are familiar enough with Cayenne to understand
that each user/session must have it's own, unique
DataContext (whether you share the 'DataRowStore'
or not)
Now typically we store the Datacontext in the Visit class.
That way each session has one unique data context for
all pages. Peace of cake right? Wrong...
When using direct links, the cleanest way to serialize and
de-serialize objects is using your own SqueezerAdaptor.
This is where the problem begins, the ISqueezeAdaptor
interface does not provide a mechanism for accessing the
Visit class, hence no access to your Datacontext which
results in having no way to de-serialize your objects.
This is where the Threadlocal solution mentioned above by
my savvy colleagues comes in. This solution essentially
makes the current visit class globaly available through access
to the current running thread. I am not sure how the specifics
work <someone can jump in with links to the deatails here>
but this essentially gives us what we need to make this
machine purrrrrr.
Okay, code is worth a thousand words so I'm going to paste
some code and explain as I go.
First we create the class that gives us access to the current
thread and will henceforth be used to provide global access
to whatever the current visit class is:
public class UserContext {
static ThreadLocal _visitLocal = new ThreadLocal();
public static Object getVisit() {
return (Visit) _visitLocal.get();
}
public static void setVisit(Object visit) {
_visitLocal.set(visit);
}
}
You should take note that everything here is static and
so can be accessed from anywhere.
Next we need to Create a Custom Engine to initialize
the UserContext with the Visit and to register our custom
Squeeze adapter.
NOTE:
To register a custom engine, go to your foo.application
file and change the engine in the line:
<application name="foo" engine-class="com.acme.superApp.CustomEngine">
If you already knew how to do this, this may seem like a
silly step to mention but I couldn't find a single place in the
TIA book where it tells you this, nor could I find it on the net.
public class CustomEngine extends BaseEngine {
protected void setupForRequest(RequestContext context)
{
if (getVisit() != null)
UserContext.setVisit(getVisit());
super.setupForRequest(context);
}
public DataSqueezer createDataSqueezer()
{
DataSqueezer defaultDataSqueezer = super.createDataSqueezer();
DataSqueezeAdaptor customAdaptor = new DataSqueezeAdaptor();
customAdaptor.register(defaultDataSqueezer);
return defaultDataSqueezer;
}
}
The main magic in the above is initializing the UserContext
with the visit class currently registered with the Engine.
Now because of this magic, we can access the Visit class in our
adaptor
unsqueeze method:
public class DataSqueezeAdaptor implements ISqueezeAdaptor {
private static final String prefix = "D";
public DataSqueezeAdaptor()
{
super();
}
public String squeeze(DataSqueezer squeezer, Object data) throws
IOException
{
if (data instanceof IDataObject)
return prefix + getDataStore().put((IDataObject) data);
return null;
}
public Object unsqueeze(DataSqueezer squeezer, String string)
throws IOException
{
String id = string.substring(prefix.length());
try
{
return getDataStore().get(id, getDataContext());
} catch (Exception e)
{
return null;
}
}
private Visit getVisit()
{
return (Visit) UserContext.getVisit();
}
public void register(DataSqueezer squeezer)
{
squeezer.register(prefix, IDataObject.class, this);
}
private DataContext getDataContext()
{
return getVisit().getDataContext();
}
private IDataStore getDataStore()
{
return getVisit().getDataStore();
}
}
And there you have it folks! If you're wondering
what the IDataStore is, it's simply a Map that
serves 2 purposes. First it generates unique
IDs for each object and second is stores the objects
while they are off on their trip to the client. Why
don't I just use the DataContext for this you ask?
Because I have chosen to make all of my objects
follow a state pattern, so internally they can be either
connected (Registered with the DataContext) or
Disconnected (Just Pojo's masquerading as DataObjects).
This allows my app to always work with objects as whole
entities, whithout worrying about how to create and remove
them from cayenne (each state does that).
Thanks to everyone who helped me figure this one out.
Filip
On 7/11/05, Robert Zeigler <[EMAIL PROTECTED]> wrote:
Incidentally, I made the data squeezer implementation I sent to Todd
available awhile ago on Tassel.
Robert
Todd O'Bryan wrote:
Robert Ziegler sent me a CayenneDataObjectSqueezeAdaptor.jar awhile
ago. Check the list to see if he sent it through the list.
Otherwise,
I'd be happy to send it along if I get his permission.
Todd
On Jul 7, 2005, at 9:49 PM, Filip Balas wrote:
Has anybody been able to get the squeezer interface
to work with Cayenne?
It seems like it is impossible to make the Datacontext
available to the datasqueezer. I can't get the visit class
from the squeezer and that is where the context resides?!?!?
I tried to use the global map to solve this problem except
the map is not initialized until AFTER the squeezer is
created. I am at my wits end.
HELP!
Filip
-------------------------------------------------------------------
--
To unsubscribe, e-mail: tapestry-user-
[EMAIL PROTECTED]
For additional commands, e-mail: tapestry-user-
[EMAIL PROTECTED]
--------------------------------------------------------------------
-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: tapestry-user-
[EMAIL PROTECTED]
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: tapestry-user-
[EMAIL PROTECTED]
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]