package com.framsticks.params; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import com.framsticks.params.types.EventParam; import com.framsticks.params.types.ProcedureParam; import com.framsticks.util.FramsticksException; import com.framsticks.util.Misc; import static com.framsticks.util.lang.Containers.*; /** * The Class ReflectionAccess. Stores data in provided object using reflection. * * @author Mateusz Jarus (please replace name and * surname with my personal data) * * @author Piotr Sniegowski */ public class ReflectionAccess extends SimpleAbstractAccess { private final static Logger log = LogManager.getLogger(ReflectionAccess.class.getName()); protected final Class javaClass; protected final ReflectionAccessBackend backend; private Object object; public ReflectionAccess(Class javaClass) throws ConstructionException { this(javaClass, FramsClass.build().forClass(javaClass)); } public ReflectionAccess(Class javaClass, FramsClass framsClass) throws ConstructionException { this(javaClass, framsClass, ReflectionAccessBackend.getOrCreateFor(javaClass, framsClass)); } protected ReflectionAccess(Class javaClass, FramsClass framsClass, ReflectionAccessBackend backend) throws ConstructionException { super(framsClass); this.javaClass = javaClass; this.backend = backend; } @Override public ReflectionAccess cloneAccess() { return new ReflectionAccess(javaClass, framsClass, backend); } @Override public T get(ValueParam param, Class type) { try { try { if (object == null) { throw new FramsticksException().msg("no object set"); } return backend.getters.get(param.getId()).get(object, type); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new FramsticksException().msg("failed to get").cause(e); } } catch (FramsticksException e) { throw e.arg("param", param).arg("type", type).arg("access", this); } } @Override protected void internalSet(ValueParam param, T value) { setValue(param, value); } private void setValue(ValueParam param, T value) { try { try { if (object == null) { throw new FramsticksException().msg("no object set"); } ReflectionAccessBackend.ReflectedSetter s = backend.setters.get(param.getId()); if (s == null) { throw new FramsticksException().msg("trying to set unsettable"); // return; // if (value != backend.getters.get(param).get(object, Object.class)) { // } } s.set(object, value); } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) { throw new FramsticksException().msg("failed to set").cause(e); } } catch (FramsticksException e) { throw e.arg("param", param).arg("value", value).arg("value type", Misc.getClass(value)).arg("access", this); } } @Override public void reg(EventParam param, EventListener listener) { try { try { if (object == null) { throw new FramsticksException().msg("no object set"); } backend.adders.get(param.getId()).reg(object, listener); return; } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new FramsticksException().msg("failed to add listener").cause(e); } } catch (FramsticksException e) { throw e.arg("param", param).arg("access", this); } } @Override public void regRemove(EventParam param, EventListener listener) { try { try { if (object == null) { throw new FramsticksException().msg("no object set"); } backend.removers.get(param.getId()).regRemove(object, listener); return; } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new FramsticksException().msg("failed to remove listener").cause(e); } } catch (FramsticksException e) { throw e.arg("param", param).arg("access", this); } } @Override public Object call(String id, Object... arguments) { try { try { if (object == null) { throw new FramsticksException().msg("no object set"); } ReflectionAccessBackend.ReflectedCaller c = backend.callers.get(id); if (c == null) { throw new FramsticksException().msg("method is not bound"); } return c.call(object, arguments); } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) { throw new FramsticksException().msg("failed to call").cause(e); } } catch (FramsticksException e) { throw e.arg("param", framsClass.getParam(id)).arg("access", this); } } @Override public Object call(ProcedureParam param, Object... arguments) { return call(param.getId(), arguments); } @Override public void clearValues() { if (object == null) { return; } try { for (ValueParam p : filterInstanceof(framsClass.getParams(), ValueParam.class)) { setValue(p, p.getDef(Object.class)); } } catch (IllegalArgumentException ex) { ex.printStackTrace(); } } /** * Sets the new object to operate on. * * @param object * new object to operate on */ @Override public ReflectionAccess select(Object object) { this.object = ParamsUtil.selectObjectForAccess(this, object, javaClass); return this; } @Override public Object getSelected() { return object; } @Override public Object createAccessee() { try { return javaClass.newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new FramsticksException().msg("failed to create reflected object").arg("java class", javaClass).arg("frams class", framsClass).cause(e); } } @Override public void tryAutoAppend(Object value) { assert object != null; try { for (Method m : backend.autoAppendMethods) { if (m.getParameterTypes()[0].isAssignableFrom(value.getClass())) { try { log.trace("auto appending with value {} with method {}", value, m); m.invoke(object, value); return; } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | FramsticksException e) { throw new FramsticksException().msg("failed to auto append").cause(e).arg("with method", m); } } } throw new FramsticksException().msg("no method found to append"); } catch (FramsticksException e) { throw e.arg("value", value).arg("into object", object); } } @Override public String toString() { StringBuilder b = new StringBuilder(); b.append(framsClass); if (getSelected() != null) { b.append("(").append(getSelected()).append(")"); } return b.toString(); } }