/******************************************************************************* * Copyright (c) 2001, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jst.j2ee.ejb.internal.util; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.jem.java.Field; import org.eclipse.jem.java.JavaClass; import org.eclipse.jem.java.JavaHelpers; import org.eclipse.jem.java.JavaParameter; import org.eclipse.jem.java.JavaVisibilityKind; import org.eclipse.jem.java.Method; import org.eclipse.jst.j2ee.ejb.ContainerManagedEntity; import org.eclipse.jst.j2ee.internal.J2EEVersionConstants; public class CMPHelper { public static final String GET = "get"; //$NON-NLS-1$ public static final String SET = "set"; //$NON-NLS-1$ protected static Comparator methodComparator = new Comparator() { /** * @see Comparator#compare(Object, Object) */ public int compare(Object o1, Object o2) { Method m1 = (Method) o1; Method m2 = (Method) o2; String s1 = m1.getName(); String s2 = m2.getName(); if (s1 == null) return "".compareTo(s2); //$NON-NLS-1$ return s1.compareTo(s2); } }; public interface CMPFieldExistTester { boolean isExisting(Field aField); boolean isExisting(Method aMethod); } protected CMPHelper() { super(); } /** * For CMP 2.0 beans, the bean class is abstract and * contains abstract get/set methods for the fields * This infers the those fields based on the get/set methods * * @return java.util.List of {@link CMPFieldDescriptor} */ public static List getAvailableCMP20FieldDescriptors(JavaClass beanClass) { return getAvailableCMP20FieldDescriptors(beanClass, null); } /** * For CMP 2.0 beans, the bean class is abstract and * contains abstract get/set methods for the fields * This infers the those fields based on the get/set methods * * @return java.util.List of {@link CMPFieldDescriptor} */ public static List getAvailableCMP20FieldDescriptors(JavaClass beanClass, CMPHelper.CMPFieldExistTester fieldTester) { if (beanClass == null) return Collections.EMPTY_LIST; List result = new ArrayList(); Map getters = new HashMap(); List methods = beanClass.getPublicMethodsExtended(); Collections.sort(methods, methodComparator); for (int i = 0; i < methods.size(); i++) { Method aMethod = (Method) methods.get(i); if (isGetter(aMethod) && aMethod.isAbstract() && !aMethod.isStatic() && (fieldTester == null || fieldTester.isExisting(aMethod))) getters.put(getFieldName(aMethod), aMethod); else if (isSetter(aMethod) && aMethod.isAbstract() && !aMethod.isStatic()) { String fieldName = getFieldName(aMethod); Method getter = (Method) getters.get(fieldName); if (typesAgree(getter, aMethod)) { String typeName = getReturnTypeName(getter); if (typeName != null && (fieldTester == null || fieldTester.isExisting(getter))) result.add(createFieldDescriptor(fieldName, typeName)); } } } return result; } /** * For CMP 1.1 beans, the list is simply the fields, extended, * on the bean class * * @return java.util.List of {@link CMPFieldDescriptor} */ public static List getAvailableCMP11FieldDescriptors(JavaClass beanClass) { return getAvailableCMP11FieldDescriptors(beanClass, null); } /** * For CMP 1.1 beans, the list is simply the fields, extended, * on the bean class * * @return java.util.List of {@link CMPFieldDescriptor} */ public static List getAvailableCMP11FieldDescriptors(JavaClass beanClass, CMPHelper.CMPFieldExistTester fieldTester) { if (beanClass == null) return Collections.EMPTY_LIST; List fields = beanClass.getFieldsExtended(); List result = new ArrayList(); for (int i = 0; i < fields.size(); i++) { Field aField = (Field) fields.get(i); if (!isPublic(aField) || aField.isStatic() || aField.isTransient() || (fieldTester != null && !fieldTester.isExisting(aField))) continue; String name = aField.getName(); String typeName = getTypeName(aField); if (typeName != null && name != null) result.add(createFieldDescriptor(name, typeName)); } return result; } /** * Get a list of available cmp fields for the CMP bean; if the bean * is v1.1, this is the fields on the bean class; if it is 2.0, this * is defined by the abstract get/set methods on the bean class * * @return java.util.List of {@link CMPFieldDescriptor} */ public static List getAvailableCMPFieldDescriptors(ContainerManagedEntity cmpBean) { return getAvailableCMPFieldDescriptors(cmpBean, null); } /** * Get a list of available cmp fields for the CMP bean; if the bean * is v1.1, this is the fields on the bean class; if it is 2.0, this * is defined by the abstract get/set methods on the bean class * * @return java.util.List of {@link CMPFieldDescriptor} */ public static List getAvailableCMPFieldDescriptors(ContainerManagedEntity cmpBean, CMPHelper.CMPFieldExistTester fieldTester) { JavaClass beanClass = cmpBean.getEjbClass(); if (beanClass == null) return Collections.EMPTY_LIST; switch(cmpBean.getVersionID()) { case J2EEVersionConstants.EJB_1_0_ID: case J2EEVersionConstants.EJB_1_1_ID: return getAvailableCMP11FieldDescriptors(beanClass, fieldTester); case J2EEVersionConstants.EJB_2_0_ID: case J2EEVersionConstants.EJB_2_1_ID: default: return getAvailableCMP20FieldDescriptors(beanClass, fieldTester); } } /** * Does the method name start with "get", and is the method a zero arg * method, that does not return void? */ protected static boolean isGetter(Method aMethod) { String name = aMethod.getName(); return name != null && name.startsWith(GET) && name.length() > 3 && aMethod.listParametersWithoutReturn().length==0 && !aMethod.isVoid(); } /** * Does the method name start with "get", and is the method a one arg * method, that is void */ protected static boolean isSetter(Method aMethod) { String name = aMethod.getName(); return name != null && name.startsWith(SET) && name.length() > 3 && aMethod.listParametersWithoutReturn().length == 1 && aMethod.isVoid(); } protected static String getFieldName(Method aMethod) { if (aMethod == null) return null; return getFieldName(aMethod.getName()); } public static String getFieldName(String methodName) { if (methodName == null) return null; StringBuffer sb = new StringBuffer(methodName); sb.delete(0, 3); char lower = Character.toLowerCase(sb.charAt(0)); sb.setCharAt(0, lower); return sb.toString(); } protected static String getReturnTypeName(Method getter) { if (getter == null) return null; JavaHelpers retType = getter.getReturnType(); return getTypeName(retType); } protected static String getTypeName(Field aField) { if (aField == null) return null; JavaHelpers type = (JavaHelpers)aField.getEType(); return getTypeName(type); } protected static String getTypeName(JavaHelpers helpers) { if (helpers == null) return null; return helpers.getQualifiedName(); } /** * Precondition: setter must take one parameter, and getter must return * a type, not void */ protected static boolean typesAgree(Method getter, Method setter) { if (getter == null || getter.isVoid() || setter == null) return false; JavaParameter[] parameters = setter.listParametersWithoutReturn(); if (parameters.length != 1) return false; JavaParameter param = parameters[0]; return param.getEType() != null && param.getEType() == getter.getReturnType(); } protected static CMPFieldDescriptor createFieldDescriptor(String name, String typeName) { CMPFieldDescriptor desc = new CMPFieldDescriptor(); desc.setName(name); desc.setType(typeName); return desc; } protected static boolean isPublic(Field field) { if (field == null) return false; return (JavaVisibilityKind.PUBLIC_LITERAL.getValue() == field.getJavaVisibility().getValue()); } }