001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.bean;
016    
017    import com.liferay.portal.kernel.bean.ConstantsBeanFactory;
018    import com.liferay.portal.kernel.concurrent.ConcurrentReferenceKeyHashMap;
019    import com.liferay.portal.kernel.concurrent.ConcurrentReferenceValueHashMap;
020    import com.liferay.portal.kernel.memory.FinalizeManager;
021    import com.liferay.portal.kernel.util.ReflectionUtil;
022    
023    import java.lang.ref.Reference;
024    import java.lang.reflect.Field;
025    import java.lang.reflect.Method;
026    import java.lang.reflect.Modifier;
027    
028    import java.util.concurrent.ConcurrentMap;
029    
030    import org.objectweb.asm.ClassWriter;
031    import org.objectweb.asm.MethodVisitor;
032    import org.objectweb.asm.Opcodes;
033    import org.objectweb.asm.Type;
034    
035    /**
036     * @author Shuyang Zhou
037     */
038    public class ConstantsBeanFactoryImpl implements ConstantsBeanFactory {
039    
040            @Override
041            public Object getConstantsBean(Class<?> constantsClass) {
042                    Object constantsBean = constantsBeans.get(constantsClass);
043    
044                    if (constantsBean == null) {
045                            constantsBean = createConstantsBean(constantsClass);
046    
047                            constantsBeans.put(constantsClass, constantsBean);
048                    }
049    
050                    return constantsBean;
051            }
052    
053            protected static Object createConstantsBean(Class<?> constantsClass) {
054                    ClassLoader classLoader = constantsClass.getClassLoader();
055    
056                    String constantsBeanClassName = constantsClass.getName() + "Bean";
057    
058                    Class<?> constantsBeanClass = null;
059    
060                    synchronized (classLoader) {
061                            try {
062                                    constantsBeanClass = classLoader.loadClass(
063                                            constantsBeanClassName);
064                            }
065                            catch (ClassNotFoundException cnfe) {
066                            }
067    
068                            try {
069                                    if (constantsBeanClass == null) {
070                                            Method defineClassMethod = ReflectionUtil.getDeclaredMethod(
071                                                    ClassLoader.class, "defineClass", String.class,
072                                                    byte[].class, int.class, int.class);
073    
074                                            byte[] classData = generateConstantsBeanClassData(
075                                                    constantsClass);
076    
077                                            constantsBeanClass = (Class<?>)defineClassMethod.invoke(
078                                                    classLoader, constantsBeanClassName, classData, 0,
079                                                    classData.length);
080                                    }
081    
082                                    return constantsBeanClass.newInstance();
083                            }
084                            catch (Throwable t) {
085                                    throw new RuntimeException(t);
086                            }
087                    }
088            }
089    
090            protected static byte[] generateConstantsBeanClassData(
091                    Class<?> constantsClass) {
092    
093                    String constantsClassBinaryName = getClassBinaryName(constantsClass);
094    
095                    String constantsBeanClassBinaryName = constantsClassBinaryName + "Bean";
096    
097                    String objectClassBinaryName = getClassBinaryName(Object.class);
098    
099                    ClassWriter classWriter = new ClassWriter(0);
100    
101                    classWriter.visit(
102                            Opcodes.V1_6, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER,
103                            constantsBeanClassBinaryName, null, objectClassBinaryName, null);
104    
105                    MethodVisitor methodVisitor = classWriter.visitMethod(
106                            Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
107    
108                    methodVisitor.visitCode();
109                    methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
110                    methodVisitor.visitMethodInsn(
111                            Opcodes.INVOKESPECIAL, objectClassBinaryName, "<init>", "()V",
112                            false);
113                    methodVisitor.visitInsn(Opcodes.RETURN);
114                    methodVisitor.visitMaxs(1, 1);
115                    methodVisitor.visitEnd();
116    
117                    Field[] fields = constantsClass.getFields();
118    
119                    for (Field field :fields) {
120                            if (Modifier.isStatic(field.getModifiers())) {
121                                    Type fieldType = Type.getType(field.getType());
122    
123                                    methodVisitor = classWriter.visitMethod(
124                                            Opcodes.ACC_PUBLIC, "get" + field.getName(),
125                                            "()" + fieldType.getDescriptor(), null, null);
126    
127                                    methodVisitor.visitCode();
128                                    methodVisitor.visitFieldInsn(
129                                            Opcodes.GETSTATIC, constantsClassBinaryName,
130                                            field.getName(), fieldType.getDescriptor());
131    
132                                    methodVisitor.visitInsn(fieldType.getOpcode(Opcodes.IRETURN));
133    
134                                    methodVisitor.visitMaxs(fieldType.getSize(), 1);
135                                    methodVisitor.visitEnd();
136                            }
137                    }
138    
139                    classWriter.visitEnd();
140    
141                    return classWriter.toByteArray();
142            }
143    
144            protected static String getClassBinaryName(Class<?> clazz) {
145                    String className = clazz.getName();
146    
147                    return className.replace('.', '/');
148            }
149    
150            protected static ConcurrentMap<Class<?>, Object> constantsBeans =
151                    new ConcurrentReferenceKeyHashMap<Class<?>, Object>(
152                            new ConcurrentReferenceValueHashMap<Reference<Class<?>>, Object>(
153                                    FinalizeManager.WEAK_REFERENCE_FACTORY),
154                            FinalizeManager.WEAK_REFERENCE_FACTORY);
155    
156    }