Package ns.foundation

Source Code of ns.foundation._NSPropertyAccessor$_LegacyCompatibleKeyBinding

package ns.foundation;

import java.util.concurrent.ConcurrentHashMap;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMember;
import javassist.CtMethod;
import javassist.CtPrimitiveType;
import javassist.NotFoundException;
import javassist.bytecode.AccessFlag;
import ns.foundation.NSKeyValueCoding._KeyBinding;
import ns.foundation.NSKeyValueCoding._KeyBindingCreation._KeyBindingFactory;
import ns.foundation.NSKeyValueCoding._KeyBindingCreation._KeyBindingFactory._BindingStorage;

public class _NSPropertyAccessor {
  private static final _KeyBinding  _NotAvailableIndicator = new NSKeyValueCoding._KeyBinding(null, null);
  private static final ConcurrentHashMap<_KeyBinding, _BindingStorage>  _bindingStorageMapTable     = new ConcurrentHashMap<_KeyBinding, _BindingStorage>(256);
  private static ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

  private static int counter = 0
  private ClassPool ctPool;
  private Object targetObject;
  private Class<?> targetClass;
  private CtClass targetCtClass;
 

  public _NSPropertyAccessor(Object object) {
    targetObject = object;
    targetClass = object.getClass();
    ctPool = new ClassPool();
    ctPool.appendSystemPath();
    try {
      targetCtClass = ctPool.getCtClass(targetClass.getName());
    } catch (NotFoundException e) {
      throw new NSForwardException(e);
    }

  }
 
  public static void _flushCaches() {
    _bindingStorageMapTable.clear();
  }
 
  public static boolean _canAccessFieldsDirectlyForClass(Class<?> objectClass) {
    //return _NSReflectionUtilities._staticBooleanMethodValue("canAccessFieldsDirectly", null, null, objectClass, NSKeyValueCoding.class, true);
    return true;
  }

  protected static class _LegacyCompatibleKeyBinding extends _KeyBinding {
    private final _KeyBinding _delegate;
    private Class<?> _valueType;
   
    _LegacyCompatibleKeyBinding(_KeyBinding keyBinding) {
      super(keyBinding.targetClass(), keyBinding.key());
      _delegate = keyBinding;
    }

    @Override
    public boolean isScalarProperty() {
      return _delegate.isScalarProperty();
    }
   
    @Override
    public void setValueInObject(Object value, Object object) {
      _delegate.setValueInObject(value, object);
    }
   
    @Override
    public Class<?> valueType() {
      if (_valueType == null) {
        Class<?> valueType = _delegate.valueType();
        if (valueType.isPrimitive() && _NSUtilities._isClassANumberOrABoolean(valueType)) {
          valueType = _NSUtilities.classObjectForClass(valueType);
        }
        _valueType = valueType;
      }
      return _valueType;
    }
   
    @Override
    public Object valueInObject(Object object) {
      return _delegate.valueInObject(object);
    }
   
    @Override
    public String toString() {
      return _delegate.toString();
    }
  }
 
  public static _KeyBinding _createKeyBindingForKey(Object object, String key, int lookupOrder[], boolean trueForSetAndFalseForGet) {
    _KeyBinding keyBinding = new _NSPropertyAccessor(object)._createKeyBindingForKey(key, lookupOrder, trueForSetAndFalseForGet);
    return keyBinding == null ? null : new _LegacyCompatibleKeyBinding(keyBinding);
  }

  private NSKeyValueCoding._KeyBinding _createKeyBindingForKey(String key, int[] lookupOrder, boolean trueForSetAndFalseForGet) {
    if ((key == null) || (key.length() == 0)) {
      return null;
    }

    Class<?> objectClass = targetObject.getClass();

    boolean canAccessFieldsDirectlyTestPerformed = false;
    boolean canAccessFieldsDirectly = false;

    // we use a KeyBinding as key for the _BindingStorage object map table since it gives us exactly what we need: a class and a key - but we have to create a new lookup key binding to avoid synchronizing the read lookup (and we need a new instance for the write access)
    NSKeyValueCoding._KeyBinding lookupBinding = new NSKeyValueCoding._KeyBinding(objectClass, key);
    _BindingStorage bindingStorage = _bindingStorageMapTable.get(lookupBinding);
    if (bindingStorage == null) {
      bindingStorage = new _KeyBindingFactory._BindingStorage();
      _bindingStorageMapTable.put(lookupBinding, bindingStorage);
    }

    _KeyBindingFactory.Callback keyBindingCreationCallbackObject = (targetObject instanceof _KeyBindingFactory.Callback) ? (_KeyBindingFactory.Callback) targetObject
        : null;
    NSKeyValueCoding._KeyBinding keyBindings[] = (trueForSetAndFalseForGet) ? bindingStorage._keySetBindings : bindingStorage._keyGetBindings;
    for (int i = 0; i < lookupOrder.length; i++) {
      int lookup = lookupOrder[i];
      NSKeyValueCoding._KeyBinding keyBinding = ((lookup >= _KeyBindingFactory.MethodLookup) && (lookup <= _KeyBindingFactory.UnderbarFieldLookup)) ? keyBindings[lookup] : null;
      if (keyBinding == null) {
        Class<?> valueType = null;
        if (trueForSetAndFalseForGet) {
          _KeyBinding getKeyBinding = _createKeyBindingForKey(key, lookupOrder, false);
          valueType = getKeyBinding != null ? getKeyBinding.valueType() : null;
        }

        switch (lookup) {
          case _KeyBindingFactory.MethodLookup:
            String methodName = prefixedKey((trueForSetAndFalseForGet) ? "set" : "get", key);

            if (trueForSetAndFalseForGet) {
              // look up 'setKey'
              keyBinding = (keyBindingCreationCallbackObject != null) ? keyBindingCreationCallbackObject._methodKeySetBinding(key, methodName)
                  : _methodKeySetBinding(key, methodName, valueType);
            } else {
              // look up 'getKey'
              keyBinding = (keyBindingCreationCallbackObject != null) ? keyBindingCreationCallbackObject._methodKeyGetBinding(key, methodName)
                  : _methodKeyGetBinding(key, methodName);

              if (keyBinding == null) {
                // look up 'key'
                keyBinding = (keyBindingCreationCallbackObject != null) ? keyBindingCreationCallbackObject._methodKeyGetBinding(key, key)
                    : _methodKeyGetBinding(key, key);
              }

              if (keyBinding == null) {
                // look up 'isKey'
                methodName = new String(prefixedKey("is", key));
                keyBinding = (keyBindingCreationCallbackObject != null) ? keyBindingCreationCallbackObject._methodKeyGetBinding(key, methodName)
                    : _methodKeyGetBinding(key, methodName);
              }
            }
            break;
          case _KeyBindingFactory.UnderbarMethodLookup:
            String underbarMethodName = prefixedKey((trueForSetAndFalseForGet) ? "_set" : "_get", key);

            if (trueForSetAndFalseForGet) {
              // look up '_setKey'
              keyBinding = (keyBindingCreationCallbackObject != null) ? keyBindingCreationCallbackObject._methodKeySetBinding(key, underbarMethodName)
                  : _methodKeySetBinding(key, underbarMethodName, valueType);
            } else {
              // look up '_getKey'
              keyBinding = (keyBindingCreationCallbackObject != null) ? keyBindingCreationCallbackObject._methodKeyGetBinding(key, underbarMethodName)
                  : _methodKeyGetBinding(key, underbarMethodName);

              if (keyBinding == null) {
                // look up '_key'
                underbarMethodName = prefixedKey("_", key);
                keyBinding = (keyBindingCreationCallbackObject != null) ? keyBindingCreationCallbackObject._methodKeyGetBinding(key, underbarMethodName)
                    : _methodKeyGetBinding(key, underbarMethodName);
              }

              if (keyBinding == null) {
                // look up '_isKey'
                underbarMethodName = prefixedKey("_is", key);
                keyBinding = (keyBindingCreationCallbackObject != null) ? keyBindingCreationCallbackObject._methodKeyGetBinding(key, underbarMethodName)
                    : _methodKeyGetBinding(key, underbarMethodName);
              }
            }
            break;
          case _KeyBindingFactory.FieldLookup:
            if (!canAccessFieldsDirectlyTestPerformed) {
              canAccessFieldsDirectlyTestPerformed = true;
              canAccessFieldsDirectly = _canAccessFieldsDirectlyForClass(objectClass);
            }
            if (canAccessFieldsDirectly) {
              // look up 'key'
              keyBinding = (keyBindingCreationCallbackObject != null) ? keyBindingCreationCallbackObject._fieldKeyBinding(key, key)
                  : _fieldKeyBinding(key, key);

              if (keyBinding == null) {
                // look up 'isKey'
                String fieldName = prefixedKey("is", key);
                keyBinding = (keyBindingCreationCallbackObject != null) ? keyBindingCreationCallbackObject._fieldKeyBinding(key, fieldName)
                    : _fieldKeyBinding(key, fieldName);
              }
            }
            break;
          case _KeyBindingFactory.UnderbarFieldLookup:
            if (!canAccessFieldsDirectlyTestPerformed) {
              canAccessFieldsDirectlyTestPerformed = true;
              canAccessFieldsDirectly = _canAccessFieldsDirectlyForClass(objectClass);
            }
            if (canAccessFieldsDirectly) {
              // look up '_key'
              String underbarFieldName = prefixedKey("_", key);
              keyBinding = (keyBindingCreationCallbackObject != null) ? keyBindingCreationCallbackObject._fieldKeyBinding(key, underbarFieldName)
                  : _fieldKeyBinding(key, underbarFieldName);

              if (keyBinding == null) {
                // look up '_isKey'
                underbarFieldName = prefixedKey("_is", key);
                keyBinding = (keyBindingCreationCallbackObject != null) ? keyBindingCreationCallbackObject._fieldKeyBinding(key, underbarFieldName)
                    : _fieldKeyBinding(key, underbarFieldName);
              }
            }
            break;
          case _KeyBindingFactory.OtherStorageLookup:
            keyBinding = (keyBindingCreationCallbackObject != null) ? keyBindingCreationCallbackObject._otherStorageBinding(key) : null;
            break;
        }

        if (keyBinding == null) {
          keyBinding = _NotAvailableIndicator;
        }
        if ((lookup == _KeyBindingFactory.FieldLookup) || (lookup == _KeyBindingFactory.UnderbarFieldLookup)) {
          // set and get bindings are the same for fields (but not for methods since the name of set and get methods are actually different)
          bindingStorage._keySetBindings[lookup] = bindingStorage._keyGetBindings[lookup] = keyBinding;
        } else if ((lookup == _KeyBindingFactory.MethodLookup) || (lookup == _KeyBindingFactory.UnderbarMethodLookup)) {
          keyBindings[lookup] = keyBinding;
        }
      }

      if ((keyBinding != null) && (keyBinding != _NotAvailableIndicator)) {
        return keyBinding;
      }
    }
    return null;
  }

  public NSKeyValueCoding._KeyBinding _fieldKeyBinding(String key, String fieldName) {
    Class<?> objectClass = targetObject.getClass();
    NSKeyValueCoding.ValueAccessor valueAccessor = NSKeyValueCoding.ValueAccessor._valueAccessorForClass(objectClass);
    boolean publicFieldOnly = (valueAccessor == null);

    try {
      CtField field = targetCtClass.getField(fieldName);
      if ((publicFieldOnly && !AccessFlag.isPublic(field.getModifiers()))
          || AccessFlag.isPrivate((field.getModifiers()))) {
        return null;
      }
     
      CtClass valueType = field.getType();
      CtClass wrapper = _keyBindingClassForMember(key, field);

      CtMethod getter = CtMethod.make("public Object valueInObject(Object object) {"
          + "return " + box(valueType, unbox(targetCtClass, "object") "." + fieldName) + "; }", wrapper);
     
      StringBuffer code = new StringBuffer("public void setValueInObject(Object value, Object object) {");
      if (valueType.isPrimitive()) {
        code.append("if (value == null) {");
        code.append(NSKeyValueCoding.Utility.class.getName() + ".unableToSetNullForKey(object,\"" + key + "\");");
        code.append("return; }");
      }
      code.append("((" + field.getDeclaringClass().getName() +")object)." + fieldName + " = "+ convert(valueType, "value") + "; }");
      CtMethod setter = CtMethod.make(code.toString(), wrapper);

      wrapper.addMethod(getter);
      wrapper.addMethod(setter);
      _addMethodsForValueType(wrapper, valueType, valueType.isPrimitive());
     
      @SuppressWarnings("unchecked")
      Class<_KeyBinding> wrapperClass = wrapper.toClass(classLoader, getClass().getProtectionDomain());
      _KeyBinding binding = wrapperClass.newInstance();
      return binding;
    } catch (NotFoundException e) {
      return null;
    } catch (Exception e) {
      throw new NSForwardException(e);
    }
  }
 
  public NSKeyValueCoding._KeyBinding _methodKeyGetBinding(String key, String methodName) {
    Class<?> objectClass = targetObject.getClass();
    NSKeyValueCoding.ValueAccessor valueAccessor = NSKeyValueCoding.ValueAccessor._valueAccessorForClass(objectClass);
    boolean publicMethodOnly = (valueAccessor == null);
   
    try {
      CtMethod method = null;
      for (CtMethod target : targetCtClass.getMethods()) {
        if (!target.getName().equals(methodName)
            || target.getParameterTypes().length != 0) {
          continue;
        }
        if (( publicMethodOnly && !AccessFlag.isPublic(target.getModifiers()))
            || (AccessFlag.isPrivate(target.getModifiers()))) {
          continue;
        }
        method = target;
        break;
      }
      if (method == null) {
        return null;
      }
      CtClass valueType = method.getReturnType();
      CtClass wrapper = _keyBindingClassForMember(key, method);
      CtMethod getter = CtMethod.make("public Object valueInObject(Object object) {"
          + "return " + box(valueType, unbox(method.getDeclaringClass(), "object") + "." + methodName + "()") + "; }", wrapper);
     
      wrapper.addMethod(getter);
      _addMethodsForValueType(wrapper, valueType, false);

      @SuppressWarnings("unchecked")
      Class<_KeyBinding> wrapperClass = wrapper.toClass(classLoader, getClass().getProtectionDomain());
      _KeyBinding binding = wrapperClass.newInstance();
      return binding;
    } catch (NotFoundException e) {
      return null;
    } catch (Exception e) {
      throw new NSForwardException(e);
    }
  }

  public NSKeyValueCoding._KeyBinding _methodKeySetBinding(String key, String methodName, Class<?> targetValueType) {
    Class<?> objectClass = targetObject.getClass();
    NSKeyValueCoding.ValueAccessor valueAccessor = NSKeyValueCoding.ValueAccessor._valueAccessorForClass(objectClass);
    boolean publicMethodOnly = (valueAccessor == null);
    if (targetValueType == null) {
      targetValueType = Object.class;
    }
    try {
      CtMethod method = null;
      for (CtMethod target : targetCtClass.getMethods()) {
        if (!target.getName().equals(methodName) || target.getParameterTypes().length != 1) {
          continue;
        }

        if ((publicMethodOnly && !AccessFlag.isPublic(target.getModifiers()))
            || AccessFlag.isPrivate(target.getModifiers())) {
          continue;
        }
        CtClass clazz = target.getParameterTypes()[0];
        if (clazz.getName().equals(targetValueType.getName())) {
          method = target;
          break;
        }
        else if (boxedTypeName(clazz).equals(_NSUtilities.classObjectForClass(targetValueType).getName())) {
          method = target;
        }
        else if (method == null) {
          method = target;
        }
      }
     
      if (method == null) {
        return null;
      }
      CtClass valueType = method.getParameterTypes()[0];
      StringBuffer code = new StringBuffer ("public void setValueInObject(Object value, Object object) {");
      if (valueType.isPrimitive()) {
        code.append("if (value == null) {");
        code.append(NSKeyValueCoding.Utility.class.getName() + ".unableToSetNullForKey(object,\"" + key + "\");");
        code.append("return; }");
      }
      code.append(unbox(method.getDeclaringClass(), "object") + "." + methodName + "("+ convert(valueType, "value") +"); }");
      CtClass wrapper = _keyBindingClassForMember(key, method);
      CtMethod setter = CtMethod.make(code.toString(), wrapper);

      wrapper.addMethod(setter);
      _addMethodsForValueType(wrapper, valueType, valueType.isPrimitive());
     
      @SuppressWarnings("unchecked")
      Class<_KeyBinding> wrapperClass = wrapper.toClass(classLoader, getClass().getProtectionDomain());
      _KeyBinding binding = wrapperClass.newInstance();
      return binding;
    } catch (NotFoundException e) {
      return null;
    } catch (Exception e) {
      throw new NSForwardException(e);
    }
  }
 
  private CtClass _keyBindingClassForMember(String key, CtMember member) {
    try {
      String declaringClassName = member.getDeclaringClass().getName();
      CtClass ctAccessor = ctPool.getCtClass(_KeyBinding.class.getName());
      String wrapperName = declaringClassName + "$" + key + "$KVCWrapper" + counter++;
      if (targetClass.getPackage().getName().startsWith("java.")) {
        wrapperName = "com.webobjects.kvc." + wrapperName;
      }
      CtClass wrapper = ctPool.makeClass(wrapperName, ctAccessor);
      CtConstructor c = new CtConstructor(new CtClass[0], wrapper);
      c.setBody("super(" + targetCtClass.getName() +".class, \"" + key + "\");");
      wrapper.addConstructor(c);
      return wrapper;
    } catch (Exception e) {
      throw new NSForwardException(e);
    }
  }
 
  private void _addMethodsForValueType(CtClass wrapper, CtClass valueType, boolean isScalar) throws CannotCompileException {
    if (valueType != null) {
      StringBuffer code = new StringBuffer("public Class valueType() {");
      if (valueType.isPrimitive()) {
        code.append("return " + boxedTypeName(valueType) + ".TYPE;");
      } else {
        code.append("return " + valueType.getName() + ".class;");
      }
      code.append("}");
      CtMethod vt = CtMethod.make(code.toString(), wrapper);
      wrapper.addMethod(vt);
     
      code = new StringBuffer("public boolean isScalarProperty() {");
      code.append(isScalar ? "return true;" :"return false;");
      code.append("}");
      CtMethod sp = CtMethod.make(code.toString(), wrapper);
      wrapper.addMethod(sp);
    }
  }
 
  private String box(CtClass type, String arg) {
    boolean isPrimitive = type.isPrimitive();
    if (isPrimitive && (type == CtClass.intType))
      return "(Integer.valueOf((int)" + arg + "))";
    if (isPrimitive && (type == CtClass.longType))
      return "(Long.valueOf((long)" + arg + "))";
    if (isPrimitive && (type == CtClass.shortType))
      return "(Short.valueOf((short)" + arg + "))";
    if (isPrimitive && (type == CtClass.floatType))
      return "(Float.valueOf((float)" + arg + "))";
    if (isPrimitive && (type == CtClass.doubleType))
      return "(Double.valueOf((double)" + arg + "))";
    if (isPrimitive && (type == CtClass.charType))
      return "(Character.valueOf((char)" + arg + "))";
    if (isPrimitive && (type == CtClass.byteType))
      return "(Byte.valueOf((byte)" + arg + "))";
    if (isPrimitive && (type == CtClass.booleanType))
      return "(Boolean.valueOf((boolean)" + arg + "))";
    return "((" + type.getName() + ") " + arg + ")";
  }

  private String unbox(CtClass type, String arg) {
    boolean isPrimitive = type.isPrimitive();
    if (isPrimitive && (type == CtClass.intType))
      return "((Number)" + arg + ").intValue()";
    if (isPrimitive && (type == CtClass.longType))
      return "((Number)" + arg + ").longValue()";
    if (isPrimitive && (type == CtClass.shortType))
      return "((Number)" + arg + ").shortValue()";
    if (isPrimitive && (type == CtClass.floatType))
      return "((Number)" + arg + ").floatValue()";
    if (isPrimitive && (type == CtClass.doubleType))
      return "((Number)" + arg + ").doubleValue()";
    if (isPrimitive && (type == CtClass.charType))
      return "((Character)" + arg + ").charValue()";
    if (isPrimitive && (type == CtClass.byteType))
      return "((Number)" + arg + ").byteValue()";
    if (isPrimitive && (type == CtClass.booleanType))
      return "((Boolean)" + arg + ").booleanValue()";
    return "((" + type.getName() + ") " + arg + ")";
  }
 
  private String convert(CtClass type, String arg) {
    String converted = "(" + _NSPropertyUtilities.class.getName()
          + ".convertObjectIntoCompatibleValue(" + arg + "," + boxedTypeName(type) + ".class" + "))";
    boolean isPrimitive = type.isPrimitive();
    if (isPrimitive && (type == CtClass.intType))
      return "((Number)" + converted + ").intValue()";
    if (isPrimitive && (type == CtClass.longType))
      return "((Number)" + converted + ").longValue()";
    if (isPrimitive && (type == CtClass.shortType))
      return "((Number)" + converted + ").shortValue()";
    if (isPrimitive && (type == CtClass.floatType))
      return "((Number)" + converted + ").floatValue()";
    if (isPrimitive && (type == CtClass.doubleType))
      return "((Number)" + converted + ").doubleValue()";
    if (isPrimitive && (type == CtClass.charType))
      return "((Character)" + converted + ").charValue()";
    if (isPrimitive && (type == CtClass.byteType))
      return "((Number)" + converted + ").byteValue()";
    if (isPrimitive && (type == CtClass.booleanType))
      return "((Boolean)" + converted + ").booleanValue()";
    if (_NSPropertyUtilities._isCtClassABoolean(type))
      return "((Boolean)" + converted + ")";
    if (_NSPropertyUtilities._isCtClassANumber(type))
      return "((Number)" + converted + ")";
    return "((" + type.getName() + ") " + converted + ")";
  }
 
  private String boxedTypeName(CtClass type) {
    if (type.isPrimitive())
      return ((CtPrimitiveType)type).getWrapperName();
    return type.getName();
  }
 
  private String prefixedKey(String prefix, String key) {
    if (prefix == null) {
      return key;
    }
    StringBuffer sb = new StringBuffer(prefix.length() + key.length());
    sb.append(prefix);
    if ("_".equals(prefix)) {
      return sb.append(key).toString();
    }
    return sb.append(_NSStringUtilities.capitalizedString(key)).toString();
  }
}
TOP

Related Classes of ns.foundation._NSPropertyAccessor$_LegacyCompatibleKeyBinding

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.