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