I am trying to completely seperate my business logic from my ORM
implementation using pluggable HiveMind services. I do not want to play with
ORM classes at all and rather just take them off the code generator, as in
the case of Cayenne.
For each of my business entities I will implement an interface (simple
get/set methods usually of primtive object types) and code off that. I then
implement a service for the ORM implementation and use CtClasses* that
implement the entity interface over the ORMs classes. Most these ORM tools
create bean like classes with simple single parm get/set methods. I'm still
not sure how all this will pan out, but it feels right.
If your data squeezer is ORM implementation specific (or coded into an ORM
dependant layer), then your URLs, which could be stored as favourites, may
be coupled to implementation. You really need a common method for squeezing
that is independant of the ORM, and coded into your services. I suggest some
lightweight encryption to code object IDs and keys, but if you follow my
model, you need your object IDs to be implemented outside the ORM. You might
code something like a UID on the entity interface, maybe just a single
character, and then a getter method to obtain the PK, as the PK concept is
probably common to all ORMs and databases. Perhaps your squeezer can then be
implemented as static methods in a util class. Maybe you could extend the
code below to add the squeezer hooking to the CTClasses?
If you want to persist entire serialized entity objects in the client (seems
nasty to me), then again they need to be done implementation independant
IMO - maybe some compressed base64 if you worried about size, it might help?
John
* code to implement a common entity interface on a ORM entity class (mapping
provided in HiveMind contrib)
package container;
import java.beans.Introspector;
import java.util.Iterator;
import java.util.Map;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.NotFoundException;
public class ImplMapper extends BaseService {
ClassPool pool = ClassPool.getDefault();
public ImplMapper() {
pool.appendClassPath(new ClassClassPath(getClass()));
}
// called by HiveMind to provide a Map of the common entity interface and
ORM class names
public void setConfigMap(Map configMap) {
log.debug("starting implementation mapping...");
for (Iterator keys = configMap.keySet().iterator(); keys.hasNext();) {
String className = (String) keys.next();
String interfaceName = (String) configMap.get(className);
setInterfaceOfClass(className, interfaceName);
}
}
// use javassist to implement the entity interface used in the business
logic services
private void setInterfaceOfClass(String className, String interfaceName) {
try {
CtClass ptc = pool.get(className);
CtClass pti = pool.get(interfaceName);
CtMethod[] ptims = pti.getDeclaredMethods();
if (!pti.isInterface()) {
log.fatal("The class " + interfaceName
+ " is not an interface.");
return;
}
for (int m = 0; m < ptims.length; m++) {
// see if class defines the method when method is get or set
if (ptims[m].getMethodInfo().isMethod()
&& (ptims[m].getName().startsWith("get") || ptims[m]
.getName().startsWith("set"))) {
try {
// see if method already declared in class
CtMethod ptcm = ptc.getDeclaredMethod(ptims[m]
.getName(), ptims[m].getParameterTypes());
} catch (NotFoundException ex1) {
// the method is not declared and needs to be added
// if not in superclass then a problem!
boolean inSuper;
try {
CtMethod ptcm = ptc.getMethod(ptims[m].getName(),
ptims[m].getSignature());
inSuper = true;
} catch (NotFoundException ex2) {
inSuper = false;
}
// quit if method unavailable from superclass
if (!inSuper) {
log.fatal("Method " + ptims[m].getName()
+ " not available in " + className
+ " class.");
return;
}
// class does not define method so add it
if (ptims[m].getName().startsWith("get")) {
String body = "public "
+ ptims[m].getReturnType().getName() + " "
+ ptims[m].getName() + "() { return super."
+ ptims[m].getName() + "(); }";
log.debug("add " + body + " to class " + className);
CtMethod nm = CtNewMethod.make(body, ptc);
ptc.addMethod(nm);
}
if (ptims[m].getName().startsWith("set")) {
String type = ptims[m].getParameterTypes()[0]
.getName();
String body = "public void " + ptims[m].getName()
+ "(" + type + " x" + ") { super."
+ ptims[m].getName() + "(x); }";
log.debug("add " + body + " to class " + className);
CtMethod nm = CtNewMethod.make(body, ptc);
ptc.addMethod(nm);
}
}
}
}
ptc.addInterface(pti);
// force the class loader to load the modified class
ptc.toClass(getClass().getClassLoader());
if (log.isDebugEnabled()) {
// ptc.writeFile();
}
log.info("class " + className + " now implements " + interfaceName);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
----- Original Message -----
From: "Steve" <[EMAIL PROTECTED]>
To: "'Tapestry users'" <[email protected]>
Sent: Friday, December 09, 2005 11:52 PM
Subject: RE: Wiring Hivemind to
> Thanks John,
>
> I based my work on that article, the hibernate one and a few others around
> the place. While working through it and with my fledgling HiveMind
> knowledge I thought a 100% HiveMind solution might be the go, I just can't
> wire it up yet. I think something based on your idea is probably
> immediately achievable, unless someone knows how to wire a service to a
ASO,
> it's probably easy I just can't see it yet...the simplest solutions are
> always the best, right?
>
> So with your solution in mind, I could make the squeezer service just pick
> the dataContext and object id store off the thread. My implementation is
> based on:
>
http://equalitylearning.org/Tassel/app?service=external/ViewComponent&sp=SCa
> yenneDataObjectSqueezeAdaptor
>
> The idea with the squeezer is to override the default one which would
base64
> the DataObjects into pages and urls, not great especially in tables or
other
> large lists. This squeezer takes the dataobject id instead of the whole
> serialized object. The only caveat here is the security risk of exposing
> the Id, but you could just change you squeezer implementation or perhaps
use
> different object id's. This has been discussed on the Cayenne lists.
>
> Thanks again.
>
>
> -----Original Message-----
> From: John Coleman [mailto:[EMAIL PROTECTED]
> Sent: Friday, 9 December 2005 8:36 PM
> To: Tapestry users
> Subject: Re: Wiring Hivemind to
>
> I found these notes
> http://wiki.apache.org/jakarta-tapestry/CayenneTapestrySqueezer, but seems
> not so helpful for your case. I have a different solution which may help
> you.
>
> What I did to use Cayenne in HiveMind is this:
>
> configure this listener in web.xml:
> <listener>
>
<listener-class>org.objectstyle.cayenne.conf.WebApplicationContextProvider</
> listener-class>
> </listener>
>
> and in my HiveMind services which are PoolManageable:
>
> public DataContext getDataContext() {
> return context;
> }
>
> public void activateService() {
> // this method only works when a DataContext is bound by a listener
> try {
> context = DataContext.getThreadDataContext();
> } catch (java.lang.IllegalStateException ex) {
> // TODO oh dear!
> }
> log.debug("activate service..."
> + Thread.currentThread().getName());
> }
>
> public void passivateService() {
> try {
> context.commitChanges();
> } catch (CayenneRuntimeException rex) {
> log.error("error commiting changes:", rex);
> }
> log.debug("passivate service..."
> + Thread.currentThread().getName());
> }
>
> This way there is no need to mess with the visit object, just pick the
> DataContext off the current thread. In my case whenever a service is
pulled
> off the pool, it grabs the DataContext and the service can then get that
> using a getDataContext() method from the subclass service implementation.
> This is quite neat and decouples things a bit.
>
> Ideally I'd like not to use the WebAppContextProvider and have a
standalone
> solution done 100% in HiveMind POJOs. I'd still like to see how the
squeezer
> is used, and understand the practical benefits of it.
>
> John
>
>
> ----- Original Message -----
> From: "Steve Wells" <[EMAIL PROTECTED]>
> To: "Tapestry users" <[email protected]>
> Sent: Friday, December 09, 2005 5:49 AM
> Subject: Re: Wiring Hivemind to
>
>
> Just to clarify a bit.
>
> What I'm trying to do is get a custom squeezer defined in HiveMind to
> access ASO's, without using any static threadLocal implmentation. The
> ASO's are data context and object id stores for the squeezer.
>
> Another way I thought here is to pass the
> tapestry.state.ApplicationObjects to the squeezer service:
> <service-point id="CayenneAdapter"
> interface="org.rz.squeezer.IDataObjectAdapter">
> <invoke-factory>
> <construct class="org.rz.squeezer.DataObjectAdaptor">
> <set-configuration property="visitList"
> configuration-id="tapestry.state.ApplicationObjects"/>
> </construct>
>
> and the constructor:
> public DataObjectAdaptor(Map visitList)
> I've also exchanged Map with List and Object and get:
> Unable to find constructor applicable for autowiring. Use explicit
> constructor parameters.
>
> TIA
>
>
> On Fri, 09 Dec 2005 14:02:32 +1000, "Steve Wells"
> <[EMAIL PROTECTED]> said:
> > I'm trying to get a Cayenne Data Squeezer to work wired with more
> > Hivemind than some previous solutions out there.
> > The Squeeze adapter constructor has 2 params which should both be stored
> > in session scope, so I'd like to config Hivemind to set the object into
> > session scope and pass them to the SqueezeAdapter, maybe this is a dumb
> > thing to do.
> >
> > I've tryed various things but here is the best shot so far:
> > hivemodule.xml
> > <!-- Cayenne Squeeze adapter service -->
> > <service-point id="CayenneAdapter"
> > interface="org.rz.squeezer.IDataObjectAdapter">
> > <invoke-factory>
> > <construct
> > class="org.rz.squeezer.DataObjectAdaptor"></construct>
> > <!-- It would be nice if I could get the constructor params to autowire
> > from the session instances -->
> >
> > <!-- DataContext param that should go into session and feed into
> > Squeezeadapter -->
> > <contribution configuration-id="tapestry.state.ApplicationObjects">
> > <state-object name="dataContextProvider" scope="session">
> > <create-instance
> > class="org.rz.squeezer.DataContextProviderImpl"/>
> > </state-object>
> > </contribution>
> >
> > What I also tryed was to create a service for the dataContextProvider
> > and pass the reference to the state-object but it seems this is a no go.
> >
> > Has anyone tried this or can anyone provide at least a hint?
> >
> > Thanks,
> >
> > Steve
> >
> >
> > --
> > Steve Wells
> > [EMAIL PROTECTED]
> >
> > --
> > http://www.fastmail.fm - Same, same, but different.
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: [EMAIL PROTECTED]
> > For additional commands, e-mail: [EMAIL PROTECTED]
> >
> --
> Steve Wells
> [EMAIL PROTECTED]
>
> --
> http://www.fastmail.fm - Choose from over 50 domains or use your own
>
>
> ---------------------------------------------------------------------
> 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]
>
>
>
> ---------------------------------------------------------------------
> 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]