| /******************************************************************************* |
| * Copyright (c) 2011 University of Illinois 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: |
| * Albert L. Rossi - design and implementation |
| ******************************************************************************/ |
| |
| package org.eclipse.ptp.rm.jaxb.core.data.impl; |
| |
| import java.lang.reflect.Method; |
| import java.math.BigInteger; |
| import java.util.List; |
| |
| import org.eclipse.ptp.rm.jaxb.core.IAssign; |
| import org.eclipse.ptp.rm.jaxb.core.IJAXBNonNLSConstants; |
| import org.eclipse.ptp.rm.jaxb.core.data.AddType; |
| import org.eclipse.ptp.rm.jaxb.core.data.AppendType; |
| import org.eclipse.ptp.rm.jaxb.core.data.EntryType; |
| import org.eclipse.ptp.rm.jaxb.core.data.PutType; |
| import org.eclipse.ptp.rm.jaxb.core.data.SetType; |
| import org.eclipse.ptp.rm.jaxb.core.variables.RMVariableMap; |
| |
| /** |
| * Base class for the wrappers around the data objects providing information as |
| * to the operations on a target property to be undertaken when there is a |
| * match. |
| * |
| * @author arossi |
| * |
| */ |
| public abstract class AbstractAssign implements IAssign, IJAXBNonNLSConstants { |
| |
| protected String uuid; |
| protected String field; |
| protected Object target; |
| protected int index; |
| |
| protected AbstractAssign() { |
| uuid = null; |
| field = null; |
| target = null; |
| index = 0; |
| } |
| |
| /** |
| * Applies the assignment. |
| * |
| * @param values |
| * from the expression parsing (groups or segments) |
| * @throws Throwable |
| */ |
| public void assign(String[] values) throws Throwable { |
| Object previous = get(target, field); |
| set(target, field, getValue(previous, values)); |
| index++; |
| } |
| |
| /** |
| * Used in the case of references to targets constructed in connection with |
| * the tokenization. The assumption is that an Assign action will be applied |
| * only once to any given target, in the order of their construction; this |
| * index keeps track of where this particular assign action is in the list. |
| * |
| * @return the index of the current target |
| */ |
| public int getIndex() { |
| return index; |
| } |
| |
| /** |
| * @param target |
| * the current property or attribute |
| */ |
| public void setTarget(Object target) { |
| this.target = target; |
| } |
| |
| /** |
| * Decides whether the index of the map key is a segment (from |
| * regex.split()) or a regex group number. |
| * |
| * @param entry |
| * from the target map |
| * @return the key index |
| */ |
| protected int determineKeyIndex(EntryType entry) { |
| int index = entry.getKeyIndex(); |
| int group = entry.getKeyGroup(); |
| if (index == 0 && group != 0) { |
| index = group; |
| } |
| return index; |
| } |
| |
| /** |
| * Decides whether the index of the map value is a segment (from |
| * regex.split()) or a regex group number. |
| * |
| * @param entry |
| * carries the key and value indices |
| * @see org.eclipse.ptp.rm.jaxb.core.data.Entry |
| * @return the value index |
| */ |
| protected int determineValueIndex(EntryType entry) { |
| int index = entry.getValueIndex(); |
| int group = entry.getValueGroup(); |
| if (index == 0 && group != 0) { |
| index = group; |
| } |
| return index; |
| } |
| |
| /** |
| * Find the map key |
| * |
| * @param entry |
| * carries the key and value indices |
| * @see org.eclipse.ptp.rm.jaxb.core.data.Entry |
| * @param values |
| * the parsed result of the expression match |
| * @return key |
| * @throws Throwable |
| */ |
| protected String getKey(EntryType entry, String[] values) throws Throwable { |
| String k = entry.getKey(); |
| if (k != null) { |
| return (String) normalizedValue(target, uuid, k, false); |
| } |
| int index = determineKeyIndex(entry); |
| if (values != null) { |
| return values[index]; |
| } |
| return null; |
| } |
| |
| /** |
| * Find the map value |
| * |
| * @param entry |
| * carries the key and value indices |
| * @see org.eclipse.ptp.rm.jaxb.core.data.Entry |
| * @param values |
| * the parsed result of the expression match |
| * @return value |
| * @throws Throwable |
| */ |
| protected Object getValue(EntryType entry, String[] values) throws Throwable { |
| String v = entry.getValue(); |
| if (v != null) { |
| return normalizedValue(target, uuid, v, true); |
| } |
| int index = determineValueIndex(entry); |
| if (values != null) { |
| return values[index]; |
| } |
| return null; |
| } |
| |
| /** |
| * Method specific to the assign type for retrieving the values from the |
| * matched expression. |
| * |
| * @param previous |
| * the value currently assigned to the field of the target in |
| * question. |
| * @param values |
| * the parsed result of the expression match |
| * @return the value(s) retrieved from the parsed result |
| * @throws Throwable |
| */ |
| protected abstract Object[] getValue(Object previous, String[] values) throws Throwable; |
| |
| /** |
| * Auxiliary for adding a wrapper implementation. |
| * |
| * @param uuid |
| * unique id associated with this resource manager operation (can |
| * be <code>null</code>). |
| * @param assign |
| * the JAXB element class. |
| * @param list |
| * the list of wrappers |
| */ |
| static void add(String uuid, Object assign, List<IAssign> list) { |
| if (assign instanceof AddType) { |
| AddType add = (AddType) assign; |
| list.add(new AddImpl(uuid, add)); |
| return; |
| } |
| if (assign instanceof AppendType) { |
| AppendType append = (AppendType) assign; |
| list.add(new AppendImpl(uuid, append)); |
| return; |
| } |
| if (assign instanceof PutType) { |
| PutType put = (PutType) assign; |
| list.add(new PutImpl(uuid, put)); |
| return; |
| } |
| if (assign instanceof SetType) { |
| SetType set = (SetType) assign; |
| list.add(new SetImpl(uuid, set)); |
| return; |
| } |
| } |
| |
| /** |
| * Auxiliary using Java reflection to perform a get on the target. |
| * |
| * @param target |
| * Property or Attribute |
| * @param field |
| * on the target from which to retrieve the value. |
| * @return value of the field |
| * @throws Throwable |
| */ |
| static Object get(Object target, String field) throws Throwable { |
| String name = GET + field.substring(0, 1).toUpperCase() + field.substring(1); |
| Method method = null; |
| try { |
| method = target.getClass().getMethod(name, (Class[]) null); |
| } catch (Throwable t) { |
| name = IS + field.substring(0, 1).toUpperCase() + field.substring(1); |
| method = target.getClass().getMethod(name, (Class[]) null); |
| } |
| return method.invoke(target, (Object[]) null); |
| } |
| |
| /** |
| * Determines whether the input represents an object field or a resolvable |
| * expression. Also converts string to int or boolean, if applicable, |
| * |
| * @param target |
| * on which to apply the getter. |
| * @param uuid |
| * unique id associated with this resource manager operation (can |
| * be <code>null</code>). |
| * @param expression |
| * input to be interpreted |
| * @param convert |
| * expression to boolean or int, if applicable. |
| * |
| * @return value after dereferencing or normalization |
| * @throws Throwable |
| */ |
| static Object normalizedValue(Object target, String uuid, String expression, boolean convert) throws Throwable { |
| if (expression.startsWith(PD)) { |
| if (target == null) { |
| return null; |
| } |
| String field = expression.substring(1); |
| return AbstractAssign.get(target, field); |
| } else if (expression.indexOf(OPENV) >= 0) { |
| expression = RMVariableMap.getActiveInstance().getString(uuid, expression); |
| return RMVariableMap.getActiveInstance().getString(uuid, expression); |
| } else if (convert) { |
| if (TRUE.equalsIgnoreCase(expression)) { |
| return true; |
| } |
| if (FALSE.equalsIgnoreCase(expression)) { |
| return false; |
| } |
| try { |
| if (expression.indexOf(DOT) >= 0) { |
| return new Double(expression); |
| } |
| return new Integer(expression); |
| } catch (NumberFormatException nfe) { |
| return expression; |
| } |
| } |
| return expression; |
| } |
| |
| /** |
| * Auxiliary using Java reflection to perform a set on the target. |
| * |
| * @param target |
| * Property or Attribute |
| * @param field |
| * on the target on which to set the value. |
| * @param values |
| * corresonding to the parameter(s) of the set method (usually a |
| * single one) |
| * @throws Throwable |
| */ |
| static void set(Object target, String field, Object[] values) throws Throwable { |
| String name = SET + field.substring(0, 1).toUpperCase() + field.substring(1); |
| Method[] methods = target.getClass().getMethods(); |
| Method setter = null; |
| for (Method m : methods) { |
| if (m.getName().equals(name)) { |
| setter = m; |
| } |
| } |
| if (setter == null) { |
| throw new NoSuchMethodException(name + CO + SP + target); |
| } |
| if (values[0] != null) { |
| Class<?>[] mclzz = setter.getParameterTypes(); |
| // better have 1 parameter |
| Class<?> param = mclzz[0]; |
| Class<?> valueClass = values[0].getClass(); |
| Throwable t = new IllegalArgumentException(name + SP + valueClass); |
| if (!param.equals(Object.class) && !param.isAssignableFrom(values[0].getClass())) { |
| if (valueClass.equals(String.class)) { |
| if (param.equals(Boolean.class)) { |
| values[0] = new Boolean(values[0].toString()); |
| } else if (param.equals(Integer.class)) { |
| values[0] = new Integer(values[0].toString()); |
| } else if (param.equals(BigInteger.class)) { |
| values[0] = new BigInteger(values[0].toString()); |
| } else { |
| throw t; |
| } |
| } else if (valueClass.equals(Integer.class) || valueClass.equals(BigInteger.class) |
| || valueClass.equals(Boolean.class)) { |
| if (param.equals(String.class)) { |
| values[0] = values[0].toString(); |
| } else { |
| throw t; |
| } |
| } else { |
| throw t; |
| } |
| } |
| } |
| setter.invoke(target, values); |
| } |
| } |