| /******************************************************************************* |
| * Copyright (c) 2015 Obeo. |
| * 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: |
| * Obeo - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.acceleo.query.services; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.Sets; |
| |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Set; |
| |
| import org.eclipse.acceleo.query.runtime.IEPackageProvider; |
| import org.eclipse.acceleo.query.runtime.IReadOnlyQueryEnvironment; |
| import org.eclipse.acceleo.query.runtime.IService; |
| import org.eclipse.acceleo.query.runtime.impl.AbstractServiceProvider; |
| import org.eclipse.acceleo.query.runtime.impl.LambdaValue; |
| import org.eclipse.acceleo.query.runtime.impl.ValidationServices; |
| import org.eclipse.acceleo.query.runtime.lookup.basic.Service; |
| import org.eclipse.acceleo.query.validation.type.EClassifierLiteralType; |
| import org.eclipse.acceleo.query.validation.type.EClassifierType; |
| import org.eclipse.acceleo.query.validation.type.ICollectionType; |
| import org.eclipse.acceleo.query.validation.type.IType; |
| import org.eclipse.acceleo.query.validation.type.LambdaType; |
| import org.eclipse.acceleo.query.validation.type.NothingType; |
| import org.eclipse.acceleo.query.validation.type.SequenceType; |
| import org.eclipse.acceleo.query.validation.type.SetType; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| |
| /** |
| * Implementation of the collection services of the Acceleo Query language. |
| * |
| * @author <a href="mailto:romain.guider@obeo.fr">Romain Guider</a> |
| */ |
| public class CollectionServices extends AbstractServiceProvider { |
| |
| /** |
| * Message separator. |
| */ |
| private static final String MESSAGE_SEPARATOR = "\n "; |
| |
| /** |
| * Exists {@link IService}. |
| * |
| * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a> |
| */ |
| private static final class BooleanLambdaService extends Service { |
| |
| /** |
| * Constructor. |
| * |
| * @param serviceMethod |
| * the method that realizes the service |
| * @param serviceInstance |
| * the instance on which the service must be called |
| */ |
| private BooleanLambdaService(Method serviceMethod, Object serviceInstance) { |
| super(serviceMethod, serviceInstance); |
| } |
| |
| @Override |
| public Set<IType> getType(ValidationServices services, IReadOnlyQueryEnvironment queryEnvironment, |
| List<IType> argTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| final LambdaType lambdaType = (LambdaType)argTypes.get(1); |
| final Object lambdaExpressionType = lambdaType.getLambdaExpressionType().getType(); |
| if (isBooleanType(queryEnvironment, lambdaExpressionType)) { |
| result.addAll(super.getType(services, queryEnvironment, argTypes)); |
| } else { |
| result.add(services.nothing("expression in %s must return a boolean", getServiceMethod() |
| .getName())); |
| } |
| return result; |
| } |
| } |
| |
| /** |
| * Any {@link IService}. |
| * |
| * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a> |
| */ |
| private static final class AnyService extends Service { |
| |
| /** |
| * Constructor. |
| * |
| * @param serviceMethod |
| * the method that realizes the service |
| * @param serviceInstance |
| * the instance on which the service must be called |
| */ |
| private AnyService(Method serviceMethod, Object serviceInstance) { |
| super(serviceMethod, serviceInstance); |
| } |
| |
| @Override |
| public Set<IType> getType(ValidationServices services, IReadOnlyQueryEnvironment queryEnvironment, |
| List<IType> argTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| final LambdaType lambdaType = (LambdaType)argTypes.get(1); |
| final Object lambdaExpressionType = lambdaType.getLambdaExpressionType().getType(); |
| if (isBooleanType(queryEnvironment, lambdaExpressionType)) { |
| IType lambdaEvaluatorType = lambdaType.getLambdaEvaluatorType(); |
| if (lambdaEvaluatorType instanceof EClassifierLiteralType) { |
| lambdaEvaluatorType = new EClassifierType(queryEnvironment, |
| ((EClassifierLiteralType)lambdaEvaluatorType).getType()); |
| } |
| result.add(lambdaEvaluatorType); |
| } else { |
| result.add(services.nothing("expression in an any must return a boolean")); |
| } |
| return result; |
| } |
| } |
| |
| /** |
| * Including {@link IService}. |
| * |
| * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a> |
| */ |
| private static final class IncludingService extends Service { |
| |
| /** |
| * Constructor. |
| * |
| * @param serviceMethod |
| * the method that realizes the service |
| * @param serviceInstance |
| * the instance on which the service must be called |
| */ |
| private IncludingService(Method serviceMethod, Object serviceInstance) { |
| super(serviceMethod, serviceInstance); |
| } |
| |
| @Override |
| public Set<IType> getType(ValidationServices services, IReadOnlyQueryEnvironment queryEnvironment, |
| List<IType> argTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| if (List.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SequenceType(queryEnvironment, ((ICollectionType)argTypes.get(0)) |
| .getCollectionType())); |
| result.add(new SequenceType(queryEnvironment, argTypes.get(1))); |
| } else if (Set.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SetType(queryEnvironment, ((ICollectionType)argTypes.get(0)) |
| .getCollectionType())); |
| result.add(new SetType(queryEnvironment, argTypes.get(1))); |
| } |
| return result; |
| } |
| |
| @Override |
| public Set<IType> validateAllType(ValidationServices services, |
| IReadOnlyQueryEnvironment queryEnvironment, Map<List<IType>, Set<IType>> allTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| final StringBuilder builder = new StringBuilder(); |
| |
| for (Entry<List<IType>, Set<IType>> entry : allTypes.entrySet()) { |
| for (IType type : entry.getValue()) { |
| if (((ICollectionType)type).getCollectionType() instanceof NothingType) { |
| builder.append(MESSAGE_SEPARATOR); |
| builder.append(((NothingType)((ICollectionType)type).getCollectionType()) |
| .getMessage()); |
| } else { |
| result.add(type); |
| } |
| } |
| } |
| |
| if (result.isEmpty()) { |
| result.add(services.nothing("Nothing left after %s:" + builder.toString(), getServiceMethod() |
| .getName())); |
| } |
| |
| return result; |
| } |
| } |
| |
| /** |
| * Collect {@link IService}. |
| * |
| * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a> |
| */ |
| private static final class CollectService extends Service { |
| /** |
| * Constructor. |
| * |
| * @param serviceMethod |
| * the method that realizes the service |
| * @param serviceInstance |
| * the instance on which the service must be called |
| */ |
| private CollectService(Method serviceMethod, Object serviceInstance) { |
| super(serviceMethod, serviceInstance); |
| } |
| |
| @Override |
| public Set<IType> getType(ValidationServices services, IReadOnlyQueryEnvironment queryEnvironment, |
| List<IType> argTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| final LambdaType lambdaType = (LambdaType)argTypes.get(1); |
| if (List.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SequenceType(queryEnvironment, lambdaType.getLambdaExpressionType())); |
| } else if (Set.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SetType(queryEnvironment, lambdaType.getLambdaExpressionType())); |
| } |
| return result; |
| } |
| } |
| |
| /** |
| * Select {@link IService}. |
| * |
| * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a> |
| */ |
| private static final class SelectService extends Service { |
| |
| /** |
| * Constructor. |
| * |
| * @param serviceMethod |
| * the method that realizes the service |
| * @param serviceInstance |
| * the instance on which the service must be called |
| */ |
| private SelectService(Method serviceMethod, Object serviceInstance) { |
| super(serviceMethod, serviceInstance); |
| } |
| |
| @Override |
| public Set<IType> getType(ValidationServices services, IReadOnlyQueryEnvironment queryEnvironment, |
| List<IType> argTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| final LambdaType lambdaType = (LambdaType)argTypes.get(1); |
| final Object lambdaExpressionType = lambdaType.getLambdaExpressionType().getType(); |
| if (isBooleanType(queryEnvironment, lambdaExpressionType)) { |
| IType lambdaEvaluatorType = lambdaType.getLambdaEvaluatorType(); |
| if (lambdaEvaluatorType instanceof EClassifierLiteralType) { |
| lambdaEvaluatorType = new EClassifierType(queryEnvironment, |
| ((EClassifierLiteralType)lambdaEvaluatorType).getType()); |
| } |
| if (List.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SequenceType(queryEnvironment, lambdaEvaluatorType)); |
| } else if (Set.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SetType(queryEnvironment, lambdaEvaluatorType)); |
| } |
| } else { |
| result.add(services.nothing("expression in a select must return a boolean")); |
| } |
| return result; |
| } |
| } |
| |
| /** |
| * Reject {@link IService}. |
| * |
| * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a> |
| */ |
| private static final class RejectService extends Service { |
| |
| /** |
| * Constructor. |
| * |
| * @param serviceMethod |
| * the method that realizes the service |
| * @param serviceInstance |
| * the instance on which the service must be called |
| */ |
| private RejectService(Method serviceMethod, Object serviceInstance) { |
| super(serviceMethod, serviceInstance); |
| } |
| |
| @Override |
| public Set<IType> getType(ValidationServices services, IReadOnlyQueryEnvironment queryEnvironment, |
| List<IType> argTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| |
| final LambdaType lambdaType = (LambdaType)argTypes.get(1); |
| final Object lambdaExpressionType = lambdaType.getLambdaExpressionType().getType(); |
| if (isBooleanType(queryEnvironment, lambdaExpressionType)) { |
| if (List.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SequenceType(queryEnvironment, ((ICollectionType)argTypes.get(0)) |
| .getCollectionType())); |
| } else if (Set.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SetType(queryEnvironment, ((ICollectionType)argTypes.get(0)) |
| .getCollectionType())); |
| } |
| } else { |
| result.add(services.nothing("expression in a reject must return a boolean")); |
| } |
| |
| return result; |
| } |
| } |
| |
| /** |
| * A {@link Service} returning the raw collection type of the first argument. |
| * |
| * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a> |
| */ |
| private static final class FirstArgumentRawCollectionType extends Service { |
| |
| /** |
| * Constructor. |
| * |
| * @param serviceMethod |
| * the method that realizes the service |
| * @param serviceInstance |
| * the instance on which the service must be called |
| */ |
| private FirstArgumentRawCollectionType(Method serviceMethod, Object serviceInstance) { |
| super(serviceMethod, serviceInstance); |
| } |
| |
| @Override |
| public Set<IType> getType(ValidationServices services, IReadOnlyQueryEnvironment queryEnvironment, |
| List<IType> argTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| |
| result.add(((ICollectionType)argTypes.get(0)).getCollectionType()); |
| |
| return result; |
| } |
| } |
| |
| /** |
| * A {@link Service} returning the same collection type as the method with the raw collection type of |
| * first argument. |
| * |
| * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a> |
| */ |
| private static final class ReturnCollectionTypeWithFirstArgumentRawCollectionType extends Service { |
| |
| /** |
| * Constructor. |
| * |
| * @param serviceMethod |
| * the method that realizes the service |
| * @param serviceInstance |
| * the instance on which the service must be called |
| */ |
| private ReturnCollectionTypeWithFirstArgumentRawCollectionType(Method serviceMethod, |
| Object serviceInstance) { |
| super(serviceMethod, serviceInstance); |
| } |
| |
| @Override |
| public Set<IType> getType(ValidationServices services, IReadOnlyQueryEnvironment queryEnvironment, |
| List<IType> argTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| |
| if (List.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SequenceType(queryEnvironment, ((ICollectionType)argTypes.get(0)) |
| .getCollectionType())); |
| } else if (Set.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SetType(queryEnvironment, ((ICollectionType)argTypes.get(0)) |
| .getCollectionType())); |
| } |
| |
| return result; |
| } |
| } |
| |
| /** |
| * A {@link Service} returning the same collection type as the method with the raw collection type of |
| * first and second arguments. |
| * |
| * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a> |
| */ |
| private static final class ReturnCollectionTypeWithFirstAndSecondArgumentRawCollectionType extends Service { |
| |
| /** |
| * Constructor. |
| * |
| * @param serviceMethod |
| * the method that realizes the service |
| * @param serviceInstance |
| * the instance on which the service must be called |
| */ |
| private ReturnCollectionTypeWithFirstAndSecondArgumentRawCollectionType(Method serviceMethod, |
| Object serviceInstance) { |
| super(serviceMethod, serviceInstance); |
| } |
| |
| @Override |
| public Set<IType> getType(ValidationServices services, IReadOnlyQueryEnvironment queryEnvironment, |
| List<IType> argTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| |
| if (List.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SequenceType(queryEnvironment, ((ICollectionType)argTypes.get(0)) |
| .getCollectionType())); |
| result.add(new SequenceType(queryEnvironment, ((ICollectionType)argTypes.get(1)) |
| .getCollectionType())); |
| } else if (Set.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SetType(queryEnvironment, ((ICollectionType)argTypes.get(0)) |
| .getCollectionType())); |
| result.add(new SetType(queryEnvironment, ((ICollectionType)argTypes.get(1)) |
| .getCollectionType())); |
| } |
| |
| return result; |
| } |
| |
| @Override |
| public Set<IType> validateAllType(ValidationServices services, |
| IReadOnlyQueryEnvironment queryEnvironment, Map<List<IType>, Set<IType>> allTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| final StringBuilder builder = new StringBuilder(); |
| |
| for (Entry<List<IType>, Set<IType>> entry : allTypes.entrySet()) { |
| for (IType type : entry.getValue()) { |
| if (((ICollectionType)type).getCollectionType() instanceof NothingType) { |
| builder.append(MESSAGE_SEPARATOR); |
| builder.append(((NothingType)((ICollectionType)type).getCollectionType()) |
| .getMessage()); |
| } else { |
| result.add(type); |
| } |
| } |
| } |
| |
| if (result.isEmpty()) { |
| result.add(services.nothing("Nothing left after %s:" + builder.toString(), getServiceMethod() |
| .getName())); |
| } |
| |
| return result; |
| } |
| |
| } |
| |
| /** |
| * A {@link Service} returning the {@link EClassifierLiteralType#getType() classifier literal type} of the |
| * second argument in the {@link org.eclipse.acceleo.query.validation.type.ICollectionType |
| * ICollectionType} of the first argument. |
| * |
| * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a> |
| */ |
| private static final class SecondArgumentTypeInFirstArgumentCollectionType extends FilterService { |
| |
| /** |
| * Constructor. |
| * |
| * @param serviceMethod |
| * the method that realizes the service |
| * @param serviceInstance |
| * the instance on which the service must be called |
| */ |
| SecondArgumentTypeInFirstArgumentCollectionType(Method serviceMethod, Object serviceInstance) { |
| super(serviceMethod, serviceInstance); |
| } |
| |
| @Override |
| public java.util.Set<IType> getType(ValidationServices services, |
| IReadOnlyQueryEnvironment queryEnvironment, java.util.List<IType> argTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| |
| final EClassifierType rawType = new EClassifierType(queryEnvironment, |
| ((EClassifierLiteralType)argTypes.get(1)).getType()); |
| if (List.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SequenceType(queryEnvironment, rawType)); |
| } else if (Set.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SetType(queryEnvironment, rawType)); |
| } |
| |
| return result; |
| |
| } |
| } |
| |
| /** |
| * A {@link Service} returning the raw type of the first argument {@link ICollectionType}. |
| * |
| * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a> |
| */ |
| private static final class FirstCollectionTypeService extends Service { |
| |
| /** |
| * Creates a new service instance given a method and an instance. |
| * |
| * @param serviceMethod |
| * the method that realizes the service |
| * @param serviceInstance |
| * the instance on which the service must be called |
| */ |
| public FirstCollectionTypeService(Method serviceMethod, Object serviceInstance) { |
| super(serviceMethod, serviceInstance); |
| } |
| |
| @Override |
| public Set<IType> getType(ValidationServices services, IReadOnlyQueryEnvironment queryEnvironment, |
| List<IType> argTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| if (List.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SequenceType(queryEnvironment, ((ICollectionType)argTypes.get(0)) |
| .getCollectionType())); |
| } else if (Set.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SetType(queryEnvironment, ((ICollectionType)argTypes.get(0)) |
| .getCollectionType())); |
| } |
| return result; |
| } |
| |
| } |
| |
| /** |
| * InsertAt {@link IService}. |
| * |
| * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a> |
| */ |
| private static final class InsertAtService extends Service { |
| |
| /** |
| * Constructor. |
| * |
| * @param serviceMethod |
| * the method that realizes the service |
| * @param serviceInstance |
| * the instance on which the service must be called |
| */ |
| private InsertAtService(Method serviceMethod, Object serviceInstance) { |
| super(serviceMethod, serviceInstance); |
| } |
| |
| @Override |
| public Set<IType> getType(ValidationServices services, IReadOnlyQueryEnvironment queryEnvironment, |
| List<IType> argTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| if (List.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SequenceType(queryEnvironment, ((ICollectionType)argTypes.get(0)) |
| .getCollectionType())); |
| result.add(new SequenceType(queryEnvironment, argTypes.get(2))); |
| } else if (Set.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SetType(queryEnvironment, ((ICollectionType)argTypes.get(0)) |
| .getCollectionType())); |
| result.add(new SetType(queryEnvironment, argTypes.get(2))); |
| } |
| return result; |
| } |
| } |
| |
| /** |
| * Intersection {@link IService}. |
| * |
| * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a> |
| */ |
| private static final class IntersectionService extends Service { |
| |
| /** |
| * Constructor. |
| * |
| * @param serviceMethod |
| * the method that realizes the service |
| * @param serviceInstance |
| * the instance on which the service must be called |
| */ |
| private IntersectionService(Method serviceMethod, Object serviceInstance) { |
| super(serviceMethod, serviceInstance); |
| } |
| |
| @Override |
| public Set<IType> getType(ValidationServices services, IReadOnlyQueryEnvironment queryEnvironment, |
| List<IType> argTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| |
| IType selfRawType = ((ICollectionType)argTypes.get(0)).getCollectionType(); |
| IType otherRawType = ((ICollectionType)argTypes.get(1)).getCollectionType(); |
| final Set<IType> resultRawTypes = new LinkedHashSet<IType>(); |
| final IType loweredType = services.lower(selfRawType, otherRawType); |
| if (loweredType != null) { |
| resultRawTypes.add(loweredType); |
| } else if (selfRawType.getType() instanceof EClass && otherRawType.getType() instanceof EClass) { |
| for (EClass eCls : getSubTypesTopIntersection(queryEnvironment.getEPackageProvider(), |
| (EClass)selfRawType.getType(), (EClass)otherRawType.getType())) { |
| resultRawTypes.add(new EClassifierType(queryEnvironment, eCls)); |
| } |
| if (resultRawTypes.isEmpty()) { |
| resultRawTypes.add(services.nothing("Nothing left after intersection of %s and %s", |
| argTypes.get(0), argTypes.get(1))); |
| } |
| } else { |
| resultRawTypes.add(selfRawType); |
| resultRawTypes.add(otherRawType); |
| } |
| if (List.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| for (IType resultRawType : resultRawTypes) { |
| result.add(new SequenceType(queryEnvironment, resultRawType)); |
| } |
| } else if (Set.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| for (IType resultRawType : resultRawTypes) { |
| result.add(new SetType(queryEnvironment, resultRawType)); |
| } |
| } |
| |
| return result; |
| } |
| |
| @Override |
| public Set<IType> validateAllType(ValidationServices services, |
| IReadOnlyQueryEnvironment queryEnvironment, Map<List<IType>, Set<IType>> allTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| final StringBuilder builder = new StringBuilder(); |
| |
| for (Entry<List<IType>, Set<IType>> entry : allTypes.entrySet()) { |
| for (IType type : entry.getValue()) { |
| if (((ICollectionType)type).getCollectionType() instanceof NothingType) { |
| builder.append(MESSAGE_SEPARATOR); |
| builder.append(((NothingType)((ICollectionType)type).getCollectionType()) |
| .getMessage()); |
| } else { |
| result.add(type); |
| } |
| } |
| } |
| |
| if (result.isEmpty()) { |
| if (List.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SequenceType(queryEnvironment, services |
| .nothing("Nothing left after intersection:" + builder.toString()))); |
| } else if (Set.class.isAssignableFrom(getServiceMethod().getReturnType())) { |
| result.add(new SetType(queryEnvironment, services |
| .nothing("Nothing left after intersection:" + builder.toString()))); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Gets the {@link Set} of the higher {@link EClass} in the super types hierarchy inheriting from both |
| * given {@link EClass} according to the given {@link IEPackageProvider} . |
| * |
| * @param provider |
| * the {@link IEPackageProvider} |
| * @param eCls1 |
| * the first {@link EClass} |
| * @param eCls2 |
| * the second {@link EClass} |
| * @return the {@link Set} of the higher {@link EClass} in the super types hierarchy inheriting from |
| * both given {@link EClass} according to the given {@link IEPackageProvider} |
| */ |
| private Set<EClass> getSubTypesTopIntersection(IEPackageProvider provider, EClass eCls1, EClass eCls2) { |
| final Set<EClass> result = new LinkedHashSet<EClass>(); |
| |
| final Set<EClass> subTypes1 = provider.getAllSubTypes(eCls1); |
| final Set<EClass> subTypes2 = provider.getAllSubTypes(eCls2); |
| |
| final Set<EClass> intersection = new LinkedHashSet<EClass>(); |
| for (EClass subType1 : subTypes1) { |
| if (subTypes2.contains(subType1)) { |
| intersection.add(subType1); |
| } |
| } |
| |
| for (EClass eCls : intersection) { |
| boolean isTopEClass = true; |
| |
| for (EClass superECls : eCls.getEAllSuperTypes()) { |
| if (intersection.contains(superECls)) { |
| isTopEClass = false; |
| break; |
| } |
| } |
| |
| if (isTopEClass) { |
| result.add(eCls); |
| } |
| } |
| |
| return result; |
| } |
| } |
| |
| @Override |
| protected IService getService(Method publicMethod) { |
| final IService result; |
| |
| if ("filter".equals(publicMethod.getName())) { |
| result = new SecondArgumentTypeInFirstArgumentCollectionType(publicMethod, this); |
| } else if ("add".equals(publicMethod.getName()) || "concat".equals(publicMethod.getName()) |
| || "union".equals(publicMethod.getName())) { |
| result = new ReturnCollectionTypeWithFirstAndSecondArgumentRawCollectionType(publicMethod, this); |
| } else if ("asSequence".equals(publicMethod.getName()) || "asSet".equals(publicMethod.getName()) |
| || "asOrderedSet".equals(publicMethod.getName())) { |
| result = new ReturnCollectionTypeWithFirstArgumentRawCollectionType(publicMethod, this); |
| } else if ("subOrderedSet".equals(publicMethod.getName()) |
| || "subSequence".equals(publicMethod.getName())) { |
| result = new FirstCollectionTypeService(publicMethod, this); |
| } else if ("first".equals(publicMethod.getName()) || "at".equals(publicMethod.getName()) |
| || "last".equals(publicMethod.getName())) { |
| result = new FirstArgumentRawCollectionType(publicMethod, this); |
| } else if ("excluding".equals(publicMethod.getName()) || "sub".equals(publicMethod.getName()) |
| || "reverse".equals(publicMethod.getName())) { |
| result = new FirstCollectionTypeService(publicMethod, this); |
| } else if ("reject".equals(publicMethod.getName())) { |
| result = new RejectService(publicMethod, this); |
| } else if ("select".equals(publicMethod.getName())) { |
| result = new SelectService(publicMethod, this); |
| } else if ("collect".equals(publicMethod.getName())) { |
| result = new CollectService(publicMethod, this); |
| } else if ("including".equals(publicMethod.getName()) || "prepend".equals(publicMethod.getName())) { |
| result = new IncludingService(publicMethod, this); |
| } else if ("sep".equals(publicMethod.getName())) { |
| if (publicMethod.getParameterTypes().length == 2) { |
| result = new Service(publicMethod, this) { |
| |
| @Override |
| public Set<IType> getType(ValidationServices services, |
| IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| |
| result.add(new SequenceType(queryEnvironment, ((ICollectionType)argTypes.get(0)) |
| .getCollectionType())); |
| result.add(new SequenceType(queryEnvironment, argTypes.get(1))); |
| |
| return result; |
| } |
| }; |
| } else if (publicMethod.getParameterTypes().length == 4) { |
| result = new Service(publicMethod, this) { |
| |
| @Override |
| public Set<IType> getType(ValidationServices services, |
| IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes) { |
| final Set<IType> result = new LinkedHashSet<IType>(); |
| |
| result.add(new SequenceType(queryEnvironment, ((ICollectionType)argTypes.get(0)) |
| .getCollectionType())); |
| result.add(new SequenceType(queryEnvironment, argTypes.get(1))); |
| result.add(new SequenceType(queryEnvironment, argTypes.get(2))); |
| result.add(new SequenceType(queryEnvironment, argTypes.get(3))); |
| |
| return result; |
| } |
| }; |
| } else { |
| result = new Service(publicMethod, this); |
| } |
| } else if ("any".equals(publicMethod.getName())) { |
| result = new AnyService(publicMethod, this); |
| } else if ("exists".equals(publicMethod.getName()) || "forAll".equals(publicMethod.getName()) |
| || "one".equals(publicMethod.getName())) { |
| result = new BooleanLambdaService(publicMethod, this); |
| } else if ("insertAt".equals(publicMethod.getName())) { |
| result = new InsertAtService(publicMethod, this); |
| } else if ("intersection".equals(publicMethod.getName())) { |
| result = new IntersectionService(publicMethod, this); |
| } else { |
| result = new Service(publicMethod, this); |
| } |
| return result; |
| } |
| |
| /** |
| * Tells if the given {@link Object} is a is a boolean {@link org.eclipse.emf.ecore.EDataType EDataType}. |
| * |
| * @param queryEnvironment |
| * the {@link IReadOnlyQueryEnvironment} |
| * @param type |
| * the {@link org.eclipse.emf.ecore.EDataType EDataType} |
| * @return <code>true</code> if the given {@link Object} is a is a boolean |
| * {@link org.eclipse.emf.ecore.EDataType EDataType}, <code>false</code> otherwise |
| */ |
| private static boolean isBooleanType(IReadOnlyQueryEnvironment queryEnvironment, Object type) { |
| final boolean result; |
| |
| if (type instanceof EClassifier) { |
| final Class<?> typeClass = queryEnvironment.getEPackageProvider().getClass((EClassifier)type); |
| result = typeClass == Boolean.class || typeClass == boolean.class; |
| } else { |
| result = false; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Returns the concatenation of the two specified lists. |
| * |
| * @param c1 |
| * the first operand |
| * @param c2 |
| * the second operand. |
| * @return the concatenation of the two specified operands. |
| */ |
| public List<Object> concat(List<Object> c1, List<Object> c2) { |
| final List<Object> result; |
| |
| if (c1.isEmpty()) { |
| result = c2; |
| } else if (c2.isEmpty()) { |
| result = c1; |
| } else { |
| result = Lists.newArrayList(c1); |
| result.addAll(c2); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Returns the concatenation of the two specified lists. |
| * |
| * @param l1 |
| * the first operand |
| * @param l2 |
| * the second operand. |
| * @return the concatenation of the two specified operands. |
| */ |
| |
| public List<Object> add(List<Object> l1, List<Object> l2) { |
| return concat(l1, l2); |
| } |
| |
| /** |
| * Returns the difference of the two specified lists. |
| * |
| * @param l1 |
| * the first operand |
| * @param l2 |
| * the second operand. |
| * @return the sequence that contains elements from l1 that are not in l2. |
| */ |
| |
| public List<Object> sub(List<Object> l1, List<Object> l2) { |
| if (l2.isEmpty()) { |
| return l1; |
| } else { |
| List<Object> result = Lists.newArrayList(l1); |
| for (Object obj : l2) { |
| result.remove(obj); |
| } |
| return result; |
| } |
| } |
| |
| /** |
| * Returns the difference of the two specified lists. |
| * |
| * @param l1 |
| * the first operand |
| * @param l2 |
| * the second operand. |
| * @return the sequence that contains elements from l1 that are not in l2. |
| */ |
| |
| public Set<Object> sub(Set<Object> l1, Set<Object> l2) { |
| if (l2.isEmpty()) { |
| return l1; |
| } else { |
| Set<Object> result = Sets.newLinkedHashSet(l1); |
| for (Object obj : l2) { |
| result.remove(obj); |
| } |
| return result; |
| } |
| } |
| |
| /** |
| * Returns the concatenation of the two specified lists. |
| * |
| * @param l1 |
| * the first operand |
| * @param l2 |
| * the second operand. |
| * @return the concatenation of the two specified operands. |
| */ |
| |
| public Set<Object> add(Set<Object> l1, Set<Object> l2) { |
| return Sets.union(l1, l2); |
| } |
| |
| /** |
| * Select returns a filtered version of the specified {@link List}. |
| * |
| * @param l1 |
| * the original {@link List}. |
| * @param lambda |
| * the predicate expression |
| * @return a filtered version of the specified {@link List}. |
| */ |
| public List<Object> select(List<Object> l1, LambdaValue lambda) { |
| final List<Object> newList; |
| |
| if (lambda == null) { |
| newList = Collections.emptyList(); |
| } else { |
| newList = Lists.newArrayList(); |
| for (Object elt : l1) { |
| try { |
| if (Boolean.TRUE.equals(lambda.eval(new Object[] {elt }))) { |
| newList.add(elt); |
| } |
| // CHECKSTYLE:OFF |
| } catch (Exception e) { |
| // TODO: log the exception. |
| } |
| // CHECKSTYLE:ON |
| } |
| } |
| |
| return newList; |
| } |
| |
| /** |
| * Select returns a filtered version of the specified {@link Set}. |
| * |
| * @param l1 |
| * the original {@link Set}. |
| * @param lambda |
| * the predicate expression |
| * @return a filtered version of the specified {@link Set}. |
| */ |
| public Set<Object> select(Set<Object> l1, LambdaValue lambda) { |
| final Set<Object> newSet; |
| |
| if (lambda == null) { |
| newSet = Collections.emptySet(); |
| } else { |
| newSet = Sets.newLinkedHashSet(); |
| for (Object elt : l1) { |
| try { |
| if (Boolean.TRUE.equals(lambda.eval(new Object[] {elt }))) { |
| newSet.add(elt); |
| } |
| // CHECKSTYLE:OFF |
| } catch (Exception e) { |
| // TODO: log the exception. |
| } |
| // CHECKSTYLE:ON |
| } |
| } |
| |
| return newSet; |
| } |
| |
| /** |
| * Select returns a filtered version of the specified {@link Set}. |
| * |
| * @param l1 |
| * the original {@link Set} |
| * @param lambda |
| * the predicate expression |
| * @return a filtered version of the specified {@link Set}. |
| */ |
| public Set<Object> reject(Set<Object> l1, LambdaValue lambda) { |
| final Set<Object> newSet; |
| |
| if (lambda == null) { |
| newSet = Collections.emptySet(); |
| } else { |
| newSet = Sets.newLinkedHashSet(); |
| for (Object elt : l1) { |
| try { |
| if (Boolean.FALSE.equals(lambda.eval(new Object[] {elt }))) { |
| newSet.add(elt); |
| } |
| // CHECKSTYLE:OFF |
| } catch (Exception e) { |
| // TODO: log the exception. |
| } |
| // CHECKSTYLE:ON |
| } |
| } |
| |
| return newSet; |
| } |
| |
| /** |
| * Select returns a filtered version of the specified {@link List}. |
| * |
| * @param l1 |
| * the original {@link List} |
| * @param lambda |
| * the predicate expression |
| * @return a filtered version of the specified {@link List}. |
| */ |
| public List<Object> reject(List<Object> l1, LambdaValue lambda) { |
| final List<Object> newList; |
| |
| if (lambda == null) { |
| newList = Collections.emptyList(); |
| } else { |
| newList = Lists.newArrayList(); |
| for (Object elt : l1) { |
| try { |
| if (Boolean.FALSE.equals(lambda.eval(new Object[] {elt }))) { |
| newList.add(elt); |
| } |
| // CHECKSTYLE:OFF |
| } catch (Exception e) { |
| // TODO: log the exception. |
| } |
| // CHECKSTYLE:ON |
| } |
| } |
| |
| return newList; |
| } |
| |
| /** |
| * Collects elements from the given {@link Set} using the given navigation {@link LambdaValue}. |
| * |
| * @param set |
| * the original {@link Set} |
| * @param lambda |
| * the predicate expression |
| * @return a navigated version of the specified {@link Set}. |
| */ |
| public Set<Object> collect(Set<Object> set, LambdaValue lambda) { |
| final Set<Object> result; |
| |
| if (lambda == null) { |
| result = Collections.emptySet(); |
| } else { |
| result = Sets.newLinkedHashSet(); |
| for (Object elt : set) { |
| try { |
| result.add(lambda.eval(new Object[] {elt })); |
| // CHECKSTYLE:OFF |
| } catch (Exception e) { |
| // TODO: log the exception. |
| } |
| // CHECKSTYLE:ON |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Collects elements from the given {@link List} using the given navigation {@link LambdaValue}. |
| * |
| * @param list |
| * the original {@link List} |
| * @param lambda |
| * the predicate expression |
| * @return a navigated version of the specified {@link List}. |
| */ |
| public List<Object> collect(List<Object> list, LambdaValue lambda) { |
| final List<Object> result; |
| |
| if (lambda == null) { |
| result = Collections.emptyList(); |
| } else { |
| result = Lists.newArrayList(); |
| for (Object elt : list) { |
| try { |
| result.add(lambda.eval(new Object[] {elt })); |
| // CHECKSTYLE:OFF |
| } catch (Exception e) { |
| // TODO: log the exception. |
| } |
| // CHECKSTYLE:ON |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Returns the size of the specified collection. |
| * |
| * @param collection |
| * the input collection |
| * @return the size of the specified collection. |
| */ |
| public Integer size(Collection<Object> collection) { |
| return collection.size(); |
| } |
| |
| /** |
| * Returns the {@link Set} containing all elements of source {@link Set} plus the given {@link Object}. |
| * |
| * @param source |
| * the source {@link Set} |
| * @param object |
| * the {@link Object} to add |
| * @return the {@link Set} containing all elements of source {@link Set} plus the given {@link Object}. |
| */ |
| public Set<Object> including(Set<Object> source, Object object) { |
| if (source.contains(object)) { |
| return source; |
| } else { |
| Set<Object> result = Sets.newLinkedHashSet(source); |
| result.add(object); |
| return result; |
| } |
| } |
| |
| /** |
| * Returns the {@link Set} containing all elements of source {@link Set} without the given {@link Object}. |
| * |
| * @param source |
| * the source {@link Set} |
| * @param object |
| * the {@link Object} to add |
| * @return the {@link Set} containing all elements of source {@link Set} without the given {@link Object}. |
| */ |
| public Set<Object> excluding(Set<Object> source, Object object) { |
| if (!source.contains(object)) { |
| return source; |
| } else { |
| Set<Object> result = Sets.newLinkedHashSet(source); |
| result.remove(object); |
| return result; |
| } |
| } |
| |
| /** |
| * Returns the {@link List} containing all elements of source {@link List} plus the given {@link Object}. |
| * |
| * @param source |
| * the source {@link List} |
| * @param object |
| * the {@link Object} to add |
| * @return the set containing all elements of source {@link List} plus the given {@link Object}. |
| */ |
| public List<Object> including(List<Object> source, Object object) { |
| if (source.contains(object)) { |
| return source; |
| } else { |
| List<Object> result = Lists.newArrayList(source); |
| result.add(object); |
| return result; |
| } |
| } |
| |
| /** |
| * Returns the {@link List} containing all elements of source {@link List} without the given |
| * {@link Object}. |
| * |
| * @param source |
| * the source {@link List} |
| * @param object |
| * the {@link Object} to add |
| * @return the {@link List} containing all elements of source {@link List} without the given |
| * {@link Object}. |
| */ |
| public List<Object> excluding(List<Object> source, Object object) { |
| if (!source.contains(object)) { |
| return source; |
| } else { |
| List<Object> result = Lists.newArrayList(source); |
| result.remove(object); |
| return result; |
| } |
| } |
| |
| /** |
| * Returns a {@link List} representation of the specified {@link Collection}. Returns the same object if |
| * it is a {@link List} already. |
| * |
| * @param collection |
| * the input collection |
| * @return a list with all the elements in collection. |
| */ |
| public List<Object> asSequence(Collection<Object> collection) { |
| if (collection instanceof List) { |
| return (List<Object>)collection; |
| } else { |
| return Lists.newArrayList(collection); |
| } |
| } |
| |
| /** |
| * Returns a {@link Set} representation of the specified {@link Collection}. Returns the same object if it |
| * is a {@link Set} already. |
| * |
| * @param collection |
| * the input {@link Collection} |
| * @return a {@link Set} with all the elements in {@link Collection}. |
| */ |
| public Set<Object> asSet(Collection<Object> collection) { |
| if (collection instanceof Set) { |
| return (Set<Object>)collection; |
| } else { |
| return Sets.newLinkedHashSet(collection); |
| } |
| } |
| |
| /** |
| * Same as {@link CollectionServices#asSet(Collection) asSet}. |
| * |
| * @param collection |
| * the input {@link Collection} |
| * @return {@link CollectionServices#asSet(Collection) asSet} |
| */ |
| public Set<Object> asOrderedSet(Collection<Object> collection) { |
| return asSet(collection); |
| } |
| |
| /** |
| * Returns the first element of the specified Collection. |
| * |
| * @param collection |
| * the input {@link Collection}. |
| * @return the first element of the {@link Collection}. |
| */ |
| public Object first(Collection<Object> collection) { |
| Iterator<Object> iterator = collection.iterator(); |
| if (iterator.hasNext()) { |
| return iterator.next(); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns a {@link List} in a reversed order. |
| * |
| * @param collection |
| * the input {@link List}. |
| * @return a {@link List} in the reversed order. |
| */ |
| public List<Object> reverse(List<Object> collection) { |
| return Lists.reverse(collection); |
| } |
| |
| /** |
| * Returns a {@link Set} in a reversed order. |
| * |
| * @param collection |
| * the input {@link Set}. |
| * @return a {@link Set} in the reversed order. |
| */ |
| public Set<Object> reverse(Set<Object> collection) { |
| return Sets.newLinkedHashSet(Lists.reverse(ImmutableList.copyOf(collection))); |
| } |
| |
| /** |
| * Returns <code>true</code> when the specified list is empty. |
| * |
| * @param collection |
| * the tested collection |
| * @return <code>true</code> when the specified list is empty. |
| */ |
| public Boolean isEmpty(Collection<Object> collection) { |
| return collection.isEmpty(); |
| } |
| |
| /** |
| * Returns <code>true</code> when the specified list is empty. |
| * |
| * @param collection |
| * the tested collection |
| * @return <code>true</code> when the specified list is empty. |
| */ |
| public Boolean notEmpty(Collection<Object> collection) { |
| return !collection.isEmpty(); |
| } |
| |
| /** |
| * Returns the element at the indicated position in the list. |
| * |
| * @param list |
| * the input list. |
| * @param position |
| * the position of the element to return [1..n]. |
| * @return the element at the indicated position in the list. |
| */ |
| public Object at(List<Object> list, Integer position) { |
| return list.get(position - 1); |
| } |
| |
| /** |
| * Keeps instances of the given {@link EClassifier} from the given {@link Set}. |
| * |
| * @param set |
| * the {@link Set} to filter |
| * @param eClassifier |
| * the {@link EClassifier} to keep |
| * @return a new {@link Set} containing instances of the given {@link EClassifier} from the given |
| * {@link Set}, or <code>null</code> if the given {@link Set} is <code>null</code> |
| */ |
| public Set<Object> filter(Set<Object> set, final EClass eClassifier) { |
| final Set<Object> result; |
| |
| if (set == null) { |
| result = null; |
| } else if (eClassifier == null) { |
| result = Sets.newLinkedHashSet(); |
| } else { |
| result = Sets.newLinkedHashSet(); |
| for (Object object : set) { |
| if (eClassifier.isInstance(object)) { |
| result.add(object); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Keeps instances of the given {@link EClassifier} from the given {@link List}. |
| * |
| * @param list |
| * the {@link List} to filter |
| * @param eClassifier |
| * the {@link EClassifier} to keep |
| * @return a new {@link List} containing instances of the given {@link EClassifier} from the given |
| * {@link List}, or <code>null</code> if the given {@link List} is <code>null</code> |
| */ |
| public List<Object> filter(List<Object> list, final EClassifier eClassifier) { |
| final List<Object> result; |
| |
| if (list == null) { |
| result = null; |
| } else if (eClassifier == null) { |
| result = Lists.newArrayList(); |
| } else { |
| result = Lists.newArrayList(); |
| for (Object object : list) { |
| if (eClassifier.isInstance(object)) { |
| result.add(object); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Inserts the given separator between each elements of the given {@link Collection}. |
| * |
| * @param collection |
| * the {@link Collection} |
| * @param separator |
| * the separator to insert |
| * @return a new {@link List}, or <code>null</code> if the given {@link Collection} is <code>null</code> |
| */ |
| public List<Object> sep(Collection<Object> collection, Object separator) { |
| final List<Object> result; |
| |
| if (collection == null) { |
| result = null; |
| } else { |
| result = Lists.newArrayList(); |
| |
| final Iterator<Object> it = collection.iterator(); |
| if (it.hasNext()) { |
| result.add(it.next()); |
| while (it.hasNext()) { |
| result.add(separator); |
| result.add(it.next()); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Inserts the given separator between each elements of the given {@link Collection}, the given prefix |
| * before the first element, and the given suffix after the last element. |
| * |
| * @param collection |
| * the {@link Collection} |
| * @param prefix |
| * the prefix to add |
| * @param suffix |
| * the suffix to add |
| * @param separator |
| * the separator to insert |
| * @return a new {@link List} |
| */ |
| public List<Object> sep(Collection<Object> collection, Object prefix, Object separator, Object suffix) { |
| final List<Object> result = Lists.newArrayList(); |
| |
| result.add(prefix); |
| if (collection != null) { |
| result.addAll(sep(collection, separator)); |
| } |
| result.add(suffix); |
| |
| return result; |
| } |
| |
| /** |
| * Gets the last element of the given {@link List}. |
| * |
| * @param list |
| * the {@link List} |
| * @return the last element of the given {@link List}, or <code>null</code> if the given {@link List} is |
| * <code>null</code> |
| */ |
| public Object last(List<Object> list) { |
| ListIterator<Object> it = list.listIterator(list.size()); |
| if (it.hasPrevious()) { |
| return it.previous(); |
| } |
| return null; |
| } |
| |
| /** |
| * Tells if the given {@link Collection} doesn't {@link Collection#contains(Object) contains} the given |
| * {@link Object}. |
| * |
| * @param collection |
| * the {@link Collection} |
| * @param object |
| * the {@link Object} |
| * @return <code>true</code> if the given {@link Collection} doesn't {@link Collection#contains(Object) |
| * contains} the given {@link Object}, <code>false</code> otherwise |
| */ |
| public Boolean excludes(Collection<Object> collection, Object object) { |
| return Boolean.valueOf(!collection.contains(object)); |
| } |
| |
| /** |
| * Tells if the given {@link Collection} {@link Collection#contains(Object) contains} the given |
| * {@link Object}. |
| * |
| * @param collection |
| * the {@link Collection} |
| * @param object |
| * the {@link Object} |
| * @return <code>true</code> if the given {@link Collection} {@link Collection#contains(Object) contains} |
| * the given {@link Object}, <code>false</code> otherwise |
| */ |
| public Boolean includes(Collection<Object> collection, Object object) { |
| return Boolean.valueOf(collection.contains(object)); |
| } |
| |
| /** |
| * Makes the union of the first {@link Set} with the second {@link Set}. |
| * |
| * @param c1 |
| * the first {@link Set} |
| * @param c2 |
| * the second {@link Set} |
| * @return the union of the first {@link Set} with the second {@link Set} |
| */ |
| public Set<Object> union(Set<Object> c1, Set<Object> c2) { |
| return add(c1, c2); |
| } |
| |
| /** |
| * Makes the union of the first {@link List} with the second {@link List}. |
| * |
| * @param c1 |
| * the first {@link List} |
| * @param c2 |
| * the second {@link List} |
| * @return the union of the first {@link List} with the second {@link List} |
| */ |
| public List<Object> union(List<Object> c1, List<Object> c2) { |
| return concat(c1, c2); |
| } |
| |
| /** |
| * Gets the first element in the given {@link Collection} for which the {@link LambdaValue} is |
| * {@link LambdaValue#eval(Object[]) evaluated} to <code>true</code>. |
| * |
| * @param self |
| * the {@link Collection} |
| * @param lambda |
| * the {@link LambdaValue} |
| * @return the first element in the given {@link Collection} for which the {@link LambdaValue} is |
| * {@link LambdaValue#eval(Object[]) evaluated} to <code>true</code> if any, <code>null</code> |
| * otherwise |
| */ |
| public Object any(Collection<Object> self, LambdaValue lambda) { |
| Object result = null; |
| |
| if (self != null && lambda == null) { |
| result = null; |
| } else { |
| for (Object input : self) { |
| try { |
| if (Boolean.TRUE.equals(lambda.eval(new Object[] {input }))) { |
| result = input; |
| break; |
| } |
| // CHECKSTYLE:OFF |
| } catch (Exception e) { |
| // TODO: log the exception. |
| } |
| // CHECKSTYLE:ON |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Counts the number of times the given object is present in the given {@link Set}. |
| * |
| * @param set |
| * the {@link Set} |
| * @param object |
| * the {@link Object} |
| * @return the number of times the given object is present in the given {@link Set} |
| */ |
| public Integer count(Set<Object> set, Object object) { |
| final Integer result; |
| |
| if (set.contains(object)) { |
| result = Integer.valueOf(1); |
| } else { |
| result = Integer.valueOf(0); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Counts the number of times the given object is present in the given {@link List}. |
| * |
| * @param list |
| * the {@link List} |
| * @param object |
| * the {@link Object} |
| * @return the number of times the given object is present in the given {@link List} |
| */ |
| public Integer count(List<Object> list, Object object) { |
| int result = 0; |
| |
| if (object == null) { |
| for (Object input : list) { |
| if (input == null) { |
| ++result; |
| } |
| } |
| } else { |
| for (Object input : list) { |
| if (object.equals(input)) { |
| ++result; |
| } |
| } |
| } |
| |
| return Integer.valueOf(result); |
| } |
| |
| /** |
| * Tells if it exists an {@link Object} from the given {@link Collection} that validate the given |
| * {@link LambdaValue}. |
| * |
| * @param collection |
| * the {@link Collection} |
| * @param lambda |
| * the {@link LambdaValue} |
| * @return <code>true</code> if it exists an {@link Object} from the given {@link Collection} that |
| * validate the given {@link LambdaValue}, <code>false</code> otherwise |
| */ |
| public Boolean exists(Collection<Object> collection, LambdaValue lambda) { |
| Boolean result = Boolean.FALSE; |
| |
| if (collection != null && lambda == null) { |
| result = Boolean.FALSE; |
| } else { |
| for (Object input : collection) { |
| try { |
| if (Boolean.TRUE.equals(lambda.eval(new Object[] {input }))) { |
| result = Boolean.TRUE; |
| break; |
| } |
| // CHECKSTYLE:OFF |
| } catch (Exception e) { |
| // TODO: log the exception. |
| } |
| // CHECKSTYLE:ON |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Tells if all {@link Object} form the given {@link Collection} validates the given {@link LambdaValue}. |
| * |
| * @param collection |
| * the {@link Collection} |
| * @param lambda |
| * the {@link LambdaValue} |
| * @return <code>true</code> if all {@link Object} form the given {@link Collection} validates the given |
| * {@link LambdaValue}, <code>false</code> otherwise |
| */ |
| public Boolean forAll(Collection<Object> collection, LambdaValue lambda) { |
| Boolean result = Boolean.TRUE; |
| |
| if (collection != null && lambda == null) { |
| result = Boolean.FALSE; |
| } else { |
| for (Object input : collection) { |
| try { |
| if (!Boolean.TRUE.equals(lambda.eval(new Object[] {input }))) { |
| result = Boolean.FALSE; |
| break; |
| } |
| // CHECKSTYLE:OFF |
| } catch (Exception e) { |
| // TODO: log the exception. |
| result = Boolean.FALSE; |
| break; |
| } |
| // CHECKSTYLE:ON |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Tells if no elements of c2 are {@link Collection#contains(Object) contained} in self. |
| * |
| * @param self |
| * the current {@link Collection} |
| * @param c2 |
| * the other {@link Collection} |
| * @return <code>true</code> if no elements of c2 are {@link Collection#contains(Object) contained} in |
| * self, <code>false</code> otherwise |
| */ |
| public Boolean excludesAll(Collection<Object> self, Collection<Object> c2) { |
| boolean result = true; |
| |
| for (Object input : c2) { |
| if (self.contains(input)) { |
| result = false; |
| break; |
| } |
| } |
| |
| return Boolean.valueOf(result); |
| } |
| |
| /** |
| * Tells if all elements of c2 are {@link Collection#contains(Object) contained} in self. |
| * |
| * @param self |
| * the current {@link Collection} |
| * @param c2 |
| * the other {@link Collection} |
| * @return <code>true</code> if all elements of c2 are {@link Collection#contains(Object) contained} in |
| * self, <code>false</code> otherwise |
| */ |
| public Boolean includesAll(Collection<Object> self, Collection<Object> c2) { |
| return Boolean.valueOf(self.containsAll(c2)); |
| } |
| |
| /** |
| * Tells if {@link LambdaValue#eval(Object[]) evaluation} of the given lambda gives a different value for |
| * all element of the given {@link Collection}. |
| * |
| * @param self |
| * the {@link Collection} |
| * @param lambda |
| * the {@link LambdaValue} |
| * @return <code>true</code> if {@link LambdaValue#eval(Object[]) evaluation} of the given lambda gives a |
| * different value for all element of the given {@link Collection}, <code>false</code> otherwise |
| */ |
| public Boolean isUnique(Collection<Object> self, LambdaValue lambda) { |
| boolean result = true; |
| final Set<Object> evaluated = Sets.newHashSet(); |
| |
| if (self != null && lambda == null) { |
| result = false; |
| } else { |
| for (Object input : self) { |
| try { |
| if (!evaluated.add(lambda.eval(new Object[] {input }))) { |
| result = false; |
| break; |
| } |
| // CHECKSTYLE:OFF |
| } catch (Exception e) { |
| // TODO: log the exception. |
| } |
| // CHECKSTYLE:ON |
| } |
| } |
| |
| return Boolean.valueOf(result); |
| } |
| |
| /** |
| * Tells if one and only one element of the given {@link Collection} validates the given |
| * {@link LambdaValue}. |
| * |
| * @param self |
| * the current {@link Collection} |
| * @param lambda |
| * the {@link LambdaValue} |
| * @return <code>true</code> if one and only one element of the given {@link Collection} validates the |
| * given {@link LambdaValue}, <code>false</code> otherwise |
| */ |
| public Boolean one(Collection<Object> self, LambdaValue lambda) { |
| boolean result = false; |
| |
| if (self != null && lambda == null) { |
| result = false; |
| } else { |
| for (Object input : self) { |
| try { |
| if (Boolean.TRUE.equals(lambda.eval(new Object[] {input }))) { |
| result = !result; |
| if (!result) { |
| break; |
| } |
| } |
| // CHECKSTYLE:OFF |
| } catch (Exception e) { |
| // TODO: log the exception. |
| } |
| // CHECKSTYLE:ON |
| } |
| } |
| |
| return Boolean.valueOf(result); |
| } |
| |
| /** |
| * Sums elements of the given {@link Collection} if possible. |
| * |
| * @param self |
| * the current {@link Collection} |
| * @return the sum of elements of the given {@link Collection} if possible, throw an exception otherwise |
| */ |
| public Double sum(Collection<Object> self) { |
| double result = 0; |
| |
| for (Object input : self) { |
| if (input instanceof Number) { |
| result += ((Number)input).doubleValue(); |
| } else { |
| throw new IllegalArgumentException("Can only sum numbers."); |
| } |
| } |
| |
| return Double.valueOf(result); |
| } |
| |
| /** |
| * Gets the index of the given {@link Object} in the given {@link List}. |
| * |
| * @param self |
| * the {@link List} |
| * @param object |
| * the {@link Object} |
| * @return the index of the given {@link Object} in the given {@link List} [1..n] |
| */ |
| public Integer indexOf(List<Object> self, Object object) { |
| return Integer.valueOf(self.indexOf(object) + 1); |
| } |
| |
| /** |
| * Inserts the given {@link Object} in a copy of the given {@link List} at the given position ([1..n]). |
| * |
| * @param list |
| * the {@link List} |
| * @param position |
| * the position |
| * @param object |
| * the {@link Object} |
| * @return a copy of the given {@link List} |
| */ |
| public List<Object> insertAt(List<Object> list, Integer position, Object object) { |
| final int initialSize = list.size(); |
| if (position < 1 || position > initialSize) { |
| throw new IndexOutOfBoundsException(); |
| } |
| final List<Object> result = new ArrayList<Object>(initialSize + 1); |
| |
| result.addAll(list.subList(0, position - 1)); |
| result.add(object); |
| result.addAll(list.subList(position - 1, initialSize)); |
| |
| return result; |
| } |
| |
| /** |
| * Inserts the given {@link Object} in a copy of the given {@link List} at position 1. |
| * |
| * @param list |
| * the {@link List} |
| * @param object |
| * the {@link Object} |
| * @return a copy of the given {@link List} |
| */ |
| public List<Object> prepend(List<Object> list, Object object) { |
| final List<Object> result = new ArrayList<Object>(list.size() + 1); |
| |
| result.add(object); |
| result.addAll(list); |
| |
| return result; |
| } |
| |
| /** |
| * Creates a {@link Set} with elements from the given {@link Set} that are also present in the given |
| * {@link Collection}. |
| * |
| * @param <T> |
| * Type of the sets' elements. |
| * @param set1 |
| * the {@link Set} |
| * @param collection |
| * the {@link Set} |
| * @return the created {@link Set} with elements from the given {@link Set} that are also present in the |
| * given {@link Set} |
| */ |
| public <T> Set<T> intersection(Set<T> set1, Collection<?> collection) { |
| if (collection instanceof Set<?>) { |
| return Sets.intersection(set1, (Set<?>)collection); |
| } |
| final Set<T> result = Sets.newLinkedHashSet(set1); |
| result.retainAll(collection); |
| return result; |
| } |
| |
| /** |
| * Creates a {@link List} with elements from the given {@link List} that are present in both {@code list1} |
| * and the given other {@code Collection}. Iteration order will match that of {@code list1}. Duplicates |
| * from the first list will all be kept in the result if they also are in the second one, but duplicates |
| * from the second list will be dumped even if they are present in the first. |
| * |
| * @param <T> |
| * Type of the collections' elements. |
| * @param list1 |
| * the first {@link List} |
| * @param collection |
| * the second {@link List} |
| * @return the intersection of both lists. |
| */ |
| public <T> List<T> intersection(List<T> list1, Collection<?> collection) { |
| final List<T> result = Lists.newArrayList(list1); |
| result.retainAll(collection); |
| return result; |
| } |
| |
| /** |
| * Gets a subset of the given {@link Set}. |
| * |
| * @param set |
| * the {@link Set} |
| * @param startIndex |
| * low end point (inclusive) of the sub-set |
| * @param endIndex |
| * high end point (inclusive) of the sub-set |
| * @return a subset of the given {@link Set} |
| * @throws IndexOutOfBoundsException |
| * for an illegal end point value ( |
| * <code>startIndex < 1 || endIndex > set.size() || startIndex > endIndex</code>) |
| */ |
| public Set<Object> subOrderedSet(Set<Object> set, Integer startIndex, Integer endIndex) { |
| if (startIndex < 1 || endIndex > set.size() || startIndex > endIndex) { |
| throw new IndexOutOfBoundsException(); |
| } |
| final Set<Object> result = new LinkedHashSet<Object>(endIndex - startIndex + 1); |
| |
| int index = 1; |
| for (Object input : set) { |
| if (index >= startIndex) { |
| if (index <= endIndex) { |
| result.add(input); |
| } else { |
| break; |
| } |
| } |
| ++index; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Gets a sub sequence of the given {@link List}. |
| * |
| * @param list |
| * the {@link List} |
| * @param startIndex |
| * low end point (inclusive) of the sub-set |
| * @param endIndex |
| * high end point (inclusive) of the sub-set |
| * @return a subset of the given {@link List} |
| * @throws IndexOutOfBoundsException |
| * for an illegal end point value ( |
| * <code>startIndex < 1 || endIndex > set.size() || startIndex > endIndex</code>) |
| */ |
| public List<Object> subSequence(List<Object> list, Integer startIndex, Integer endIndex) { |
| if (startIndex < 1 || endIndex > list.size() || startIndex > endIndex) { |
| throw new IndexOutOfBoundsException(); |
| } |
| final List<Object> result = new ArrayList<Object>(endIndex - startIndex + 1); |
| |
| int index = 1; |
| for (Object input : list) { |
| if (index >= startIndex) { |
| if (index <= endIndex) { |
| result.add(input); |
| } else { |
| break; |
| } |
| } |
| ++index; |
| } |
| |
| return result; |
| } |
| |
| } |