001: // Copyright 2006, 2007 The Apache Software Foundation
002: //
003: // Licensed under the Apache License, Version 2.0 (the "License");
004: // you may not use this file except in compliance with the License.
005: // You may obtain a copy of the License at
006: //
007: // http://www.apache.org/licenses/LICENSE-2.0
008: //
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014:
015: package org.apache.tapestry.ioc.internal.services;
016:
017: import static org.apache.tapestry.ioc.internal.util.Defense.notNull;
018:
019: import java.lang.reflect.Constructor;
020: import java.lang.reflect.Method;
021:
022: import javassist.CtClass;
023: import javassist.CtConstructor;
024: import javassist.CtMethod;
025:
026: import org.apache.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028: import org.apache.tapestry.ioc.Location;
029: import org.apache.tapestry.ioc.internal.util.InternalUtils;
030: import org.apache.tapestry.ioc.services.ClassFab;
031: import org.apache.tapestry.ioc.services.ClassFabUtils;
032: import org.apache.tapestry.ioc.services.ClassFactory;
033:
034: /**
035: * Implementation of {@link org.apache.tapestry.ioc.services.ClassFactory}.
036: */
037: public class ClassFactoryImpl implements ClassFactory {
038: private final Log _log;
039:
040: /**
041: * ClassPool shared by all modules (all CtClassSource instances).
042: */
043: private final ClassFactoryClassPool _pool;
044:
045: private final CtClassSource _classSource;
046:
047: private final ClassLoader _loader;
048:
049: public ClassFactoryImpl(ClassLoader classLoader) {
050: this (classLoader, LogFactory.getLog(ClassFactoryImpl.class));
051: }
052:
053: public ClassFactoryImpl() {
054: this (Thread.currentThread().getContextClassLoader());
055: }
056:
057: /** Main constructor where a specific class loader and log is provided. */
058: public ClassFactoryImpl(ClassLoader classLoader, Log log) {
059: this (classLoader, new ClassFactoryClassPool(classLoader), log);
060: }
061:
062: /** Special constructor used when the class pool is provided externally. */
063: public ClassFactoryImpl(ClassLoader classLoader,
064: ClassFactoryClassPool pool, Log log) {
065: _loader = classLoader;
066:
067: _pool = pool;
068:
069: _classSource = new CtClassSource(_pool, classLoader);
070:
071: _log = log;
072: }
073:
074: public ClassFab newClass(Class serviceInterface) {
075: String name = ClassFabUtils.generateClassName(serviceInterface);
076:
077: ClassFab cf = newClass(name, Object.class);
078:
079: cf.addInterface(serviceInterface);
080:
081: return cf;
082: }
083:
084: public ClassFab newClass(String name, Class super Class) {
085: if (_log.isDebugEnabled())
086: _log.debug(String.format(
087: "Create ClassFab for %s (extends %s)", name,
088: super Class.getName()));
089:
090: try {
091: CtClass ctNewClass = _classSource
092: .newClass(name, super Class);
093:
094: return new ClassFabImpl(_classSource, ctNewClass, _log);
095: } catch (Exception ex) {
096: throw new RuntimeException(ServiceMessages
097: .unableToCreateClass(name, super Class, ex), ex);
098: }
099: }
100:
101: public Class importClass(Class clazz) {
102: return _pool.importClass(clazz);
103: }
104:
105: public int getCreatedClassCount() {
106: return _classSource.getCreatedClassCount();
107: }
108:
109: public ClassLoader getClassLoader() {
110: return _loader;
111: }
112:
113: public Location getMethodLocation(Method method) {
114: notNull(method, "method");
115:
116: // TODO: Is it worth caching this? Probably not as it usually is only
117: // invoked perhaps at startup and in the event of errors.
118:
119: Class declaringClass = method.getDeclaringClass();
120: Class effectiveClass = importClass(declaringClass);
121:
122: CtClass ctClass = _classSource.getCtClass(effectiveClass);
123:
124: StringBuilder builder = new StringBuilder("(");
125:
126: for (Class parameterType : method.getParameterTypes()) {
127: builder.append(ClassFabUtils.getTypeCode(parameterType));
128: }
129:
130: builder.append(")");
131: builder.append(ClassFabUtils
132: .getTypeCode(method.getReturnType()));
133:
134: try {
135: CtMethod ctMethod = ctClass.getMethod(method.getName(),
136: builder.toString());
137:
138: int lineNumber = ctMethod.getMethodInfo().getLineNumber(0);
139:
140: String sourceFile = ctMethod.getDeclaringClass()
141: .getClassFile2().getSourceFile();
142:
143: String description = String.format("%s (at %s:%d)",
144: InternalUtils.asString(method), sourceFile,
145: lineNumber);
146:
147: return new StringLocation(description, lineNumber);
148: } catch (Exception ex) {
149: return new StringLocation(InternalUtils.asString(method), 0);
150: }
151: }
152:
153: public Location getConstructorLocation(Constructor constructor) {
154: notNull(constructor, "constructor");
155:
156: StringBuilder builder = new StringBuilder();
157:
158: Class declaringClass = constructor.getDeclaringClass();
159:
160: builder.append(declaringClass.getName());
161: builder.append("(");
162:
163: CtClass ctClass = _classSource.getCtClass(declaringClass);
164:
165: StringBuilder descripton = new StringBuilder("(");
166:
167: Class[] parameterTypes = constructor.getParameterTypes();
168: for (int i = 0; i < parameterTypes.length; i++) {
169: Class parameterType = parameterTypes[i];
170:
171: if (i > 0)
172: builder.append(", ");
173:
174: builder.append(parameterType.getSimpleName());
175:
176: descripton.append(ClassFabUtils.getTypeCode(parameterType));
177: }
178:
179: builder.append(")");
180:
181: // A constructor resembles a method of type void
182: descripton.append(")V");
183:
184: int lineNumber = 0;
185:
186: try {
187: CtConstructor ctConstructor = ctClass
188: .getConstructor(descripton.toString());
189:
190: lineNumber = ctConstructor.getMethodInfo().getLineNumber(0);
191:
192: String sourceFile = ctConstructor.getDeclaringClass()
193: .getClassFile2().getSourceFile();
194:
195: builder.append(String.format(" (at %s:%d)", sourceFile,
196: lineNumber));
197: } catch (Exception ex) {
198: }
199:
200: return new StringLocation(builder.toString(), lineNumber);
201: }
202: }
|