001
014
015 package com.liferay.portal.bean;
016
017 import com.liferay.portal.kernel.bean.ConstantsBeanFactory;
018 import com.liferay.portal.kernel.memory.EqualityWeakReference;
019 import com.liferay.portal.kernel.util.ReflectionUtil;
020
021 import java.lang.ref.Reference;
022 import java.lang.ref.ReferenceQueue;
023 import java.lang.ref.WeakReference;
024 import java.lang.reflect.Field;
025 import java.lang.reflect.Method;
026 import java.lang.reflect.Modifier;
027
028 import java.util.concurrent.ConcurrentHashMap;
029 import java.util.concurrent.ConcurrentMap;
030
031 import org.objectweb.asm.ClassWriter;
032 import org.objectweb.asm.MethodVisitor;
033 import org.objectweb.asm.Opcodes;
034 import org.objectweb.asm.Type;
035
036
039 public class ConstantsBeanFactoryImpl implements ConstantsBeanFactory {
040
041 public Object getConstantsBean(Class<?> constantsClass) {
042 Reference<?> constantsBeanReference = constantsBeans.get(
043 new EqualityWeakReference<Class<?>>(constantsClass));
044
045 Object constantsBean = null;
046
047 if (constantsBeanReference != null) {
048 constantsBean = constantsBeanReference.get();
049 }
050
051 if (constantsBean == null) {
052 constantsBean = createConstantsBean(constantsClass);
053
054 constantsBeans.put(
055 new EqualityWeakReference<Class<?>>(
056 constantsClass, constantsClassReferenceQueue),
057 new WeakReference<Object>(constantsBean));
058 }
059
060 while (true) {
061 EqualityWeakReference<Class<?>> staleConstantsClassReference =
062 (EqualityWeakReference<Class<?>>)
063 constantsClassReferenceQueue.poll();
064
065 if (staleConstantsClassReference == null) {
066 break;
067 }
068
069 constantsBeans.remove(staleConstantsClassReference);
070 }
071
072 return constantsBean;
073 }
074
075 protected static Object createConstantsBean(Class<?> constantsClass) {
076 ClassLoader classLoader = constantsClass.getClassLoader();
077
078 String constantsBeanClassName = constantsClass.getName() + "Bean";
079
080 Class<?> constantsBeanClass = null;
081
082 synchronized (classLoader) {
083 try {
084 constantsBeanClass = classLoader.loadClass(
085 constantsBeanClassName);
086 }
087 catch (ClassNotFoundException cnfe) {
088 }
089
090 try {
091 if (constantsBeanClass == null) {
092 Method defineClassMethod = ReflectionUtil.getDeclaredMethod(
093 ClassLoader.class, "defineClass", String.class,
094 byte[].class, int.class, int.class);
095
096 byte[] classData = generateConstantsBeanClassData(
097 constantsClass);
098
099 constantsBeanClass = (Class<?>)defineClassMethod.invoke(
100 classLoader, constantsBeanClassName, classData, 0,
101 classData.length);
102 }
103
104 return constantsBeanClass.newInstance();
105 }
106 catch (Exception e) {
107 throw new RuntimeException(e);
108 }
109 }
110 }
111
112 protected static byte[] generateConstantsBeanClassData(
113 Class<?> constantsClass) {
114
115 String constantsClassBinaryName = getClassBinaryName(constantsClass);
116
117 String constantsBeanClassBinaryName = constantsClassBinaryName + "Bean";
118
119 String objectClassBinaryName = getClassBinaryName(Object.class);
120
121 ClassWriter classWriter = new ClassWriter(0);
122
123 classWriter.visit(
124 Opcodes.V1_5, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER,
125 constantsBeanClassBinaryName, null, objectClassBinaryName, null);
126
127 MethodVisitor methodVisitor = classWriter.visitMethod(
128 Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
129
130 methodVisitor.visitCode();
131 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
132 methodVisitor.visitMethodInsn(
133 Opcodes.INVOKESPECIAL, objectClassBinaryName, "<init>", "()V");
134 methodVisitor.visitInsn(Opcodes.RETURN);
135 methodVisitor.visitMaxs(1, 1);
136 methodVisitor.visitEnd();
137
138 Field[] fields = constantsClass.getFields();
139
140 for (Field field :fields) {
141 if (Modifier.isStatic(field.getModifiers())) {
142 Class<?> fieldClass = field.getType();
143
144 Type fieldType = Type.getType(fieldClass);
145
146 methodVisitor = classWriter.visitMethod(
147 Opcodes.ACC_PUBLIC, "get" + field.getName(),
148 "()" + fieldType.getDescriptor(), null, null);
149
150 methodVisitor.visitCode();
151 methodVisitor.visitFieldInsn(
152 Opcodes.GETSTATIC, constantsClassBinaryName,
153 field.getName(), fieldType.getDescriptor());
154
155 int returnOpcode = Opcodes.ARETURN;
156
157 if (fieldClass.isPrimitive()) {
158 if (fieldClass == Float.TYPE) {
159 returnOpcode = Opcodes.FRETURN;
160 }
161 else if (fieldClass == Double.TYPE) {
162 returnOpcode = Opcodes.DRETURN;
163 }
164 else if (fieldClass == Long.TYPE) {
165 returnOpcode = Opcodes.LRETURN;
166 }
167 else {
168 returnOpcode = Opcodes.IRETURN;
169 }
170 }
171
172 methodVisitor.visitInsn(returnOpcode);
173
174 methodVisitor.visitMaxs(fieldType.getSize(), 1);
175 methodVisitor.visitEnd();
176 }
177 }
178
179 classWriter.visitEnd();
180
181 return classWriter.toByteArray();
182 }
183
184 protected static String getClassBinaryName(Class<?> clazz) {
185 String className = clazz.getName();
186
187 return className.replace('.', '/');
188 }
189
190 protected static ConcurrentMap
191 <EqualityWeakReference<Class<?>>, Reference<?>>
192 constantsBeans =
193 new ConcurrentHashMap
194 <EqualityWeakReference<Class<?>>, Reference<?>>();
195 protected static ReferenceQueue<Class<?>> constantsClassReferenceQueue =
196 new ReferenceQueue<Class<?>>();
197
198 }