Mule ESB: how to filter emails based on subject or sender? - email

I am new to Mule 3.3 and I am trying to use it to retrieve emails from a POP3 server and download the CSV attachments if the sender field and subject field contain certain keywords. I have used the example provided on Mulesoft website and I have successfully managed to scan my inbox for new emails and only download CSV attachments. However, I am now stuck because I can't figure out how to filter emails by subject and sender fields.
Doing some research I have come across a message-property-filter pattern tag that can be applied to an endpoint, but I am not sure exactly to which endpoint to apply it, incoming or outgoing. Neither approach seems to work and I can't find a decent example showing how to use this tag. The basic algorithm I want to implement is as follows:
if email is from "Bob"
if attachment of type "CSV"
then download CSV attachment
if email subject field contains "keyword"
if attachment of type CSV
then download CSV attachment
Here's the Mule xml I have so far:
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:file="http://www.mulesoft.org/schema/mule/file" xmlns:pop3s="http://www.mulesoft.org/schema/mule/pop3s" xmlns:pop3="http://www.mulesoft.org/schema/mule/pop3"
xmlns="http://www.mulesoft.org/schema/mule/core"
xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:spring="http://www.springframework.org/schema/beans" version="CE-3.3.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/pop3s http://www.mulesoft.org/schema/mule/pop3s/current/mule-pop3s.xsd
http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/pop3 http://www.mulesoft.org/schema/mule/pop3/current/mule-pop3.xsd ">
<expression-transformer expression="#[attachments-list:*.csv]"
name="returnAttachments" doc:name="Expression">
</expression-transformer>
<pop3s:connector name="POP3Connector"
checkFrequency="5000"
deleteReadMessages="false"
defaultProcessMessageAction="RECENT"
doc:name="POP3"
validateConnections="true">
</pop3s:connector>
<file:connector name="fileName" doc:name="File">
<file:expression-filename-parser />
</file:connector>
<flow name="incoming-orders" doc:name="incoming-orders">
<pop3s:inbound-endpoint user="my_username"
password="my_password"
host="pop.gmail.com"
port="995"
transformer-refs="returnAttachments"
doc:name="GetMail"
connector-ref="POP3Connector"
responseTimeout="10000"/>
<collection-splitter doc:name="Collection Splitter"/>
<echo-component doc:name="Echo"/>
<file:outbound-endpoint path="/attachments"
outputPattern="#[function:datestamp].csv"
doc:name="File" responseTimeout="10000">
<expression-transformer expression="payload.inputStream"/>
<message-property-filter pattern="from=(.*)(bob#email.com)(.*)" caseSensitive="false"/>
</file:outbound-endpoint>
</flow>
What is the best way to tackle this problem?
Thanks in advance.

To help you, here are two configuration bits:
The following filter accepts only messages where fromAddress is 'Bob' and where subject contains 'keyword':
<expression-filter
expression="#[message.inboundProperties.fromAddress == 'Bob' || message.inboundProperties.subject contains 'keyword']" />
The following transformer extracts all the attachments whose names end with '.csv':
<expression-transformer
expression="#[($.value in message.inboundAttachments.entrySet() if $.key ~= '.*\\.csv')]" />

Welcome to Mule! A few month ago I implemented a similar proejct for a customer. I take a look at your flow, let´s start refactoring.
Remove the transformer-refs="returnAttachments" from inbound-endpoint
Add the following elements to your flow
<pop3:inbound-endpoint ... />
<custom-filter class="com.benasmussen.mail.filter.RecipientFilter">
<spring:property name="regex" value=".*bob.bent#.*" />
</custom-filter>
<expression-transformer>
<return-argument expression="*.csv" evaluator="attachments-list" />
</expression-transformer>
<collection-splitter doc:name="Collection Splitter" />
Add my RecipientFilter as java class to your project. All messages will be discard if they don't match to the regex pattern.
package com.benasmussen.mail.filter;
import java.util.Collection;
import java.util.Set;
import java.util.regex.Pattern;
import org.mule.api.MuleMessage;
import org.mule.api.lifecycle.Initialisable;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.api.routing.filter.Filter;
import org.mule.config.i18n.CoreMessages;
import org.mule.transport.email.MailProperties;
public class RecipientFilter implements Filter, Initialisable
{
private String regex;
private Pattern pattern;
public boolean accept(MuleMessage message)
{
String from = message.findPropertyInAnyScope(MailProperties.FROM_ADDRESS_PROPERTY, null);
return isMatch(from);
}
public void initialise() throws InitialisationException
{
if (regex == null)
{
throw new InitialisationException(CoreMessages.createStaticMessage("Property regex is not set"), this);
}
pattern = Pattern.compile(regex);
}
public boolean isMatch(String from)
{
return pattern.matcher(from).matches();
}
public void setRegex(String regex)
{
this.regex = regex;
}
}
The mule expression framework is powerful, but in some use cases I prefer my own business logic.
Improvment
Use application properties (mule-app.properties) > mule documentation
Documentation
MailProperties shows you all available message properties (EMail)
Take a look at the mule schema doc to see all available elements
Incoming payload (mails, etc) are transported by an DefaultMuleMessage (Payload, Properties, Attachments)

Related

Generating password protected pdf. How to get unique password for every user?

I've uploaded my reports on JasperServer where I'm scheduling the reports and send the pdf as attachments in emails to the users using the jobs rest api. Everything works perfectly, however we also need the pdf's to be encrypted. I've read the wiki topic and was able to encrypt the pdf.
But we want the passwords to be dynamic and be different for every user(for exmaple some combination of their phone numbers and date of births). The example described in the link specifies the password as a report property in the jrxml.
<property name="net.sf.jasperreports.export.pdf.user.password" value="123456"/>
<property name="net.sf.jasperreports.export.pdf.owner.password" value="123456"/>
The password is specified as a string and is similar for every pdf generated from this jrxml.
I tried something like this
<property name="net.sf.jasperreports.export.pdf.user.password" value="{$F{dateOfBirth}}"/>
where $F{dateOfBirth} is the dateOfBirth of the user for which the query is being run. But instead of putting in the field value, it just considers it a string and sets the password to="{$F{dateOfBirth}}"
How do I go along with this? Is their any way for me to set different passwords for every user?
NOTE:The datasource is configured for the report on the jasperserver. On the job execution api call, Jasperserver executed the query, fills the report, exports as pdf and sends it as email to the user.
Add the following code in your Java code.
JasperPrint print = JasperFillManager.fillReport(jasper, parameters, beanColDataSource2);
print.setProperty("net.sf.jasperreports.export.pdf.user.password", "jasper123");
Add in JRXML.
property name="net.sf.jasperreports.export.pdf.encrypted" value="True"
property name="net.sf.jasperreports.export.pdf.128.bit.key" value="True"
property name="net.sf.jasperreports.export.pdf.permissions.allowed" value="PRINTING"
As one comment mentioned, just use Java.
Here is an example, how I would code this (it's not perfect, but I think you will get it):
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import net.sf.jasperreports.engine.JRDefaultScriptlet;
import net.sf.jasperreports.engine.JRScriptletException;
import net.sf.jasperreports.engine.fill.JRFillParameter;
public class GetBirthdayScriptlet extends JRDefaultScriptlet {
private Connection conn;
private Connection getConnection() throws JRScriptletException {
if (conn == null) {
if (getParameterValue(JRFillParameter.REPORT_CONNECTION) != null) {
conn = (Connection) (getParameterValue(JRFillParameter.REPORT_CONNECTION));
} else {
throw new RuntimeException("No db-connection configured in the report!");
}
}
return conn;
}
public String getBirthday(String email) throws JRScriptletException, SQLException {
ResultSet result = null;
String resultString = null;
CallableStatement stmt = getConnection().prepareCall("select birthday from birthday_table where email = " + email);
stmt.executeUpdate();
result = stmt.getResultSet();
if(result.next()){
result.getString(1);
}
return resultString;
}
}
Pack this little snippet into a jar and add it to your Studio Build Path and also upload it to your Jaspersoft Server.
In your report outline rightlick on Scriptlets -> "Create Scriptlet"
The class of the scriptlet is GetBirthdayScriptlet (this is the codesnippet-class).
The expression you want to use in your report is:
$P{>>scriptlet-name<<_SCRIPTLET}.getBirthday("email#example.com")
Instead of entering the String, just use the parameter.
Also, maybe think of using the Jaspersoft Built In Parameter LoggedInUserEmailAddress
This helps if you want live-reports to be encrypted.

Custom tags with spyne

Im trying to set up a small SOAP 1.1 server with twisted and spyne, but I can't seem to find anything on how to create custom tags(body), namespaces, or headers for my responses. Is there a better way to do this than creating my own ProtocolBase?
The goal is to have soap responses that look like this:
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cwmp="urn:dslforum-org:cwmp-1-2">
<SOAP-ENV:Header>
<cwmp:ID SOAP-ENV:mustUnderstand="1">123456789</cwmp:ID>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<cwmp:SetParameterValues>
<ParameterList SOAP-ENC:arrayType="cwmp:ParameterValueStruct[1]">
<ParameterValueStruct>
<Name>MY.NAME</Name>
<Value xsi:type="xsd:unsignedInt">4000</Value>
</ParameterValueStruct>
</ParameterList>
<ParameterKey>Axess Update parameters</ParameterKey>
</cwmp:SetParameterValues>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Im able to produce what I'm looking for by creating my own protocol for which I hand a string of xml similar to below.
class spyne(ServiceBase):
isLeaf = TwistedWebResource
#rpc(AnyDict, AnyDict, _returns=Unicode)
def my_rpc(ctx, DeviceId, ParameterList):
out_document = etree.parse('data.xml')
return etree.tostring(out_document, pretty_print=True,
encoding='utf8', xml_declaration=False)
class my_protocol(XmlDocument):
mime_type = 'text/xml; charset=utf-8'
type = set(XmlDocument.type)
type.update(('soap', 'soap11'))
def __init__(self, *args, **kwargs):
super(TR_069_SOAP, self).__init__(*args, **kwargs)
def serialize(self, ctx, message):
ctx.out_document = ctx.out_object[0]
def create_out_string(self, ctx, charset=None):
ctx.out_string = [ctx.out_document]
I'm not sure if there is a better way to be doing this.
Spyne does not support serializing array using the SOAP-ENC:arrayType="cwmp:ParameterValueStruct[1]" style, whatever that means.
You don't need your own protocol but you do need to override XmlDocument's complex_to_parent in Soap11 and add special handling for arrays that have, say, Array(SomeType, array_type="cwmp:ParameterValueStruct[1]").
You can either patch Spyne itself and send a pull request my way or create a Soap11 subclass (NOT XmlDocument subclass) of your own and write overriding code there.
Chime in at http://lists.spyne.io/listinfo/people if you wish to proceed either way.

Implement validator in Eclipse

I am trying to implement validation in Eclipse. My work has many little projects that serve to customize our product for various customers. Since there are a ton of developers we are trying to find a way to enforce various standards and best practices.
For example, we have many XML configurations that we want to validate. The built-in validators ensure files are well-formed and follow a schema, but we would like to add validations such as checking that a Java class referenced in XML actually exists on the classpath. Another example is validating that a Java class implementing a certain interface does not have any object variables (i.e. the code needs to operate only on parameters and not maintain state).
It appears that there are two ways to add validation. The first is through a builder which adds markers. The second is through stand-alone validation. However, we are not actually building anything, and I have not found any useful tutorials or examples on validation (does not help that help.eclipse.org is currently being moved and is unavailable).
When I right-click a test project and select "validate" I get a message stating there was an error during validation, and my test message does not show up in the problem view. However, there are no errors in the Eclipse log. The host Eclipse shows nothing in the console. No exceptions logged anywhere, and no message. The project does have the required custom nature.
I was following these instructions but there is no code or fully functioning example, and Google has not been kind enough to fill in the blanks. Combined with the Eclipse help site being down right now, I am at a loss as to how to proceed.
plugin.xml:
<plugin>
<extension name="My Validator" point="org.eclipse.wst.validation.validator"
id="com.mycompany.pluginname.validator.MyValidator">
<validator>
<projectNature id="com.mycompany.pluginname.nature.MyNature"/>
<helper class="org.eclipse.wst.validation.internal.operations.WorkbenchContext"/>
<markerId markerIdValue="com.mycompany.pluginname.validator.DefaultMarker"/>
<run class="com.mycompany.pluginname.validation.validator.MyValidator"/>
<runStrategy project="true"/>
</validator>
</extension>
<extension point="org.eclipse.core.resources.markers" name="My Validator"
id="com.mycompany.pluginname.validator.DefaultMarker">
<super type="org.eclipse.core.resources.problemmarker"/>
<persistent value="true"/>
<attribute name="owner"/>
<attribute name="validationSeverity"/>
<attribute name="targetObject"/>
<attribute name="groupName"/>
<attribute name="messageId"/>
</extension>
</plugin>
Validator code:
package com.mycompany.pluginname.validation.validator;
import org.eclipse.core.resources.IProject;
import org.eclipse.wst.validation.internal.core.Message;
import org.eclipse.wst.validation.internal.core.ValidationException;
import org.eclipse.wst.validation.internal.operations.IWorkbenchContext;
import org.eclipse.wst.validation.internal.provisional.core.*;
import com.mycompany.pluginname.validation.plugin.ValidationPlugin;
#SuppressWarnings("restriction")
public class MyValidator
implements IValidator {
#Override
public void cleanup(IReporter argReporter) {
argReporter.removeAllMessages(this);
}
#Override
public void validate(IValidationContext argContext, IReporter argReporter)
throws ValidationException {
String bundle = ValidationPlugin.getDefault().getTranslationsBundleName();
IProject prj = ((IWorkbenchContext) argContext).getProject();
String[] attributes =
new String[] {"owner", "validationSeverity", "targetObject", "groupName", "messageId"};
IMessage msg = new Message(bundle, IMessage.HIGH_SEVERITY, "test", attributes, prj);
argReporter.addMessage(this, msg);
}
}
I also find it odd that adding validation would require using restricted packages and interfaces. It also seems odd that it wants an IMessage rather than an IMarker.
I did look at Eclipse plugin with custom validation which seems to be oriented around creating a new editor, where I want to validate files regardless of the editor used (in fact I do not want to create an editor).
Edit: I updated to use the V2 framework, but nothing appears in the problem view. What am I doing wrong? Is there a tutorial somewhere that explains how this works? I was able to figure out the following, but obviously it is not correct:
public ValidationResult validate(ValidationEvent argEvent, ValidationState argState,
IProgressMonitor argMonitor) {
final IResource resource = argEvent.getResource();
final ValidationResult result = new ValidationResult();
try {
List<String> contents = Resources.readFile((IFile) resource);
for (int i = 0; i < contents.size(); ++i) {
int offset = contents.get(i).indexOf("bad_string");
if (offset >= 0) {
result.add(ValidatorMessage.create("Found bad string", resource));
result.incrementError(1);
}
}
}
catch (Exception ex) {
result.add(ValidatorMessage.create(ex.getMessage(), resource));
}
return result;
}
I admit this is a stab in the dark: the documentation is not very descriptive and I have not found any tutorials on this V2 validator. Oh, I have a filter on this validator so it only receives specific XML files, which is why there is no input validation.
Also, since I am a pedant myself, I am using the old-style for loop there because I expect to show the line number with the error to the user. But obviously I am not quite there yet.
Another edit: here is the working code. The only issue is the squiggly is not on the correct line because the offset is from the start of the file, not the line. But it does work:
public ValidationResult validate(ValidationEvent argEvent, ValidationState argState,
IProgressMonitor argMonitor) {
final IResource resource = argEvent.getResource();
final ValidationResult result = new ValidationResult();
try {
List<String> contents = Resources.readFile((IFile) resource);
int location = 0;
for (int i = 0; i < contents.size(); ++i) {
int offset = contents.get(i).indexOf(CONSTANT);
if (offset >= 0) {
ValidatorMessage vm = ValidatorMessage.create("Message", resource);
vm.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
vm.setAttribute(IMarker.SOURCE_ID, IMarker.PROBLEM);
vm.setAttribute(IMarker.LINE_NUMBER, i + 1);
vm.setAttribute(IMarker.CHAR_START, location + offset);
vm.setAttribute(IMarker.CHAR_END, location + offset + CONSTANT.length());
result.add(vm);
}
// TODO: account for different line endings.
location += (line.length() + 2);
}
}
catch (Exception ex) {
ValidationPlugin.getDefault().warn(ex);
result.add(ValidatorMessage.create(ex.toString(), resource));
}
return result;
}
Plugin.xml:
<extension name="My Validator" point="org.eclipse.wst.validation.validatorV2"
id="com.company.plugin.validation.validator.MyValidator">
<validator class="com.company.plugin.validation.validator.MyValidator">
<include>
<rules>
<file type="file" name="FileName.xml"/>
</rules>
</include>
</validator>
</extension>
I actually found another SO question along these lines that corroborates what I found: Setting IMarker.CHAR_START and IMarker.CHAR_END attributes for IMarkers Annotations
sigh that document is very out of date. You should use the org.eclipse.wst.validation.validatorV2 extension point, extending the newer org.eclipse.wst.validation.AbstractValidator class.

XSD2Code namespace issue

I am using XSD2Code to generate C# class from XSD file.
I got stuck with the following problem.
XML file looks something like
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Notification xmlns="http://message.domain.com">
<Object xmlns="http://type.domain.com" ID="97440" />
</Notification>
XML gets succefsully deserialized when xmls for Object is empty. But when there is a value like in the sample above, I get an error "Object reference not set to an instance of an object".
What could cause this error?
you have to change the Serializer to something like that
private static System.Xml.Serialization.XmlSerializer Serializer
{
get
{
if ((serializer == null))
{
serializer = new System.Xml.Serialization.XmlSerializer(typeof(Notification), "http://message.domain.com");
}
return serializer;
}
}
To turn off encoding, disable encoding on the Serialization tab

Can XmlSerializer deserialize into a Nullable<int>?

I wanted to deserialize an XML message containing an element that can be marked nil="true" into a class with a property of type int?. The only way I could get it to work was to write my own NullableInt type which implements IXmlSerializable. Is there a better way to do it?
I wrote up the full problem and the way I solved it on my blog.
I think you need to prefix the nil="true" with a namespace in order for XmlSerializer to deserialise to null.
MSDN on xsi:nil
<?xml version="1.0" encoding="UTF-8"?>
<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="array">
<entity>
<id xsi:type="integer">1</id>
<name>Foo</name>
<parent-id xsi:type="integer" xsi:nil="true"/>
My fix is to pre-process the nodes, fixing any "nil" attributes:
public static void FixNilAttributeName(this XmlNode #this)
{
XmlAttribute nilAttribute = #this.Attributes["nil"];
if (nilAttribute == null)
{
return;
}
XmlAttribute newNil = #this.OwnerDocument.CreateAttribute("xsi", "nil", "http://www.w3.org/2001/XMLSchema-instance");
newNil.Value = nilAttribute.Value;
#this.Attributes.Remove(nilAttribute);
#this.Attributes.Append(newNil);
}
I couple this with a recursive search for child nodes, so that for any given XmlNode (or XmlDocument), I can issue a single call before deserialization. If you want to keep the original in-memory structure unmodified, work with a Clone() of the XmlNode.
The exceptionally lazy way to do it. It's fragile for a number of reasons but my XML is simple enough to warrant such a quick and dirty fix.
xmlStr = Regex.Replace(xmlStr, "nil=\"true\"", "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"");