/*
* 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.synapse.mediators.bean;
import org.apache.synapse.MessageContext;
import org.apache.synapse.SynapseException;
import org.apache.synapse.SynapseLog;
import org.apache.synapse.mediators.AbstractMediator;
import org.apache.synapse.mediators.Value;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.util.Map;
/**
* Bean mediator can manipulate a JavaBean that is bound to the Synapse message context as a
* property.
* This mediator can be used to create a new bean (CREATE action), remove an existing bean
* (REMOVE action), set a property of an existing JavaBean (SET_PROPERTY action) or to retrieve a
* property of an existing JavaBean (GET_PROPERTY) action.
*/
public class BeanMediator extends AbstractMediator {
/**
* Action performed by this mediator.
*/
private Action action;
/**
* Variable name. This corresponds to the property name using which the bean is attached to
* the message context
*/
private String varName;
/**
* Name of the bean property.
*/
private String propertyName;
/**
* Value for SET_PROPERTY action
*/
private Value value;
/**
* Target for GET_PROPERTY action
*/
private Target target;
/**
* Whether or not the existing bean is replaced by the CREATE action.
*/
private boolean replace = true;
/**
* Class object representing the class of the bean
*/
private Class clazz;
/**
* Manipulates a JavaBean attached to the current message context according to the supplied
* semantics.
* @param synCtx The current message for mediation
* @return true If mediation should continue
*/
public boolean mediate(MessageContext synCtx) {
if (synCtx.getEnvironment().isDebuggerEnabled()) {
if (super.divertMediationRoute(synCtx)) {
return true;
}
}
SynapseLog synLog = getLog(synCtx);
if (synLog.isTraceOrDebugEnabled()) {
synLog.traceOrDebug("Start : Bean mediator");
if (synLog.isTraceTraceEnabled()) {
synLog.traceTrace("Message : " + synCtx.getEnvelope());
}
}
boolean output = false;
switch (action) {
case CREATE:
if (synLog.isTraceOrDebugEnabled()) {
synLog.traceOrDebug("Creating a new bean of type '" + clazz.getName() +
"' with var name '" + varName + "'.");
}
output = mediateCreateBeanAction(synCtx);
break;
case REMOVE:
if (synLog.isTraceOrDebugEnabled()) {
synLog.traceOrDebug("Removing the bean with var name '" + varName + "'.");
}
output = mediateRemoveBeanAction(synCtx);
break;
case SET_PROPERTY:
if (synLog.isTraceOrDebugEnabled()) {
synLog.traceOrDebug("Setting the '" + propertyName + "' property of the bean " +
"with var name '" + varName + "'.");
}
output = mediateSetPropertyAction(synCtx);
break;
case GET_PROPERTY:
if (synLog.isTraceOrDebugEnabled()) {
synLog.traceOrDebug("Retrieving the '" + propertyName + "' property of the " +
"bean with var name '" + varName + "'.");
}
output = mediateGetPropertyAction(synCtx);
break;
default:
assert false;
}
if (synLog.isTraceOrDebugEnabled()) {
synLog.traceOrDebug("End : Bean mediator");
}
return output;
}
/**
* Creates a new bean and attaches it to the current message context.
* @param synCtx The current message for mediation
* @return true If mediation should continue
*/
private boolean mediateCreateBeanAction(MessageContext synCtx) {
if (!replace && synCtx.getProperty(varName) != null) {
return true;
}
Object instance = null;
try {
instance = clazz.newInstance();
} catch (Exception ex) {
handleException("An error occurred while instantiating '" + clazz.getName() +
"' class.", ex, synCtx);
}
synCtx.setProperty(varName, instance);
return true;
}
/**
* Removes a bean attached to the current message context.
* @param synCtx The current message for mediation
* @return true If mediation should continue
*/
private boolean mediateRemoveBeanAction(MessageContext synCtx) {
synCtx.getPropertyKeySet().remove(varName);
return true;
}
/**
* Sets a property of a bean attached to the current message context.
* @param synCtx The current message for mediation
* @return true If mediation should continue
*/
private boolean mediateSetPropertyAction(MessageContext synCtx) {
Object bean = synCtx.getProperty(varName);
if (bean == null) {
handleException("Bean with var name '" + varName + "' was not found.", synCtx);
return false;
}
Object valueObj = value.evaluateObjectValue(synCtx);
if (bean instanceof Map) {
((Map) bean).put(propertyName, valueObj);
} else {
try {
BeanUtils.invokeInstanceMethod(
bean,
new PropertyDescriptor(propertyName, bean.getClass()).getWriteMethod(),
new Object[]{valueObj}
);
} catch (IntrospectionException e) {
handleException("Could not resolve the setter method for '" + propertyName +
"' property in '" + bean.getClass() + "'.", e, synCtx);
} catch (SynapseException e) {
handleException("Error while invoking the setter method for '" + propertyName +
"' property on '" + bean.getClass() + "'.", e, synCtx);
}
}
return true;
}
/**
* Retrieves a property of a bean attached to the current message context.
* @param synCtx The current message for mediation
* @return true If mediation should continue
*/
private boolean mediateGetPropertyAction(MessageContext synCtx) {
Object bean = synCtx.getProperty(varName);
if (bean == null) {
handleException("Bean with var name '" + varName + "' was not found.", synCtx);
return false;
}
Object value = null;
if (bean instanceof Map) {
value = ((Map) bean).get(propertyName);
} else {
try {
value = BeanUtils.invokeInstanceMethod(
bean,
new PropertyDescriptor(propertyName, bean.getClass()).getReadMethod(),
new Object[0]
);
} catch (IntrospectionException e) {
handleException("Could not resolve the getter method for '" + propertyName +
"' property in '" + bean.getClass() + "'.", e, synCtx);
} catch (SynapseException e) {
handleException("Error while invoking the getter method for '" + propertyName +
"' property on '" + bean.getClass() + "'.", e, synCtx);
}
}
try {
target.insert(synCtx, value);
} catch (SynapseException e) {
handleException("Failed to set the target after retrieving the bean property.", e,
synCtx);
}
return true;
}
public Action getAction() {
return action;
}
public void setAction(Action action) {
this.action = action;
}
public String getVarName() {
return varName;
}
public void setVarName(String varName) {
this.varName = varName;
}
public String getPropertyName() {
return propertyName;
}
public void setPropertyName(String propertyName) {
this.propertyName = propertyName;
}
public Value getValue() {
return value;
}
public void setValue(Value value) {
this.value = value;
}
public Target getTarget() {
return target;
}
public void setTarget(Target target) {
this.target = target;
}
public boolean isReplace() {
return replace;
}
public void setReplace(boolean replace) {
this.replace = replace;
}
public Class getClazz() {
return clazz;
}
public void setClazz(Class clazz) {
this.clazz = clazz;
}
/**
* Enum representing the action performed by the Bean mediator.
*/
public enum Action {
CREATE, REMOVE, SET_PROPERTY, GET_PROPERTY
}
}