/*******************************************************************************
* (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Apache License v2.0 which accompany this distribution.
*
* The Apache License is available at
* http://www.apache.org/licenses/LICENSE-2.0
*
*******************************************************************************/
package io.cloudslang.lang.runtime.steps;
import com.hp.oo.sdk.content.annotations.Param;
import com.hp.oo.sdk.content.plugin.GlobalSessionObject;
import com.hp.oo.sdk.content.plugin.SerializableSessionObject;
import io.cloudslang.runtime.api.java.JavaExecutionParametersProvider;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Created by Genadi Rabinovich, genadi@hpe.com on 17/05/2016.
*/
public class CloudSlangJavaExecutionParameterProvider implements JavaExecutionParametersProvider {
private static final String PARAM_CLASS_NAME = Param.class.getCanonicalName();
private static final String GLOBAL_SESSION_OBJECT_CLASS_NAME = GlobalSessionObject.class.getCanonicalName();
private static final String SERIALIZABLE_SESSION_OBJECT = SerializableSessionObject.class.getCanonicalName();
private final Map<String, SerializableSessionObject> serializableSessionData;
private final Map<String, Serializable> currentContext;
private final Map<String, Object> nonSerializableExecutionData;
public CloudSlangJavaExecutionParameterProvider(Map<String, SerializableSessionObject> serializableSessionData,
Map<String, Serializable> currentContext,
Map<String, Object> nonSerializableExecutionData) {
this.serializableSessionData = serializableSessionData;
this.currentContext = currentContext;
this.nonSerializableExecutionData = nonSerializableExecutionData;
}
@Override
public Object[] getExecutionParameters(Method executionMethod) {
List<Object> args = new ArrayList<>();
int index = 0;
Class[] parameterTypes = executionMethod.getParameterTypes();
for (Annotation[] annotations : executionMethod.getParameterAnnotations()) {
index++;
for (Annotation annotation : annotations) {
String parameterName = getValueIfParamAnnotation(annotation);
if (parameterName != null) {
String paramClassName = parameterTypes[index - 1].getCanonicalName();
if (paramClassName.equals(GLOBAL_SESSION_OBJECT_CLASS_NAME)) {
handleSessionContextArgument(nonSerializableExecutionData,
GLOBAL_SESSION_OBJECT_CLASS_NAME, args, parameterName,
annotation.getClass().getClassLoader());
} else if (paramClassName.equals(SERIALIZABLE_SESSION_OBJECT)) {
handleSessionContextArgument(serializableSessionData, SERIALIZABLE_SESSION_OBJECT,
args, parameterName,
annotation.getClass().getClassLoader());
} else {
Serializable value = currentContext.get(parameterName);
Class parameterClass = parameterTypes[index - 1];
if (parameterClass.isInstance(value) || value == null) {
args.add(value);
} else {
StringBuilder exceptionMessageBuilder = new StringBuilder();
exceptionMessageBuilder.append("Parameter type mismatch for action ");
exceptionMessageBuilder.append(executionMethod.getName());
exceptionMessageBuilder.append(" of class ");
exceptionMessageBuilder.append(executionMethod.getDeclaringClass().getName());
exceptionMessageBuilder.append(". Parameter ");
exceptionMessageBuilder.append(parameterName);
exceptionMessageBuilder.append(" expects type ");
exceptionMessageBuilder.append(parameterClass.getName());
exceptionMessageBuilder.append(". Actual type is ");
exceptionMessageBuilder.append(value.getClass().getName());
throw new RuntimeException(exceptionMessageBuilder.toString());
}
}
}
}
if (args.size() != index) {
throw new RuntimeException("All action arguments should be annotated with @Param");
}
}
return args.toArray(new Object[args.size()]);
}
private String getValueIfParamAnnotation(Annotation annotation) {
Class<? extends Annotation> annotationType = annotation.annotationType();
if (PARAM_CLASS_NAME.equalsIgnoreCase(annotation.annotationType().getCanonicalName())) {
try {
return (String) annotationType.getMethod("value", new Class[0]).invoke(annotation, new Object[0]);
} catch (Exception e) {
throw new RuntimeException("Failed to get value from " + Param.class.getCanonicalName() +
" annotation", e);
}
}
return null;
}
private void handleSessionContextArgument(Map sessionData, String objectClassName, List<Object> args,
String parameterName, ClassLoader classLoader) {
Object sessionContextObject = sessionData.get(parameterName);
if (sessionContextObject == null) {
try {
sessionContextObject = Class.forName(objectClassName, true, classLoader).newInstance();
} catch (Exception e) {
throw new RuntimeException("Failed to create instance of [" + objectClassName + "] class", e);
}
//noinspection unchecked
sessionData.put(parameterName, sessionContextObject);
}
args.add(sessionContextObject);
}
}