<commit_before>/*
 * Copyright (c) 2005 Your Corporation. All Rights Reserved.
 */
package com.intellij.util.xml;

import com.intellij.util.containers.WeakArrayHashMap;
import com.intellij.util.xml.impl.AdvancedProxy;
import com.intellij.util.xml.impl.DomManagerImpl;
import net.sf.cglib.proxy.InvocationHandler;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author peter
 */
public class ModelMergerImpl implements ModelMerger {
  private final WeakArrayHashMap myMergedMap = new WeakArrayHashMap();

  public <T> T mergeModels(final Class<? extends T> aClass, final T... implementations) {
    final Object o = myMergedMap.get(implementations);
    if (o != null) {
      return (T) o;
    }
    if (implementations.length == 1) return implementations[0];
    final MergingInvocationHandler<T> handler = new MergingInvocationHandler<T>(implementations);
    return _mergeModels(aClass, handler, implementations);
  }

  public <T> T mergeModels(final Class<? extends T> aClass, final Collection<? extends T> implementations) {
    return (T) mergeModels(aClass, implementations.toArray());
  }


  public <T> T mergeModels(final MergingInvocationHandler<T> handler,
                                  final Class<? extends T> aClass,
                                  final T... implementations) {
    final Object o = myMergedMap.get(implementations);
    if (o != null) {
      return (T) o;
    }

    return _mergeModels(aClass, handler, implementations);
  }

  private <T> T _mergeModels(final Class<? extends T> aClass,
                                    final MergingInvocationHandler<T> handler,
                                    final T... implementations) {
    final Set<Class> commonClasses = getCommonClasses(implementations);
    commonClasses.add(MergedObject.class);
    commonClasses.remove(aClass);
    final T t = AdvancedProxy.createProxy(handler, aClass, commonClasses.toArray(new Class[commonClasses.size()]));
    myMergedMap.put(implementations, t);
    return t;
  }

  private static void addAllInterfaces(Class aClass, List<Class> list) {
    final Class[] interfaces = aClass.getInterfaces();
    list.addAll(Arrays.asList(interfaces));
    for (Class anInterface : interfaces) {
      addAllInterfaces(anInterface, list);
    }
  }

  private static Set<Class> getCommonClasses(final Object... implementations) {
    final HashSet<Class> set = new HashSet<Class>();
    if (implementations.length > 0) {
      final ArrayList<Class> list = new ArrayList<Class>();
      addAllInterfaces(implementations[0].getClass(), list);
      set.addAll(list);
      for (int i = 1; i < implementations.length; i++) {
        final ArrayList<Class> list1 = new ArrayList<Class>();
        addAllInterfaces(implementations[i].getClass(), list1);
        set.retainAll(list1);
      }
    }
    return set;
  }


  private static final Map<Class<? extends Object>,Method> ourPrimaryKeyMethods = new HashMap<Class<? extends Object>, Method>();

  public class MergingInvocationHandler<T> implements InvocationHandler {
    private T[] myImplementations;
    private Set<JavaMethodSignature> signaturesNotToMerge = Collections.emptySet();

    public MergingInvocationHandler(final T... implementations) {
      setImplementations(implementations);
    }

    public MergingInvocationHandler() {
    }

    protected final void setImplementations(final T[] implementations) {
      myImplementations = implementations;
    }

    protected Object getPrimaryKey(Object implementation) throws IllegalAccessException, InvocationTargetException {
      if (implementation instanceof GenericValue) return Boolean.TRUE; // ((GenericValue)implementation).getValue();
      final Method method = getPrimaryKeyMethod(implementation.getClass());
      if (method == null) return null;

      final Object o = method.invoke(implementation);
      return GenericValue.class.isAssignableFrom(method.getReturnType()) ? ((GenericValue)o).getValue() : o;
    }

    @Nullable
    private Method getPrimaryKeyMethod(final Class<? extends Object> aClass) {
      Method method = ourPrimaryKeyMethods.get(aClass);
      if (method == null) {
        if (ourPrimaryKeyMethods.containsKey(aClass)) return null;

        for (final Method method1 : aClass.getMethods()) {
          if ((method = findPrimaryKeyAnnotatedMethod(method1, aClass)) != null) {
            break;
          }
        }
        ourPrimaryKeyMethods.put(aClass, method);
      }
      return method;
    }

    private Method findPrimaryKeyAnnotatedMethod(final Method method, final Class aClass) {
      return method.getReturnType() != void.class
             && method.getParameterTypes().length == 0?
             JavaMethodSignature.getSignature(method).findAnnotatedMethod(PrimaryKey.class, aClass): null;
    }


    public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
      DomManagerImpl.getInvocationStack().push(method, proxy);
      try {
        if (Object.class.equals(method.getDeclaringClass())) {
          @NonNls String methodName = method.getName();
          if ("toString".equals(methodName)) {
            return "Merger: " + Arrays.asList(myImplementations);
          }
          if ("hashCode".equals(methodName)) {
            return Arrays.hashCode(myImplementations);
          }
          if ("equals".equals(methodName)) {
            final Object arg = args[0];
            return arg != null && arg instanceof MergedObject &&
                   ((MergedObject)arg).getImplementations().equals(Arrays.asList(myImplementations));

          }
          return null;
        }
        if (DomElement.class.equals(method.getDeclaringClass()) && "isValid".equals(method.getName())) {
          for (final T implementation : myImplementations) {
            if (!((Boolean) method.invoke(implementation, args))) {
              return false;
            }
          }
        }

        try {
          if (MergedObject.class.equals(method.getDeclaringClass())) {
            @NonNls String methodName = method.getName();
            if ("getImplementations".equals(methodName)) {
              return Arrays.asList(myImplementations);
            }
            else assert false;
          }
          final Class returnType = method.getReturnType();
          if (signaturesNotToMerge.size() > 0) {
            final JavaMethodSignature signature = JavaMethodSignature.getSignature(method);
            if (signaturesNotToMerge.contains(signature)) {
              for (final T t : myImplementations) {
                final Object o = method.invoke(t, args);
                if (o != null) return o;
              }
              return null;<commit_msg>isValid declaring class check removed<commit_after>/*
 * Copyright (c) 2005 Your Corporation. All Rights Reserved.
 */
package com.intellij.util.xml;

import com.intellij.util.containers.WeakArrayHashMap;
import com.intellij.util.xml.impl.AdvancedProxy;
import com.intellij.util.xml.impl.DomManagerImpl;
import net.sf.cglib.proxy.InvocationHandler;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author peter
 */
public class ModelMergerImpl implements ModelMerger {
  private final WeakArrayHashMap myMergedMap = new WeakArrayHashMap();

  public <T> T mergeModels(final Class<? extends T> aClass, final T... implementations) {
    final Object o = myMergedMap.get(implementations);
    if (o != null) {
      return (T) o;
    }
    if (implementations.length == 1) return implementations[0];
    final MergingInvocationHandler<T> handler = new MergingInvocationHandler<T>(implementations);
    return _mergeModels(aClass, handler, implementations);
  }

  public <T> T mergeModels(final Class<? extends T> aClass, final Collection<? extends T> implementations) {
    return (T) mergeModels(aClass, implementations.toArray());
  }


  public <T> T mergeModels(final MergingInvocationHandler<T> handler,
                                  final Class<? extends T> aClass,
                                  final T... implementations) {
    final Object o = myMergedMap.get(implementations);
    if (o != null) {
      return (T) o;
    }

    return _mergeModels(aClass, handler, implementations);
  }

  private <T> T _mergeModels(final Class<? extends T> aClass,
                                    final MergingInvocationHandler<T> handler,
                                    final T... implementations) {
    final Set<Class> commonClasses = getCommonClasses(implementations);
    commonClasses.add(MergedObject.class);
    commonClasses.remove(aClass);
    final T t = AdvancedProxy.createProxy(handler, aClass, commonClasses.toArray(new Class[commonClasses.size()]));
    myMergedMap.put(implementations, t);
    return t;
  }

  private static void addAllInterfaces(Class aClass, List<Class> list) {
    final Class[] interfaces = aClass.getInterfaces();
    list.addAll(Arrays.asList(interfaces));
    for (Class anInterface : interfaces) {
      addAllInterfaces(anInterface, list);
    }
  }

  private static Set<Class> getCommonClasses(final Object... implementations) {
    final HashSet<Class> set = new HashSet<Class>();
    if (implementations.length > 0) {
      final ArrayList<Class> list = new ArrayList<Class>();
      addAllInterfaces(implementations[0].getClass(), list);
      set.addAll(list);
      for (int i = 1; i < implementations.length; i++) {
        final ArrayList<Class> list1 = new ArrayList<Class>();
        addAllInterfaces(implementations[i].getClass(), list1);
        set.retainAll(list1);
      }
    }
    return set;
  }


  private static final Map<Class<? extends Object>,Method> ourPrimaryKeyMethods = new HashMap<Class<? extends Object>, Method>();

  public class MergingInvocationHandler<T> implements InvocationHandler {
    private T[] myImplementations;
    private Set<JavaMethodSignature> signaturesNotToMerge = Collections.emptySet();

    public MergingInvocationHandler(final T... implementations) {
      setImplementations(implementations);
    }

    public MergingInvocationHandler() {
    }

    protected final void setImplementations(final T[] implementations) {
      myImplementations = implementations;
    }

    protected Object getPrimaryKey(Object implementation) throws IllegalAccessException, InvocationTargetException {
      if (implementation instanceof GenericValue) return Boolean.TRUE; // ((GenericValue)implementation).getValue();
      final Method method = getPrimaryKeyMethod(implementation.getClass());
      if (method == null) return null;

      final Object o = method.invoke(implementation);
      return GenericValue.class.isAssignableFrom(method.getReturnType()) ? ((GenericValue)o).getValue() : o;
    }

    @Nullable
    private Method getPrimaryKeyMethod(final Class<? extends Object> aClass) {
      Method method = ourPrimaryKeyMethods.get(aClass);
      if (method == null) {
        if (ourPrimaryKeyMethods.containsKey(aClass)) return null;

        for (final Method method1 : aClass.getMethods()) {
          if ((method = findPrimaryKeyAnnotatedMethod(method1, aClass)) != null) {
            break;
          }
        }
        ourPrimaryKeyMethods.put(aClass, method);
      }
      return method;
    }

    private Method findPrimaryKeyAnnotatedMethod(final Method method, final Class aClass) {
      return method.getReturnType() != void.class
             && method.getParameterTypes().length == 0?
             JavaMethodSignature.getSignature(method).findAnnotatedMethod(PrimaryKey.class, aClass): null;
    }


    public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
      DomManagerImpl.getInvocationStack().push(method, proxy);
      try {
        if (Object.class.equals(method.getDeclaringClass())) {
          @NonNls String methodName = method.getName();
          if ("toString".equals(methodName)) {
            return "Merger: " + Arrays.asList(myImplementations);
          }
          if ("hashCode".equals(methodName)) {
            return Arrays.hashCode(myImplementations);
          }
          if ("equals".equals(methodName)) {
            final Object arg = args[0];
            return arg != null && arg instanceof MergedObject &&
                   ((MergedObject)arg).getImplementations().equals(Arrays.asList(myImplementations));

          }
          return null;
        }
        if (/*DomElement.class.equals(method.getDeclaringClass()) &&*/ "isValid".equals(method.getName())) {
          for (final T implementation : myImplementations) {
            if (!((Boolean) method.invoke(implementation, args))) {
              return false;
            }
          }
        }

        try {
          if (MergedObject.class.equals(method.getDeclaringClass())) {
            @NonNls String methodName = method.getName();
            if ("getImplementations".equals(methodName)) {
              return Arrays.asList(myImplementations);
            }
            else assert false;
          }
          final Class returnType = method.getReturnType();
          if (signaturesNotToMerge.size() > 0) {
            final JavaMethodSignature signature = JavaMethodSignature.getSignature(method);
            if (signaturesNotToMerge.contains(signature)) {
              for (final T t : myImplementations) {
                final Object o = method.invoke(t, args);
                if (o != null) return o;
              }
              return null;
{'fraction_non_alphanumeric': 0.10646664724730556, 'fraction_numerical': 0.002475968540635013, 'mean_word_length': 2.9451307095662167, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5996772', 'n_tokens_mistral': 3692, 'n_tokens_neox': 3650, 'n_words': 867}