1:
31: package ;
32:
33: import ;
34: import ;
35: import ;
36:
37: import ;
38:
39: import ;
40: import ;
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47:
48:
58: public class StaticReportDataFactory implements ReportDataFactory
59: {
60: public StaticReportDataFactory()
61: {
62: }
63:
64:
74: public ReportData queryData(final String query, final DataSet parameters)
75: throws ReportDataFactoryException
76: {
77: final int methodSeparatorIdx = query.indexOf('#');
78:
79: if ((methodSeparatorIdx + 1) >= query.length())
80: {
81:
82: throw new ReportDataFactoryException("Malformed query: " + query);
83: }
84:
85: if (methodSeparatorIdx == -1)
86: {
87:
88:
89: final String[] parameterNames;
90: final int parameterStartIdx = query.indexOf('(');
91: final String constructorName;
92: if (parameterStartIdx == -1)
93: {
94: parameterNames = new String[0];
95: constructorName = query;
96: }
97: else
98: {
99: parameterNames = createParameterList(query, parameterStartIdx);
100: constructorName = query.substring(0, parameterStartIdx);
101: }
102:
103: try
104: {
105: final Constructor c = findDirectConstructor(constructorName, parameterNames.length);
106:
107: final Object[] params = new Object[parameterNames.length];
108: for (int i = 0; i < parameterNames.length; i++)
109: {
110: final String name = parameterNames[i];
111: params[i] = DataSetUtility.getByName(parameters, name);
112: }
113: final Object o = c.newInstance(params);
114: if (o instanceof TableModel)
115: {
116: return new TableReportData ((TableModel) o);
117: }
118:
119: return (ReportData) o;
120: }
121: catch (Exception e)
122: {
123: throw new ReportDataFactoryException
124: ("Unable to instantiate class for non static call.", e);
125: }
126: }
127:
128: return createComplexTableModel
129: (query, methodSeparatorIdx, parameters);
130: }
131:
132: private ReportData createComplexTableModel(final String query,
133: final int methodSeparatorIdx,
134: final DataSet parameters)
135: throws ReportDataFactoryException
136: {
137: final String constructorSpec = query.substring(0, methodSeparatorIdx);
138: final int constParamIdx = constructorSpec.indexOf('(');
139: if (constParamIdx == -1)
140: {
141:
142: return loadFromDefaultConstructor(query, methodSeparatorIdx, parameters);
143: }
144:
145:
146: final String className = query.substring(0, constParamIdx);
147: final String[] parameterNames = createParameterList(constructorSpec, constParamIdx);
148: final Constructor c = findIndirectConstructor(className, parameterNames.length);
149:
150: final String methodQuery = query.substring(methodSeparatorIdx + 1);
151: final String[] methodParameterNames;
152: final String methodName;
153: final int parameterStartIdx = methodQuery.indexOf('(');
154: if (parameterStartIdx == -1)
155: {
156:
157: methodParameterNames = new String[0];
158: methodName = methodQuery;
159: }
160: else
161: {
162: methodName = methodQuery.substring(0, parameterStartIdx);
163: methodParameterNames = createParameterList(methodQuery, parameterStartIdx);
164: }
165: final Method m = findCallableMethod(className, methodName, methodParameterNames.length);
166:
167: try
168: {
169: final Object[] constrParams = new Object[parameterNames.length];
170: for (int i = 0; i < parameterNames.length; i++)
171: {
172: final String name = parameterNames[i];
173: constrParams[i] = DataSetUtility.getByName(parameters, name);
174: }
175: final Object o = c.newInstance(constrParams);
176:
177: final Object[] methodParams = new Object[methodParameterNames.length];
178: for (int i = 0; i < methodParameterNames.length; i++)
179: {
180: final String name = methodParameterNames[i];
181: methodParams[i] = DataSetUtility.getByName(parameters, name);
182: }
183: final Object data = m.invoke(o, methodParams);
184: if (data instanceof TableModel)
185: {
186: return new TableReportData((TableModel) data);
187: }
188: return (ReportData) data;
189: }
190: catch (Exception e)
191: {
192: throw new ReportDataFactoryException
193: ("Unable to instantiate class for non static call.");
194: }
195: }
196:
197: private ReportData loadFromDefaultConstructor(final String query,
198: final int methodSeparatorIdx,
199: final DataSet parameters)
200: throws ReportDataFactoryException
201: {
202: final String className = query.substring(0, methodSeparatorIdx);
203: final String methodSpec = query.substring(methodSeparatorIdx + 1);
204: final String methodName;
205: final String[] parameterNames;
206: final int parameterStartIdx = methodSpec.indexOf('(');
207: if (parameterStartIdx == -1)
208: {
209:
210: parameterNames = new String[0];
211: methodName = methodSpec;
212: }
213: else
214: {
215: parameterNames = createParameterList(methodSpec, parameterStartIdx);
216: methodName = methodSpec.substring(0, parameterStartIdx);
217: }
218:
219: try
220: {
221: final Method m = findCallableMethod(className, methodName, parameterNames.length);
222: final Object[] params = new Object[parameterNames.length];
223: for (int i = 0; i < parameterNames.length; i++)
224: {
225: final String name = parameterNames[i];
226: params[i] = DataSetUtility.getByName(parameters, name);
227: }
228:
229: if (Modifier.isStatic(m.getModifiers()))
230: {
231: final Object o = m.invoke(null, params);
232: if (o instanceof TableModel)
233: {
234: return new TableReportData((TableModel) o);
235: }
236: return (ReportData) o;
237: }
238:
239: final ClassLoader classLoader = getClassLoader();
240: final Class c = classLoader.loadClass(className);
241: final Object o = c.newInstance();
242: if (o == null)
243: {
244: throw new ReportDataFactoryException
245: ("Unable to instantiate class for non static call.");
246: }
247: final Object data = m.invoke(o, params);
248: if (data instanceof TableModel)
249: {
250: return new TableReportData((TableModel) data);
251: }
252: return (ReportData) data;
253: }
254: catch (ReportDataFactoryException rdfe)
255: {
256: throw rdfe;
257: }
258: catch (Exception e)
259: {
260: throw new ReportDataFactoryException
261: ("Something went terribly wrong: ", e);
262: }
263: }
264:
265: private String[] createParameterList(final String query,
266: final int parameterStartIdx)
267: throws ReportDataFactoryException
268: {
269: final int parameterEndIdx = query.lastIndexOf(')');
270: if (parameterEndIdx < parameterStartIdx)
271: {
272: throw new ReportDataFactoryException("Malformed query: " + query);
273: }
274: final String parameterText =
275: query.substring(parameterStartIdx + 1, parameterEndIdx);
276: final CSVTokenizer tokenizer = new CSVTokenizer(parameterText);
277: final int size = tokenizer.countTokens();
278: final String[] parameterNames = new String[size];
279: int i = 0;
280: while (tokenizer.hasMoreTokens())
281: {
282: parameterNames[i] = tokenizer.nextToken();
283: i += 1;
284: }
285: return parameterNames;
286: }
287:
288: protected ClassLoader getClassLoader()
289: {
290: return ObjectUtilities.getClassLoader(StaticReportDataFactory.class);
291: }
292:
293: private Method findCallableMethod(final String className,
294: final String methodName,
295: final int paramCount)
296: throws ReportDataFactoryException
297: {
298: final ClassLoader classLoader = getClassLoader();
299:
300: if (classLoader == null)
301: {
302: throw new ReportDataFactoryException("No classloader!");
303: }
304: try
305: {
306: final Class c = classLoader.loadClass(className);
307: if (Modifier.isAbstract(c.getModifiers()))
308: {
309: throw new ReportDataFactoryException("Abstract class cannot be handled!");
310: }
311:
312: final Method[] methods = c.getMethods();
313: for (int i = 0; i < methods.length; i++)
314: {
315: final Method method = methods[i];
316: if (Modifier.isPublic(method.getModifiers()) == false)
317: {
318: continue;
319: }
320: if (method.getName().equals(methodName) == false)
321: {
322: continue;
323: }
324: final Class returnType = method.getReturnType();
325: if (method.getParameterTypes().length != paramCount)
326: {
327: continue;
328: }
329: if (TableModel.class.isAssignableFrom(returnType) ||
330: ReportData.class.isAssignableFrom(returnType))
331: {
332: return method;
333: }
334: }
335: }
336: catch (ClassNotFoundException e)
337: {
338: throw new ReportDataFactoryException("No such Class", e);
339: }
340: throw new ReportDataFactoryException("No such Method: " + className + "#" + methodName);
341: }
342:
343: private Constructor findDirectConstructor(final String className,
344: final int paramCount)
345: throws ReportDataFactoryException
346: {
347: final ClassLoader classLoader = getClassLoader();
348: if (classLoader == null)
349: {
350: throw new ReportDataFactoryException("No classloader!");
351: }
352:
353: try
354: {
355: final Class c = classLoader.loadClass(className);
356: if (TableModel.class.isAssignableFrom(c) == false &&
357: ReportData.class.isAssignableFrom(c) == false)
358: {
359: throw new ReportDataFactoryException("The specified class must be either a TableModel or a ReportData implementation.");
360: }
361: if (Modifier.isAbstract(c.getModifiers()))
362: {
363: throw new ReportDataFactoryException("The specified class cannot be instantiated: it is abstract.");
364: }
365:
366: final Constructor[] methods = c.getConstructors();
367: for (int i = 0; i < methods.length; i++)
368: {
369: final Constructor method = methods[i];
370: if (Modifier.isPublic(method.getModifiers()) == false)
371: {
372: continue;
373: }
374: if (method.getParameterTypes().length != paramCount)
375: {
376: continue;
377: }
378: return method;
379: }
380: }
381: catch (ClassNotFoundException e)
382: {
383: throw new ReportDataFactoryException("No such Class", e);
384: }
385: throw new ReportDataFactoryException
386: ("There is no constructor in class " + className +
387: " that accepts " + paramCount + " parameters.");
388: }
389:
390:
391: private Constructor findIndirectConstructor(final String className,
392: final int paramCount)
393: throws ReportDataFactoryException
394: {
395: final ClassLoader classLoader = getClassLoader();
396: if (classLoader == null)
397: {
398: throw new ReportDataFactoryException("No classloader!");
399: }
400:
401: try
402: {
403: final Class c = classLoader.loadClass(className);
404: if (Modifier.isAbstract(c.getModifiers()))
405: {
406: throw new ReportDataFactoryException("The specified class cannot be instantiated: it is abstract.");
407: }
408:
409: final Constructor[] methods = c.getConstructors();
410: for (int i = 0; i < methods.length; i++)
411: {
412: final Constructor method = methods[i];
413: if (Modifier.isPublic(method.getModifiers()) == false)
414: {
415: continue;
416: }
417: if (method.getParameterTypes().length != paramCount)
418: {
419: continue;
420: }
421: return method;
422: }
423: }
424: catch (ClassNotFoundException e)
425: {
426: throw new ReportDataFactoryException("No such Class", e);
427: }
428: throw new ReportDataFactoryException
429: ("There is no constructor in class " + className +
430: " that accepts " + paramCount + " parameters.");
431: }
432:
433:
434: public void open()
435: {
436:
437: }
438:
439: public void close()
440: {
441:
442: }
443:
444:
451: public ReportDataFactory derive()
452: {
453: return this;
454: }
455: }