/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ignite.internal.util.gridify;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteException;
import org.apache.ignite.compute.gridify.GridifyArgument;
import org.apache.ignite.compute.gridify.GridifyInput;
import org.apache.ignite.compute.gridify.GridifySetToSet;
import org.apache.ignite.compute.gridify.GridifySetToValue;
import org.apache.ignite.compute.gridify.aop.GridifyArgumentAdapter;
/**
* Argument builder used for creating arguments for tasks and jobs in gridified methods.
* @see GridifySetToValue
* @see GridifySetToSet
*/
public final class GridifyArgumentBuilder {
/**
* Create argument for task.
*
* @param mtdCls Method class.
* @param mtdName Method name.
* @param mtdReturnType Method return type.
* @param mtdTypes Method parameter types.
* @param mtdParamAnns Method parameter annotations.
* @param mtdParams Method parameters.
* @param mtdTarget Target object.
* @return Argument for task.
*/
public GridifyRangeArgument createTaskArgument(
Class<?> mtdCls,
String mtdName,
Class<?> mtdReturnType,
Class<?>[] mtdTypes,
Annotation[][] mtdParamAnns,
Object[] mtdParams,
Object mtdTarget) {
GridifyRangeArgument arg = new GridifyRangeArgument();
arg.setMethodClass(mtdCls);
arg.setMethodName(mtdName);
arg.setMethodReturnType(mtdReturnType);
arg.setMethodParameterTypes(mtdTypes);
arg.setMethodParameters(mtdParams);
arg.setTarget(mtdTarget);
arg.setParamIndex(findMethodParameterIndex(mtdName, mtdTypes, mtdParamAnns));
return arg;
}
/**
* Find parameter index where elements should be placed.
*
* @param mtdName Method name.
* @param mtdTypes Method parameter types.
* @param mtdParamAnns Method parameter annotations.
* @return Parameter index where elements should be placed.
*/
private int findMethodParameterIndex(
String mtdName,
Class<?>[] mtdTypes,
Annotation[][] mtdParamAnns) {
List<Integer> allowedParamIdxs = new ArrayList<>(mtdTypes.length);
for (int i = 0; i < mtdTypes.length; i++) {
Class<?> paramType = mtdTypes[i];
if (GridifyUtils.isMethodParameterTypeAllowed(paramType))
allowedParamIdxs.add(i);
}
assert !allowedParamIdxs.isEmpty() : "Invalid method signature. Failed to get valid method parameter " +
"types [mtdName=" + mtdName + ", mtdTypes=" + Arrays.asList(mtdTypes) + ']';
if (allowedParamIdxs.size() == 1)
return allowedParamIdxs.get(0);
List<Integer> annParamIdxs = new ArrayList<>(mtdTypes.length);
for (int i = 0; i < mtdTypes.length; i++) {
if (GridifyUtils.isMethodParameterTypeAnnotated(mtdParamAnns[i]))
annParamIdxs.add(i);
}
assert annParamIdxs.size() == 1 : "Invalid method signature. Method parameter must be annotated with @" +
GridifyInput.class.getSimpleName() + "[mtdName=" + mtdName + ", mtdTypes=" + Arrays.asList(mtdTypes) +
", allowedParamIdxs=" + allowedParamIdxs + ", annParamIdxs=" + annParamIdxs + ']';
return annParamIdxs.get(0);
}
/**
* Create {@link GridifyRangeArgument} for task.
*
* @param arg Task argument contains all necessary data for method invoke.
* @param input Input collection..
* @return Argument for task.
* @throws IgniteCheckedException In case of error.
*/
public GridifyRangeArgument createTaskArgument(GridifyRangeArgument arg, Collection<?> input) throws IgniteCheckedException {
GridifyRangeArgument res = new GridifyRangeArgument();
res.setTarget(arg.getTarget());
res.setMethodClass(arg.getMethodClass());
res.setMethodName(arg.getMethodName());
res.setMethodReturnType(arg.getMethodReturnType());
res.setMethodParameterTypes(arg.getMethodParameterTypes());
res.setParamIndex(arg.getParamIndex());
Object[] mtdArgs = new Object[arg.getMethodParameters().length];
System.arraycopy(arg.getMethodParameters(), 0, mtdArgs, 0, arg.getMethodParameters().length);
res.setMethodParameters(mtdArgs);
assert arg.getParamIndex() != -1;
Class<?> paramCls = arg.getMethodParameterTypes()[arg.getParamIndex()];
assert paramCls != null;
Object paramValue = GridifyUtils.collectionToParameter(paramCls, input);
if (paramValue == null)
throw new IgniteCheckedException("Failed to create task argument for type: " + paramCls.getName());
mtdArgs[arg.getParamIndex()] = paramValue;
return res;
}
/**
* Create {@link org.apache.ignite.compute.gridify.GridifyArgument} for job.
*
* @param arg Task argument contains all necessary data for method invoke.
* @param input Input collection used in job.
* @return Argument for job.
* @throws IgniteException In case of error.
*/
public GridifyArgument createJobArgument(GridifyRangeArgument arg, Collection<?> input) throws IgniteException {
GridifyArgumentAdapter res = new GridifyArgumentAdapter();
res.setTarget(arg.getTarget());
res.setMethodClass(arg.getMethodClass());
res.setMethodName(arg.getMethodName());
res.setMethodParameterTypes(arg.getMethodParameterTypes());
Object[] mtdArgs = new Object[arg.getMethodParameters().length];
System.arraycopy(arg.getMethodParameters(), 0, mtdArgs, 0, arg.getMethodParameters().length);
res.setMethodParameters(mtdArgs);
assert arg.getParamIndex() != -1;
Class<?> paramCls = arg.getMethodParameterTypes()[arg.getParamIndex()];
assert paramCls != null;
Object paramValue = GridifyUtils.collectionToParameter(paramCls, input);
if (paramValue == null)
throw new IgniteException("Failed to create job argument for type: " + paramCls.getName());
mtdArgs[arg.getParamIndex()] = paramValue;
return res;
}
}