/*
* Copyright 2005-2010 Ignis Software Tools Ltd. All rights reserved.
*/
package jsystem.extensions.paramproviders;
import jsystem.framework.TestBeanClass;
import jsystem.framework.scenario.*;
import jsystem.runner.loader.LoadersManager;
import jsystem.treeui.utilities.MultiPropertiesDialog;
import jsystem.treeui.utilities.ParameterProviderListener;
import jsystem.utils.StringUtils;
import jsystem.utils.beans.BeanElement;
import jsystem.utils.beans.BeanUtils;
import java.awt.*;
import java.awt.Dialog.ModalityType;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.List;
public class ObjectArrayParameterProvider extends AbstractSerializingParameterProvider {
private static Logger log = Logger.getLogger(ObjectArrayParameterProvider.class.getName());
private List<ParameterProviderListener> listenersList = new ArrayList<ParameterProviderListener>();
public ObjectArrayParameterProvider() {
}
@Override
public String getAsString(Object o) {
// if the input object is null or is of type String return
if (o == null) {
return null;
}
if (o instanceof String) {
return (String) o;
}
if (!o.getClass().isArray()) {
return null;
}
Object[] array = (Object[]) o;
ArrayList<BeanElement> beanElements = BeanUtils.getBeans(o.getClass().getComponentType(), true, true,
BeanUtils.getBasicTypes());
// build properties object from the given object
Properties properties = new Properties();
for (int i = 0; i < array.length; i++) {
for (BeanElement be : beanElements) {
if (be.getGetMethod() == null) {
continue;
}
try {
Object value = be.getGetMethod().invoke(array[i], new Object[0]);
if (value != null) {
properties.setProperty(i + "." + be.getName(), StringUtils.advancedToString(value));
}
} catch (Exception e) {
log.log(Level.WARNING, "Fail to invoke the getter: " + be.getName(), e);
}
}
}
return propetiesToString(o.getClass().getComponentType().getName(), properties);
}
@Override
public Object getFromString(String stringRepresentation) throws Exception {
// if the input is null return null object
if (stringRepresentation == null) {
return null;
}
// first extract the class name
int classEndIndex = stringRepresentation.indexOf(';');
if (classEndIndex < 0) {
return null;
}
String className = stringRepresentation.substring(0, classEndIndex);
// then extract the string to be load as properties object
String propertiesString = stringRepresentation.substring(classEndIndex + 1);
Properties properties = new Properties();
try {
properties.load(new StringReader(propertiesString));
} catch (IOException e1) {
log.log(Level.WARNING, "Fail to load properties: " + propertiesString, e1);
return null;
}
// create the class from the input string
Class<?> c;
try {
c = LoadersManager.getInstance().getLoader().loadClass(className);
} catch (ClassNotFoundException e) {
log.log(Level.WARNING, "Fail to create class: " + className, e);
return null;
}
// create the object and init it using the properties
ArrayList<Properties> splitProperties = splitProperties(properties);
Object[] array = (Object[]) Array.newInstance(c, splitProperties.size());
for (int i = 0; i < array.length; i++) {
array[i] = BeanUtils.propertiesToObject(c, propertiesToMap(splitProperties.get(i)));
}
return array;
}
@Override
public boolean isFieldEditable() {
return false;
}
@Override
public synchronized Object showUI(Component parent, Scenario currentScenario, RunnerTest rtest, Class<?> classType,
Object object, Parameter parameter) throws Exception {
if (!classType.isArray()) {
throw new RuntimeException("ObjectArrayParameter must be of array type! current type is : " + classType);
}
ArrayList<BeanElement> beanElements = BeanUtils.getBeans(classType.getComponentType(), true, true,
BeanUtils.getBasicTypes());
ArrayList<LinkedHashMap<String, String>> multiMap = new ArrayList<LinkedHashMap<String, String>>();
if (object != null) {
Object[] array = null;
try {
array = (Object[]) object;
} catch (ClassCastException e) {
throw new RuntimeException("ObjectArrayParameter got wrong parameter! expected array type, got: "
+ object.getClass() + ", with value: " + object);
}
for (int i = 0; i < array.length; i++) {
Properties oProperties = BeanUtils.objectToProperties(array[i], beanElements);
multiMap.add(propertiesToMapBeanOrder(oProperties, beanElements));
}
}
// the user can specified using <code>TestBeanClass</code> annotation
// new data model class.
TestBeanClass tbc = classType.getComponentType().getAnnotation(TestBeanClass.class);
BeanCellEditorModel beanCellEditorModel = null;
if (tbc != null) {
// create the new data model
Class<?> modelClass = tbc.model();
if (!modelClass.equals(UseDefaultDataModel.class)) {
Constructor<?> cons = modelClass.getConstructor(beanElements.getClass(), multiMap.getClass());
if (cons != null) {
Object dataModel = cons.newInstance(beanElements, multiMap);
if (dataModel instanceof BeanCellEditorModel) {
beanCellEditorModel = (BeanCellEditorModel) dataModel;
}
}
}
}
MultiPropertiesDialog dialog = new MultiPropertiesDialog(multiMap, "Bean properties", beanElements,
propertiesToMapBeanOrder(
BeanUtils.objectToProperties(classType.getComponentType().newInstance(), beanElements),
beanElements), beanCellEditorModel, parameter.isEditable());
dialog.setModalityType(ModalityType.APPLICATION_MODAL);
dialog.setListeners(listenersList);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int screenHeight = screenSize.height;
int screenWidth = screenSize.width;
dialog.setLocation(screenWidth / 4, screenHeight / 5);
if (dialog.showAndWaitForApprove()) {
Object[] array = (Object[]) Array.newInstance(classType.getComponentType(), multiMap.size());
for (int i = 0; i < array.length; i++) {
array[i] = BeanUtils.propertiesToObject(classType.getComponentType(), multiMap.get(i));
}
return array;
}
return object;
}
private static LinkedHashMap<String, String> propertiesToMap(Properties properties) {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
Set<Object> keys = properties.keySet();
for (Object key : keys) {
map.put(key.toString(), properties.getProperty(key.toString()));
}
return map;
}
private static LinkedHashMap<String, String> propertiesToMapBeanOrder(Properties properties,
ArrayList<BeanElement> elements) {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
for (BeanElement be : elements) {
String value = properties.getProperty(be.getName());
if (value != null) {
map.put(be.getName(), value);
}
}
return map;
}
private static ArrayList<Properties> splitProperties(Properties properties) {
HashMap<Integer, Properties> propertiesMap = new HashMap<Integer, Properties>();
Enumeration<?> keys = properties.keys();
while (keys.hasMoreElements()) {
String key = keys.nextElement().toString();
String value = properties.getProperty(key);
String[] keyElements = key.split("\\.");
int index = Integer.parseInt(keyElements[0]);
Properties prop = propertiesMap.get(index);
if (prop == null) {
prop = new Properties();
propertiesMap.put(index, prop);
}
prop.setProperty(keyElements[1], value);
}
ArrayList<Properties> toReturn = new ArrayList<Properties>();
int i = 0;
while (true) {
Properties prop = propertiesMap.get(i);
if (prop != null) {
toReturn.add(prop);
i++;
} else {
break;
}
}
return toReturn;
}
@Override
public void setProviderConfig(String... args) {
for (String arg : args) {
if (StringUtils.isEmpty(arg)) {
continue;
}
if (arg.startsWith("listeners=")) {
registerListeners(arg.replaceFirst("listeners=", ""));
}
}
}
/**
* This allows the user to add listeners that would receive events for any
* changes that occurs in the dialog. The listeners are specified using the @UseProvider
* annotation. <br>
* e.g: <br>
*
* @UseProvider(provider =
* jsystem.extensions.paramproviders.ObjectArrayParameterProvider
* .class,config = {"listeners=org.jsystem.Listener"}) <br>
*
* Multiple providers can be specified using the ';'
* delimiter
*
*
* @param listeners
*/
private void registerListeners(String listeners) {
for (String listenerStr : listeners.split(";")) {
ParameterProviderListener listener = null;
try {
listener = (ParameterProviderListener) LoadersManager.getInstance().getLoader().loadClass(listenerStr)
.newInstance();
} catch (Exception e) {
log.log(Level.WARNING,
"Failed to create instance of type " + ParameterProviderListener.class.getName(), e);
continue;
}
listenersList.add(listener);
}
}
}