package act.mail; /*- * #%L * ACT Framework * %% * Copyright (C) 2014 - 2017 ActFramework * %% * Licensed 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. * #L% */ import act.app.ActionContext; import org.osgl.logging.L; import org.osgl.logging.Logger; import org.osgl.util.E; import org.osgl.util.S; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.Future; /** * A Tag annotation indicate a class or method is used to preparing and send out email * <p>Note if the annotation is tagged on a class, then framework will treat all public * void method with name start with "send" as sender method</p> */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface Mailer { /** * Defines the {@link MailerConfig mailer configure ID}. * <p>Default value: {@code "default"}</p> */ String value() default "default"; class Util { protected static final Logger logger = L.get(Mailer.class); public static Future<Boolean> send(Object... args) { throw E.unsupport("to be enhanced"); } public static MailerContext mailer() { throw E.unsupport("to be enhanced"); } public static void from(String from) { ctx().from = from; } public static void to(List<String> recipients) { ctx().to = S.join(",", recipients); } public static void to(String ... recipients) { ctx().to = S.join(",", recipients); } public static void cc(String ... cc) { ctx().cc = S.join(",", cc); } public static void bcc(String ... bcc) { ctx().bcc = S.join(",", bcc); } public static void subject(String subject, Object ... args) { ctx().subject = subject; ctx().subjectArgs = args; } private static SimpleContext ctx() { return _ctx.get(); } public static Future<Boolean> doSendWithoutLoadThreadLocal(final MailerContext context) { return context.app().jobManager().now(new Callable<Boolean>() { @Override public Boolean call() throws Exception { return context.send(); } }); } public static Future<Boolean> doSend(final MailerContext context) { tryLoadLocale(context); SimpleContext ctx = _ctx.get(); if (null != ctx) { if (S.notBlank(ctx.from)) { context.from(ctx.from); } if (S.notBlank(ctx.to)) { context.to(ctx.to); } if (S.notBlank(ctx.cc)) { context.cc(ctx.cc); } if (S.notBlank(ctx.bcc)) { context.bcc(ctx.bcc); } if (S.notBlank(ctx.subject)) { context.subject(ctx.subject, ctx.subjectArgs); } _ctx.remove(); } return context.app().jobManager().now(new Callable<Boolean>() { @Override public Boolean call() throws Exception { return context.send(); } }); } private static void tryLoadLocale(MailerContext context) { if (!context.config().i18nEnabled() || context.locale() != null) { // do nother if // 1. i18n is not enabled // 2. context locale has already loaded (via AppJobManager.ContextualJob) return; } // check if there are ActionContext instance in the render args for (Map.Entry<String, Object> entry : context.renderArgs().entrySet()) { Object val = entry.getValue(); if (val instanceof ActionContext) { // load locale from action context context.locale(((ActionContext) val).locale()); return; } } // load locale from app config (default locale) context.locale(context.config().locale()); } private static final ThreadLocal<SimpleContext> _ctx = new ThreadLocal<SimpleContext>() { @Override protected SimpleContext initialValue() { return new SimpleContext(); } }; private static class SimpleContext { String from; String to; String cc; String bcc; String subject; Object[] subjectArgs; } } }