In my Grails application, there is a requirement to allow different text to be shown to users on a per 'organisation' basis, but to fall back to reading the text from messages.properties if no overriding text is defined for an organisation.
I'm using an approach similar to the one detailed here, which works well in the scope of an http request, however I now also need to define email content on a per organisation basis which is a bit problematic as emails are sent asynchronously (using the async mail plugin). My current resolveCode() implementation looks like this:
public MessageFormat resolveCode(String code, Locale locale) {
Message msg = null
try {
Organisation currentOrganisation = currentOrganisationSessionProxy.currentSessionOrganisation
msg = Message.findByCodeAndLocaleAndOrganisation(code, locale, currentOrganisation)
} catch (Exception e) {
//handle exception
}
def format
if (msg) {
format = new MessageFormat(msg.text, msg.locale)
} else {
format = messageBundleMessageSource.resolveCode(code, locale)
}
return format
}
I've modified the DatabaseMessageSource implementation slightly as I need to resolve the current 'session' organisation using a session-scoped proxy.
Can anyone suggest a good approach for sending localized, organisation-specific emails asynchronously? I guess I would need to persist the organisation id along with the email, and then retrieve it some how in my DatabaseMessageSource. Any help is appreciated.
This actually turned out to be simpler than I thought. I didn't need to modify the async mail plugin, but I did need to override the ValidationTagLib g:message implementation so that I could pass in an organisationId. I also needed to provide alternate implementations of AbstractMessageSource.getMessage methods that also took an organisationId argument.
Related
I'm trying to create a piece of code that would retrieve the whole content of an INBOX, using Spring Integration Mail.
By default, an ImapIdleChannelAdapter will only fetch recent, unseen, unanswered etc... emails.
So when I created my adapter, I tried to use a special strategy that would retrieve all emails without a given unique user flag (so basically, all the mails I haven't retrieve yet).
Here is my adapter:
Mail.imapIdleAdapter(imapUrl(user, pw, provider))
.javaMailProperties { p: PropertiesBuilder -> p.put("mail.debug", "false") }
.userFlag(uniqueFlag)
.shouldMarkMessagesAsRead(false)
.searchTermStrategy(GetAllMailsStrategy(uniqueFlag))
.shouldReconnectAutomatically(true)
.autoCloseFolder(false)
val integrationFlowBuilder = IntegrationFlows.from(imapIdleAdapter)
.handle { message -> onNewEmail(user, uniqueFlag, message as org.springframework.messaging.Message<Message>) }
val flow: IntegrationFlow = integrationFlowBuilder.get()
flowContext.registration(flow).register()
And here is my strategy:
inner class GetAllMailsStrategy(private val uniqueFlag: String) : SearchTermStrategy {
override fun generateSearchTerm(supportedFlags: Flags?, folder: Folder?): SearchTerm {
val userFlag = Flags()
userFlag.add(uniqueFlag)
return NotTerm(FlagTerm(userFlag, true))
}
}
This piece of code does work, on small inboxes. As soon as I try to retrieve mails from an inbox with thousands of mails, at some point it just stops (sometime with FolderClosedException, even though I set autoCloseFolder to false, and sometime without any exception or log...), and then won't retrieve missing emails even if I start it all over with the same unique user flag. As if all the mails where flagged even though I never retrieved them. It does work on all new incoming emails though...
Any idea on what strategy I should use? Is there a way to get all the mails once, without flagging them?
Should I use Spring mail only to get incoming new mail but something else for the task of retrieving all the mails once?
Thanks
I never did it, but I think you are right: you should use an ImapIdleChannelAdapter for new (in IMAP terms RECENT) message, and some other ImapMailReceiver instance for initial call with your custom SearchTermStrategy.
The folder might be closed for some other reason, e.g. too many messages too long processed.
Is there any way in Kentico to have a user submit a form and then email the response but not actually save the answer to the related table?
As mentioned the emails from Kentico rely on the record being written to the DB before they trigger. Furthermore (unless I'm just unlucky) the only values you have access to are those stored in the table. I had thought that maybe you could mark the offending fields as Field without database representation, but sadly, the fields you may want will all be null - so best not to go down that route.
I took a slightly different approach to #trevor-j-fayas in that I used the BizFormItemEvents.Insert.Before event so that there is no trace of any log. It's a short hop from there to make use of an email template to make things look good. So my code looked as follows:
using CMS;
using CMS.DataEngine;
using CMS.EmailEngine;
using System;
[assembly: RegisterModule(typeof(FormGlobalEvents))]
public class FormGlobalEvents : Module
{
public FormGlobalEvents() : base("FormGlobalEvents")
{
}
protected override void OnInit()
{
CMS.OnlineForms.BizFormItemEvents.Insert.Before += Insert_Before;
}
private void Insert_Before(object sender, CMS.OnlineForms.BizFormItemEventArgs e)
{
var email = new EmailMessage();
email.From = e.Item.GetStringValue("ContactEmail", "null#foo.com");
email.Recipients = "no-reply#foo.com";
email.Subject = "Test from event handler (before save)";
email.PlainTextBody = "test" + DateTime.Now.ToLongTimeString();
EmailSender.SendEmail(email);
e.Cancel();
}
}
To me, it seems cleaner to not insert the record in the first place than delete it, but obviously that autoresponder etc. will only kick in automatically if you do save the record, so the choice is yours and ultimately depends on your preference.
Well, there's a couple different options, but the easiest is to simply delete the record after it's inserted. Use the Global Event Hooks to capture the BizFormItemEvent insert after, if it's your form, then delete it. Below is for Kentico 10:
using CMS;
using CMS.DataEngine;
using CMS.Forums;
using CMS.Helpers;
using CMS.IO;
using System.Net;
using System.Web;
// Registers the custom module into the system
[assembly: RegisterModule(typeof(CustomLoaderModule))]
public class CustomLoaderModule : Module
{
// Module class constructor, the system registers the module under the name "CustomForums"
public CustomLoaderModule()
: base("CustomLoaderModule")
{
}
// Contains initialization code that is executed when the application starts
protected override void OnInit()
{
base.OnInit();
CMS.OnlineForms.BizFormItemEvents.Insert.After += BizFormItem_Insert_After;
}
private void BizFormItem_Insert_After(object sender, CMS.OnlineForms.BizFormItemEventArgs e)
{
switch(e.Item.BizFormInfo.FormName)
{
case "YourFormNameHere":
e.Item.Delete();
break;
}
}
}
The other option would be to clone and modify the Online Form Web part to take the information, manually call the email and cancel the insert, but that's a lot of work when this is quicker.
Yes and no. The record is stored before the email notifications and autoresponders are sent out. Your best bet for this is to create a custom global event handler for the form submission(s) using the BizFormItemEvents.Insert.Before. This will call the event before the actual record is stored in the database. You can then cancel out of the event (which will not store the record) and send your email manually.
Handling global events
BizFormItemEvents Events
I am using the Asp.Net Web Api. I would like to be able to filter out certain fields on the response objects based on the connected clients access rights.
Example:
class Foo
{
[AccessFilter("Uberlord")]
string Wibble { get; set; }
string Wobble { get; set; }
}
When returning data the filed Wibble should only be returned if the current users context can satisfy the value of "Uberlord".
There are three avenues that I am exploring but I have not got a working solution:
A custom WebApi MediaTypeFormatter.
A custom json.net IContractResolver.
Some sort of AOP wrapper for controllers that manipulates the response object
My issue with these are:
The custom formatter does not feel like the right place to do it but might be the only option.
The custom json serializer would not have access to the current context so I would have to work that out.
With the first two options you would require specific implementations for each response format, json, xml, some custom format, etc. This would mean that if another response type is supported then a custom formatter / serializer is required to prevent sensitive data leaking.
The AOP controller wrapper would require a lot of reflection.
An additional bonus would be to strip out values from the fields on an inbound request object using the same mechanism.
Have I missed an obvious hook? Has this been solved by another way?
It was actually a lot simpler than I first thought. What I did not realise is that the DelegatingHandler can be used to manipulate the response as well as the request in the Web Api Pipeline.
Lifecycle of an ASP.NET Web API Message
Delegating Handler
Delegating handlers are an extensibility point in the message pipeline allowing you to massage the Request before passing it on to the rest of the pipeline. The response message on its way back has to pass through the Delegating Handler as well, so any response can also be monitored/filtered/updated at this extensibility point.
Delegating Handlers if required, can bypass the rest of the pipeline too and send back and Http Response themselves.
Example
Here is an example implementation of a DelegatingHandler that can either manipulate the response object or replace it altogether.
public class ResponseDataFilterHandler : DelegatingHandler
{
protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken)
.ContinueWith(task =>
{
var response = task.Result;
//Manipulate content here
var content = response.Content as ObjectContent;
if (content != null && content.Value != null)
{
((SomeObject)content.Value).SomeProperty = null;
}
//Or replace the content
response.Content = new ObjectContent(typeof(object), new object(), new JsonMediaTypeFormatter());
return response;
});
}
}
Microsoft article on how to implement a delegating handler and add it to the pipeline.HTTP Message Handlers in ASP.NET Web API
I have a similar question in the works over here: ASP.NET WebAPI Conditional Serialization based on User Role
A proposed solution that I came up with is to have my ApiController inherit from a BaseApiController which overrides the Initalize function to set the appropriate formatter based on the user's role. I haven't decided if I will go this way yet, but perhaps it will work for you.
protected override void Initialize(System.Web.Http.Controllers.HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
// If the user is in a sensitive-data access role
controllerContext.Configuration.Formatters.Add(/*My Formatter*/);
// Otherwise use the default ones added in global app_start that defaults to remove sensitive data
}
Using JAX-WS 2, I see an issue that others have spoken about as well. The issue is that if a SOAP message is received inside a handler, and that SOAP message is large - whether due to inline SOAP body elements that happen to have lots of content, or due to MTOM attachments - then it is dangerously easy to get an OutOfMemoryError.
The reason is that the call to getMessage() seems to set off a chain of events that involve reading the entire SOAP message on the wire, and creating an object (or objects) representing what was on the wire.
For example:
...
public boolean handleMessage(SOAPMessageContext context)
{
// for a large message, this will cause an OutOfMemoryError
System.out.println( context.getMessage().countAttachments() );
...
My question is: is there a known mechanism/workaround for dealing with this? Specifically, it would be nice to access the SOAP part in a SOAP message without forcing the attachments (if MTOM for example) to also be vacuumed up.
For those who run their app on JBoss 6 & 7 (with Apache CXF)... I was able to troubleshoot the problem by implementing my handler from the LogicalHandler interface instead of the SOAPHandler.
In this case your handleMessage() method would get the LogicalMessageContext context (instead of SOAPMessageContext) in the arguments that has no issues with the context.getMessage() call
There's actually a JAX-WS RI (aka Metro) specific solution for this which is very effective.
See https://javaee.github.io/metro/doc/user-guide/ch02.html#efficient-handlers-in-jax-ws-ri. Unfortunately that link is now broken but you can find it on WayBack Machine. I'll give the highlights below:
The Metro folks back in 2007 introduced an additional handler type, MessageHandler<MessageHandlerContext>, which is proprietary to Metro. It is far more efficient than SOAPHandler<SOAPMessageContext> as it doesn't try to do in-memory DOM representation.
Here's the crucial text from the original blog article:
MessageHandler:
Utilizing the extensible Handler framework provided by JAX-WS
Specification and the better Message abstraction in RI, we introduced
a new handler called MessageHandler to extend your Web Service
applications. MessageHandler is similar to SOAPHandler, except that
implementations of it gets access to MessageHandlerContext (an
extension of MessageContext). Through MessageHandlerContext one can
access the Message and process it using the Message API. As I put in
the title of the blog, this handler lets you work on Message, which
provides efficient ways to access/process the message not just a DOM
based message. The programming model of the handlers is same and the
Message handlers can be mixed with standard Logical and SOAP handlers.
I have added a sample in JAX-WS RI 2.1.3 showing the use of
MessageHandler to log messages and here is a snippet from the sample:
public class LoggingHandler implements MessageHandler<MessageHandlerContext> {
public boolean handleMessage(MessageHandlerContext mhc) {
Message m = mhc.getMessage().copy();
XMLStreamWriter writer = XMLStreamWriterFactory.create(System.out);
try {
m.writeTo(writer);
} catch (XMLStreamException e) {
e.printStackTrace();
return false;
}
return true;
}
public boolean handleFault(MessageHandlerContext mhc) {
.....
return true;
}
public void close(MessageContext messageContext) { }
public Set getHeaders() {
return null;
}
}
(end quote from 2007 blog post)
You can find a full example in the Metro GitHub repo.
What JAX-WS implementation runtime are you using? If there's a way to do this using the runtime built into WebSphere I'm certain there's a way to do this cleanly in other runtimes like Axis2 (proper), Apache CXF, and Metro/RI.
I am using the other way to reduce the memory costing, which is Message Accessor.
Instead of using context.getMessage(), I changed it to this way:
Object accessor = context.get("jaxws.message.accessor");
if (accessor != null) {
baosInString = accessor.toString();
}
Base on advice from IBM website. http://www-01.ibm.com/support/docview.wss?uid=swg1PM21151
I have a C# service that runs continuously with user credentials (i.e not as localsystem - I can't change this though I want to). For the most part the service seems to run ok, but ever so often it bombs out and restarts for no apparent reason (servicer manager is set to restart service on crash).
I am doing substantial event logging, and I have a layered approach to Exception handling that I believe makes at least some sort of sense:
Essentially I got the top level generic exception, null exception and startup exception handlers.
Then I got various handlers at the "command level" (i.e specific actions that the service runs)
Finally I handle a few exceptions handled at the class level
I have been looking at whether any resources aren't properly released, and I am starting to suspect my mailing code (send email). I noticed that I was not calling Dispose for the MailMessage object, and I have now rewritten the SendMail code as illustrated below.
The basic question is:
will this code properly release all resources used to send mails?
I don't see a way to dispose of the SmtpClient object?
(for the record: I am not using object initializer to make the sample easier to read)
private static void SendMail(string subject, string html)
{
try
{
using ( var m = new MailMessage() )
{
m.From = new MailAddress("service#company.com");
m.To.Add("user#company.com");
m.Priority = MailPriority.Normal;
m.IsBodyHtml = true;
m.Subject = subject;
m.Body = html;
var smtp = new SmtpClient("mailhost");
smtp.Send(m);
}
}
catch (Exception ex)
{
throw new MyMailException("Mail error.", ex);
}
}
I know this question is pre .Net 4 but version 4 now supports a Dispose method that properly sends a quit to the smpt server. See the msdn reference and a newer stackoverflow question.
There are documented issues with the SmtpClient class. I recommend buying a third party control since they aren't too expensive. Chilkat makes a decent one.