001: // You can redistribute this software and/or modify it under the terms of
002: // the Ozone Core License version 1 published by ozone-db.org.
003: //
004: // The original code and portions created by SMB are
005: // Copyright (C) 1997-@year@ by SMB GmbH. All rights reserved.
006: //
007: // $Id: AbstractObjectContainer.java,v 1.3 2002/06/08 00:49:38 mediumnet Exp $
008:
009: package org.ozoneDB.core;
010:
011: import java.io.*;
012: import java.util.*;
013: import java.lang.reflect.*;
014: import org.ozoneDB.*;
015: import org.ozoneDB.tools.OPP.*;
016: import org.ozoneDB.DxLib.*;
017: import org.ozoneDB.core.*;
018: import org.ozoneDB.util.*;
019:
020: /**
021: * @author <a href="http://www.softwarebuero.de/">SMB</a>
022: * @version $Revision: 1.3 $Date: 2002/06/08 00:49:38 $
023: */
024: public abstract class AbstractObjectContainer implements
025: ObjectContainer {
026:
027: private static transient DxMap methodTable = new DxHashMap(128);
028:
029: private static transient DxMap classTable = new DxHashMap(128);
030:
031: private transient OzoneProxy theProxy;
032:
033: protected int state;
034:
035: public int state() {
036: return state;
037: }
038:
039: public synchronized void raiseState(int newState) {
040: state = newState > state ? newState : state;
041: }
042:
043: public synchronized void clearState() {
044: state = STATE_CLEAN;
045: }
046:
047: public OzoneInterface database() {
048: return Env.currentEnv().database;
049: }
050:
051: public OzoneProxy ozoneProxy() {
052: try {
053: if (theProxy == null) {
054: synchronized (this ) {
055: if (theProxy == null) {
056: String implName = targetClass().getName();
057: String proxyName;
058: if (implName
059: .endsWith(ObjectContainer.IMPLNAME_POSTFIX)) {
060: proxyName = implName.substring(0, implName
061: .length() - 5);
062: } else {
063: proxyName = implName + PROXYNAME_POSTFIX;
064: }
065:
066: MethodKey key = new MethodKey(proxyName,
067: "_ctor_", "(default)");
068: Constructor ctor = (Constructor) methodTable
069: .elementForKey(key);
070: if (ctor == null) {
071: Class cl = Env.currentEnv().classManager
072: .classForName(proxyName);
073: Class[] argTypes = { ObjectID.class,
074: OzoneInterface.class };
075: ctor = cl.getConstructor(argTypes);
076: methodTable.addForKey(ctor, key);
077: }
078:
079: //System.out.println ("creating proxy: " + cl.getName());
080: Object[] args = { id(), database() };
081: theProxy = (OzoneProxy) ctor.newInstance(args);
082: // Env.currentEnv().logWriter.newEntry (this, "proxy added to cache - " + theProxy, LogWriter.DEBUG);
083: }
084: }
085: }
086: return theProxy;
087: } catch (Exception e) {
088: Env.currentEnv().logWriter
089: .newEntry(
090: this ,
091: "ozoneProxy(): unable to create proper proxy object.",
092: e, LogWriter.WARN);
093: throw new RuntimeException(e.toString());
094: }
095: }
096:
097: public OzoneCompatible targetClone() throws Exception {
098: ByteArrayOutputStream bout = new ByteArrayOutputStream(2048);
099: ObjectOutputStream out = new ObjectOutputStream(bout);
100: out.writeObject(target());
101: out.close();
102: ObjectInputStream in = new ObjectInputStream(
103: new ByteArrayInputStream(bout.toByteArray()));
104: Object targetClone = (OzoneCompatible) in.readObject();
105: in.close();
106: return (OzoneCompatible) targetClone;
107: }
108:
109: /**
110: * Search the method with the specified name and signature. Once
111: * a method has been invoked it is stored in a global cache that holds
112: * the method objects of all database classes.
113: *
114: *
115: * @param methodName
116: * @param sig
117: * @param args
118: */
119: protected final Method methodFor(Env env, Object obj,
120: String methodName, String sig, Object[] args)
121: throws Exception {
122:
123: MethodKey key = new MethodKey(targetClass().getName(),
124: methodName, sig);
125:
126: Method method = (Method) methodTable.elementForKey(key);
127: if (method == null) {
128: Class[] classes;
129: StringTokenizer st = new StringTokenizer(sig,
130: OPP.SIGNATURE_DELIMITER);
131: classes = new Class[args.length];
132: for (int i = 0; st.hasMoreTokens(); ++i) {
133: classes[i] = env.classManager.classForName(st
134: .nextToken());
135: }
136:
137: method = obj.getClass().getMethod(methodName, classes);
138: methodTable.addForKey(method, key);
139: env.logWriter.newEntry(this , "method added to cache - "
140: + key, LogWriter.DEBUG);
141: }
142: return method;
143: }
144:
145: /**
146: * Search the constructor with the specified signature.
147: * Once a constructor has been invoked it is stored in a global cache that
148: * holds the method and constructor objects of all database classes.
149: *
150: * @param env
151: * @param obj
152: * @param sig
153: */
154: protected Constructor constructorFor(Env env, Class cl, String sig)
155: throws Exception, NoSuchMethodException {
156:
157: MethodKey key = new MethodKey(cl.getName(), "_ctor_", sig);
158: Constructor constructor = (Constructor) methodTable
159: .elementForKey(key);
160: if (constructor == null) {
161: Class[] classes;
162: if (sig == null) {
163: classes = new Class[0];
164: } else {
165: StringTokenizer st = new StringTokenizer(sig,
166: OPP.SIGNATURE_DELIMITER);
167: classes = new Class[st.countTokens()];
168: for (int i = 0; st.hasMoreTokens(); ++i) {
169: classes[i] = env.classManager.classForName(st
170: .nextToken());
171: }
172: }
173: try {
174: constructor = cl.getConstructor(classes);
175: } catch (NoSuchMethodException e) {
176: StringBuffer b = new StringBuffer(200);
177:
178: b.append("caught NoSuchMethodException for " + cl
179: + " constructor signature \"" + sig + "\" (");
180: for (int i = 0; i < classes.length; i++) {
181: if (i != 0)
182: b.append(',');
183: b.append(classes[i]);
184: }
185: b.append(")\n");
186:
187: b.append("available constructors are:\n");
188:
189: Constructor[] constructors = cl.getConstructors();
190:
191: for (int i = 0; i < constructors.length; i++) {
192: b.append(" " + constructors[i] + "\n");
193: }
194:
195: env.logWriter.newEntry(this , b.toString(),
196: LogWriter.ERROR);
197: throw e;
198: }
199: methodTable.addForKey(constructor, key);
200: env.logWriter.newEntry(this ,
201: "constructor added to cache - " + key,
202: LogWriter.DEBUG);
203: }
204: return constructor;
205: }
206:
207: public static void flushMethodCache() {
208: methodTable = new DxHashMap(128);
209: }
210:
211: public Object invokeTarget(Env env, String methodName, String sig,
212: Object[] args) throws Exception, InvocationTargetException {
213:
214: Method method = methodFor(env, target(), methodName, sig, args);
215: if (method == null) {
216: throw new MethodNotFoundExc(methodName);
217: }
218:
219: try {
220: return method.invoke(target(), args);
221: } catch (InvocationTargetException e) {
222: throw e;
223: }
224: }
225:
226: public Object invokeTarget(Env env, int methodIndex, Object[] args)
227: throws Exception, InvocationTargetException {
228:
229: Class cl = targetClass();
230:
231: Method[] methods = (Method[]) classTable.elementForKey(cl);
232: if (methods == null) {
233: methods = OPPHelper.methodsOfClass(cl);
234: classTable.addForKey(methods, cl);
235: }
236:
237: Method method = methods[methodIndex];
238: if (method == null) {
239: throw new MethodNotFoundExc("Method index: " + methodIndex);
240: }
241:
242: if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
243: env.logWriter.newEntry(this , "invoke(): method="
244: + method.getName(), LogWriter.DEBUG3);
245: }
246:
247: try {
248: return method.invoke(target(), args);
249: } catch (InvocationTargetException e) {
250: throw e;
251: }
252: }
253:
254: public void createTarget(Env env, Class cl, String sig,
255: Object[] args) throws Exception {
256: OzoneCompatible result;
257: if (sig != null) {
258: Constructor ctor = constructorFor(env, cl, sig);
259: result = (OzoneCompatible) ctor.newInstance(args);
260: } else {
261: result = (OzoneCompatible) cl.newInstance();
262: }
263: setTarget(result);
264: }
265:
266: }
|