What I am using for the same problem, is the attached Cache Class, which only
looks at startup and if unknown objects are required in the database. We are
not using JDK1.5, so we are writing specialised classes for each table, in
which we define constants and getInstance methods for the correct return type.
When foreign keys are referring this class we are using the conversion
attribute of the field-descriptor.
Abstract Base class:
public abstract class BaseEnumeratedObject implements EnumeratedObject,
FieldConversion {
/** Id of the object*/
protected int id = 0;
/** Name of the object */
protected String key; // key of the flag
protected static JLogger LOG =
JLoggerFactory.getInstance().getLogger(BaseEnumeratedObject.class);
/**
* stores lists of objects by key Object.class
*/
private static Hashtable loadedObjects = new Hashtable();
/**
* returns list of objects for the given class
* @param clazz
* @return
*/
protected static List getListForClass(Class clazz) {
List back = (List) loadedObjects.get(clazz);
return back;
}
/**
* loads all objects of the given class
* @param clazz
*/
protected static synchronized void initInstances(Class clazz) {
try {
if (getListForClass(clazz) == null) {
CommonObject bean = getObjectBean();
List objects = bean.getAllByClass(clazz);
loadedObjects.put(clazz, objects);
}
} catch (Exception e) {
LOG.error("error reading objects: " + clazz, e);
}
}
/**
* just reroutes the other method
* @param id ID of the object
* @param clazz class of the object
* @return
*/
public static BaseEnumeratedObject getInstance(Integer id, Class clazz) {
return (id == null) ? null : getInstance(id.intValue(), clazz);
}
/**
*
* @param key
* @param clazz class of the object
* @return
*/
public static BaseEnumeratedObject getInstance(String key, Class clazz) {
initInstances(clazz);
List objects = getListForClass(clazz);
int i = objects.size();
while (--i >= 0) {
if (((BaseEnumeratedObject)
objects.get(i)).key.equalsIgnoreCase(key)) {
return (BaseEnumeratedObject)objects.get(i);
}
}
return null;
}
/**
* returns an object for the given id
* @param id
* @param clazz class of the object
* @return
*/
public static BaseEnumeratedObject getInstance(int id, Class clazz) {
initInstances(clazz);
List objects = getListForClass(clazz);
int i = objects.size();
while (--i >= 0) {
if (((BaseEnumeratedObject) objects.get(i)).id == id) {
return (BaseEnumeratedObject)objects.get(i);
}
}
// now look in DB
try {
BaseEnumeratedObject load =
(BaseEnumeratedObject)getObjectBean().getObjectByClass(clazz, new Integer(id));
if (load != null) {
objects.add(load);
return load;
}
} catch (Exception e) {
LOG.error("could not load object with primary key: " + id + "
reason: " + e.getMessage());
}
LOG.warn("unknown object requested for class: " + clazz + " : " + id);
return null;
}
public String toString() {
return "" + this.id;
}
public Long toLong() {
return new Long(this.id);
}
public String getKey() {
return this.key;
}
public int intValue() {
return this.id;
}
public int compareTo(Object o) {
return this.id - ((BaseEnumeratedObject) o).id;
}
public final boolean equals(Object other) {
return super.equals(other);
}
public final int hashCode() {
return this.id;
}
/**
* as all objects are immutable instances, we don't need to do a "real"
clone
*
* @return this object
*/
public final Object clone() {
return this;
}
/**
* from ojb interface
*
* @param o
* @return primary Key stored here
* @throws ConversionException
*/
public Object javaToSql(Object o) throws ConversionException {
return this.toLong();
}
// setter for ojb
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setKey(String key) {
this.key = key;
}
/**
* returns the accessor bean
* @return
* @throws ServiceLocatorException
* @throws CreateException
* @throws RemoteException
*/
protected static CommonObject getObjectBean() throws
ServiceLocatorException, CreateException, RemoteException {
CommonObjectHome home = (CommonObjectHome)
ServiceLocator.getInstance().getRemoteHome(CommonObject.DEFAULT_JNDI_NAME,
CommonObjectHome.class.getName());
CommonObject bean = home.create();
return bean;
}
Example for concrete class:
public static Genre POP = getInstance("Pop");
public Genre() {
}
public Genre(int id, String key) {
this.id = id;
this.key = key;
}
/**
* access to the list of objects, made unmodifiable!
*
* @return the list of objects
*/
public static List getAllValues() {
return Collections.unmodifiableList(getListForClass(Genre.class));
}
/**
* load all objects at startup
*/
static {
LOG.debug("loading genres");
initInstances(Genre.class);
}
public static Genre getInstance(int id) {
return (Genre) getInstance(id, Genre.class);
}
public static Genre getInstance(Integer ordinal) {
return (Genre) getInstance(ordinal, Genre.class);
}
public static Genre getInstance(String key) {
return (Genre) getInstance(key, Genre.class);
}
public Object sqlToJava(Object o) throws ConversionException {
if (o == null)
return null;
return getInstance(((Long) o).intValue());
}
-----Urspr�ngliche Nachricht-----
Von: Alexandre Borgoltz [mailto:[EMAIL PROTECTED]
Gesendet: Dienstag, 15. Februar 2005 11:06
An: OJB Users List
Betreff: Re: [cache] Caching JDBC access - first idea
Would it be a good idea to override
public ResultSetAndStatement executeQuery(Query arg0, ClassDescriptor arg1)
in JdbcAccessImpl, and cache the resultset directly?
I could cache an instance of a "fake" resultset implementation,
populated with the data from the "real" resultset, the first time the
jdbc access is performed. And then always return a ResultSetAndStatement
build upon this cached resultset.
What do you think? Is there a better way to go? Are there drawbacks I
don't see?
Thank you!
*--
Alexandre BORGOLTZ
Head of Technology
SmartJog SA
Phone: +33 (0)1 4996 6324
Fax: +33 (0)1 4996 6405
Mobile: +33 (0)6 8882 1417
[EMAIL PROTECTED]
Alexandre Borgoltz wrote:
> Hey all,
>
> Simple question :
> There are a few tables in my model that I know won't change during
> long periods. For exemple, the list of continents won't change a lot :)
> I would like to cache them in a very "strong" way, which means
> returning always the same objects, WITHOUT EVEN PERFORMING ANY JDBC
> ACCESS.
> Which part of OJB should I customize to achieve this? I guess it's not
> on the ObjectCache level, because object caching occurs after the
> JdbcAccess has been performed.
> Is it JdbcAccess then? Something like
> public ResultSetAndStatement executeQuery(Query arg0, ClassDescriptor
> arg1)
> would look really good if if didn't return a ResultSetAndStatement,
> which I guess can be used only once.
> So what?
>
> In the end, it "simply" means applying cache directly at the query
> level. Don't re-execute the query (jdbc+bean population) if it has
> already been performed (and is configured as cacheable...).
>
> Thank you in advance for your help!
>
---------------------------------------------------------------------
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]