/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.core.routing.filters;
import static org.mule.runtime.core.DefaultEventContext.create;
import static org.mule.runtime.core.api.construct.Flow.builder;
import static org.mule.runtime.core.config.i18n.CoreMessages.transformFailedBeforeFilter;
import static org.mule.runtime.core.util.ClassUtils.hash;
import static org.mule.runtime.dsl.api.component.config.DefaultComponentLocation.fromSingleComponent;
import org.mule.runtime.api.lifecycle.Initialisable;
import org.mule.runtime.api.lifecycle.InitialisationException;
import org.mule.runtime.api.message.Message;
import org.mule.runtime.api.metadata.DataType;
import org.mule.runtime.core.api.Event;
import org.mule.runtime.core.api.MuleContext;
import org.mule.runtime.core.api.construct.Flow;
import org.mule.runtime.core.api.context.MuleContextAware;
import org.mule.runtime.core.api.routing.filter.Filter;
import org.mule.runtime.core.api.routing.filter.ObjectFilter;
import org.mule.runtime.core.api.transformer.TransformerException;
import org.mule.runtime.core.transformer.simple.ByteArrayToObject;
import org.mule.runtime.core.util.AttributeEvaluator;
import org.mule.runtime.core.util.ClassUtils;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <code>RegExFilter</code> is used to match a String argument against a regular expression.
*/
public class RegExFilter implements Filter, ObjectFilter, MuleContextAware, Initialisable {
private static final int NO_FLAGS = 0;
protected transient Logger logger = LoggerFactory.getLogger(getClass());
private Pattern pattern;
private MuleContext muleContext;
private int flags = NO_FLAGS;
private AttributeEvaluator value;
@Override
public void initialise() throws InitialisationException {
if (value != null) {
value.initialize(muleContext.getExpressionManager());
}
}
public RegExFilter() {
super();
}
public RegExFilter(String pattern) {
this(pattern, null, NO_FLAGS);
}
public RegExFilter(String pattern, int flags) {
this(pattern, null, flags);
}
public RegExFilter(String pattern, String value) {
this(pattern, value, NO_FLAGS);
}
public RegExFilter(String pattern, String value, int flags) {
this.pattern = Pattern.compile(pattern, flags);
this.flags = flags;
this.value = new AttributeEvaluator(value);
}
@Override
public boolean accept(Message message, Event.Builder builder) {
// TODO MULE-9341 Remove Filters that are not needed
Flow flowConstruct = builder("RegExFilterFlow", muleContext).build();
return accept(Event.builder(create(flowConstruct, fromSingleComponent("RegExFilter"))).message(message).flow(flowConstruct)
.build(), builder);
}
@Override
public boolean accept(Event event, Event.Builder builder) {
try {
if (value != null && value.getRawValue() != null) {
return accept(value.resolveValue(event));
} else {
final Message transformedMessage =
muleContext.getTransformationService().transform(event.getMessage(), DataType.STRING);
// If the payload is a stream and we've consumed it, then we should set the payload on the message. This is the only time
// this method will alter the payload on the message.
// TODO MULE-9142 See how this API can be improved to not need the builder.
if (event.getMessage().getPayload().getDataType().isStreamType()) {
builder.message(transformedMessage);
}
return accept(transformedMessage.getPayload().getValue());
}
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
@Override
public boolean accept(Object object) {
if (object == null) {
return false;
}
Object tempObject = object;
// check whether the payload is a byte[] or a char[]. If it is, then it has
// to be transformed otherwise the toString will not represent the true
// contents
// of the payload for the RegEx filter to use.
if (object instanceof byte[]) {
ByteArrayToObject transformer = new ByteArrayToObject();
try {
object = transformer.transform(object);
} catch (TransformerException e) {
logger.warn(transformFailedBeforeFilter().toString(), e);
// revert transformation
object = tempObject;
}
} else if (object instanceof char[]) {
object = new String((char[]) object);
}
return (pattern != null && pattern.matcher(object.toString()).find());
}
public String getPattern() {
return (pattern == null ? null : pattern.pattern());
}
public void setPattern(String pattern) {
this.pattern = (pattern != null ? Pattern.compile(pattern, flags) : null);
}
public int getFlags() {
return flags;
}
public void setFlags(int flags) {
this.flags = flags;
this.pattern = (this.pattern != null ? Pattern.compile(pattern.pattern(), flags) : null);
}
public void setValue(String value) {
this.value = new AttributeEvaluator(value);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final RegExFilter other = (RegExFilter) obj;
boolean patternsAreEqual = ClassUtils.equal(pattern.pattern(), other.pattern.pattern());
boolean flagsAreEqual = (flags == other.flags);
boolean valuesAreEquals = areValuesEqual(value, other.value);
return (patternsAreEqual && flagsAreEqual && valuesAreEquals);
}
@Override
public void setMuleContext(MuleContext context) {
this.muleContext = context;
}
@Override
public int hashCode() {
return hash(new Object[] {this.getClass(), pattern, value == null ? null : value.getRawValue()});
}
private boolean areValuesEqual(AttributeEvaluator value1, AttributeEvaluator value2) {
if (value1 == null) {
return value2 == null;
} else {
if (value2 == null) {
return false;
}
if (value1.getRawValue() == null) {
return value2.getRawValue() == null;
}
return value1.getRawValue().equals(value2.getRawValue());
}
}
}