提交 4df7d71c 编写于 作者: A Arjen Poutsma

Initial import of context support module

上级 da208c28
<?xml version="1.0" encoding="UTF-8"?>
<project name="org.springframework.context.support">
<property file="${basedir}/../build.properties"/>
<import file="${basedir}/../build-spring-framework/package-bundle.xml"/>
<import file="${basedir}/../spring-build/standard/default.xml"/>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="http://ivyrep.jayasoft.org/ivy-doc.xsl"?>
<ivy-module
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://incubator.apache.org/ivy/schemas/ivy.xsd"
version="1.3">
<info organisation="org.springframework" module="${ant.project.name}">
<license name="Apache 2.0" url="http://www.apache.org/licenses/LICENSE-2.0"/>
</info>
<configurations>
<include file="${spring.build.dir}/common/default-ivy-configurations.xml"/>
</configurations>
<publications>
<artifact name="${ant.project.name}"/>
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
</publications>
<dependencies>
<!-- compile dependencies -->
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.logging" rev="1.1.1" conf="compile->runtime" />
<dependency org="org.springframework" name="org.springframework.core" rev="latest.integration" conf="compile->compile" />
<dependency org="org.springframework" name="org.springframework.context" rev="latest.integration" conf="compile->compile" />
<!-- optional dependencies -->
<dependency org="org.springframework" name="org.springframework.jdbc" rev="latest.integration" conf="optional->compile" />
<dependency org="org.springframework" name="org.springframework.transaction" rev="latest.integration" conf="optional->compile" />
<dependency org="javax.mail" name="com.springsource.javax.mail" rev="1.4.1" conf="optional->compile" />
<dependency org="org.apache.velocity" name="com.springsource.org.apache.velocity" rev="1.5.0" conf="optional->compile" />
<dependency org="org.freemarker" name="com.springsource.freemarker" rev="2.3.12" conf="optional->compile" />
<dependency org="net.sourceforge.jasperreports" name="com.springsource.net.sf.jasperreports" rev="2.0.5" conf="optional->compile" />
<dependency org="com.opensymphony.quartz" name="com.springsource.org.quartz" rev="1.6.0" conf="optional->compile" />
<dependency org="com.bea.commonj" name="com.springsource.commonj" rev="1.1.0" conf="optional->compile" />
<dependency org="net.sourceforge.ehcache" name="com.springsource.net.sf.ehcache" rev="1.4.1" conf="optional->compile" />
<!-- test dependencies -->
<dependency org="org.apache.log4j" name="com.springsource.org.apache.log4j" rev="1.2.15" conf="test->runtime"/>
<dependency org="org.junit" name="com.springsource.org.junit" rev="4.4.0" conf="test->runtime" />
</dependencies>
</ivy-module>
\ No newline at end of file
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.parent</artifactId>
<version>3.0-M1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.springframework.context.support</artifactId>
<packaging>jar</packaging>
<name>Spring Framework: Context Support</name>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.jdbc</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.transaction</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>com.springsource.javax.mail</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>com.springsource.org.apache.velocity</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>com.springsource.freemarker</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.sourceforge.jasperreports</groupId>
<artifactId>com.springsource.net.sf.jasperreports</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.bea.commonj</groupId>
<artifactId>com.springsource.commonj</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.opensymphony.quartz</groupId>
<artifactId>com.springsource.org.quartz</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.sourceforge.ehcache</groupId>
<artifactId>com.springsource.net.sf.ehcache</artifactId>
<optional>true</optional>
</dependency>
<!--
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.agent</artifactId>
</dependency>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>com.springsource.javax.ejb</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.jms</groupId>
<artifactId>com.springsource.javax.jms</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>com.springsource.javax.persistence</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.sourceforge.cglib</groupId>
<artifactId>com.springsource.net.sf.cglib</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>com.springsource.org.aspectj.weaver</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.aopalliance</groupId>
<artifactId>com.springsource.org.aopalliance</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>com.springsource.org.jruby</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>com.springsource.org.codehaus.groovy</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.beanshell</groupId>
<artifactId>com.springsource.bsh</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>edu.emory.mathcs.backport</groupId>
<artifactId>com.springsource.edu.emory.mathcs.backport</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.oracle.oc4j</groupId>
<artifactId>com.springsource.oracle.classloader</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.sun.enterprise</groupId>
<artifactId>com.springsource.com.sun.enterprise.loader</artifactId>
<optional>true</optional>
</dependency>
-->
</dependencies>
</project>
\ No newline at end of file
/*
* Copyright 2002-2008 the original author or authors.
*
* 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.
*/
package org.springframework.cache.ehcache;
import java.io.IOException;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.constructs.blocking.BlockingCache;
import net.sf.ehcache.constructs.blocking.CacheEntryFactory;
import net.sf.ehcache.constructs.blocking.SelfPopulatingCache;
import net.sf.ehcache.constructs.blocking.UpdatingCacheEntryFactory;
import net.sf.ehcache.constructs.blocking.UpdatingSelfPopulatingCache;
import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* FactoryBean that creates a named EHCache {@link net.sf.ehcache.Cache} instance
* (or a decorator that implements the {@link net.sf.ehcache.Ehcache} interface),
* representing a cache region within an EHCache {@link net.sf.ehcache.CacheManager}.
*
* <p>If the specified named cache is not configured in the cache configuration descriptor,
* this FactoryBean will construct an instance of a Cache with the provided name and the
* specified cache properties and add it to the CacheManager for later retrieval. If some
* or all properties are not set at configuration time, this FactoryBean will use defaults.
*
* <p>Note: If the named Cache instance is found, the properties will be ignored and the
* Cache instance will be retrieved from the CacheManager.
*
* @author Dmitriy Kopylenko
* @author Juergen Hoeller
* @since 1.1.1
* @see #setCacheManager
* @see EhCacheManagerFactoryBean
* @see net.sf.ehcache.Cache
*/
public class EhCacheFactoryBean implements FactoryBean, BeanNameAware, InitializingBean {
protected final Log logger = LogFactory.getLog(getClass());
private CacheManager cacheManager;
private String cacheName;
private int maxElementsInMemory = 10000;
private int maxElementsOnDisk = 10000000;
private MemoryStoreEvictionPolicy memoryStoreEvictionPolicy = MemoryStoreEvictionPolicy.LRU;
private boolean overflowToDisk = true;
private String diskStorePath;
private boolean eternal = false;
private int timeToLive = 120;
private int timeToIdle = 120;
private boolean diskPersistent = false;
private int diskExpiryThreadIntervalSeconds = 120;
private boolean blocking = false;
private CacheEntryFactory cacheEntryFactory;
private String beanName;
private Ehcache cache;
/**
* Set a CacheManager from which to retrieve a named Cache instance.
* By default, <code>CacheManager.getInstance()</code> will be called.
* <p>Note that in particular for persistent caches, it is advisable to
* properly handle the shutdown of the CacheManager: Set up a separate
* EhCacheManagerFactoryBean and pass a reference to this bean property.
* <p>A separate EhCacheManagerFactoryBean is also necessary for loading
* EHCache configuration from a non-default config location.
* @see EhCacheManagerFactoryBean
* @see net.sf.ehcache.CacheManager#getInstance
*/
public void setCacheManager(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
/**
* Set a name for which to retrieve or create a cache instance.
* Default is the bean name of this EhCacheFactoryBean.
*/
public void setCacheName(String cacheName) {
this.cacheName = cacheName;
}
/**
* Specify the maximum number of cached objects in memory.
* Default is 10000 elements.
*/
public void setMaxElementsInMemory(int maxElementsInMemory) {
this.maxElementsInMemory = maxElementsInMemory;
}
/**
* Specify the maximum number of cached objects on disk.
* Default is 10000000 elements.
*/
public void setMaxElementsOnDisk(int maxElementsOnDisk) {
this.maxElementsOnDisk = maxElementsOnDisk;
}
/**
* Set the memory style eviction policy for this cache.
* Supported values are "LRU", "LFU" and "FIFO", according to the
* constants defined in EHCache's MemoryStoreEvictionPolicy class.
* Default is "LRU".
*/
public void setMemoryStoreEvictionPolicy(MemoryStoreEvictionPolicy memoryStoreEvictionPolicy) {
Assert.notNull(memoryStoreEvictionPolicy, "memoryStoreEvictionPolicy must not be null");
this.memoryStoreEvictionPolicy = memoryStoreEvictionPolicy;
}
/**
* Set whether elements can overflow to disk when the in-memory cache
* has reached the maximum size limit. Default is "true".
*/
public void setOverflowToDisk(boolean overflowToDisk) {
this.overflowToDisk = overflowToDisk;
}
/**
* Set whether elements are considered as eternal. If "true", timeouts
* are ignored and the element is never expired. Default is "false".
*/
public void setEternal(boolean eternal) {
this.eternal = eternal;
}
/**
* Set t he time in seconds to live for an element before it expires,
* i.e. the maximum time between creation time and when an element expires.
* It is only used if the element is not eternal. Default is 120 seconds.
*/
public void setTimeToLive(int timeToLive) {
this.timeToLive = timeToLive;
}
/**
* Set the time in seconds to idle for an element before it expires, that is,
* the maximum amount of time between accesses before an element expires.
* This is only used if the element is not eternal. Default is 120 seconds.
*/
public void setTimeToIdle(int timeToIdle) {
this.timeToIdle = timeToIdle;
}
/**
* Set whether the disk store persists between restarts of the Virtual Machine.
* The default is "false".
*/
public void setDiskPersistent(boolean diskPersistent) {
this.diskPersistent = diskPersistent;
}
/**
* Set the number of seconds between runs of the disk expiry thread.
* The default is 120 seconds.
*/
public void setDiskExpiryThreadIntervalSeconds(int diskExpiryThreadIntervalSeconds) {
this.diskExpiryThreadIntervalSeconds = diskExpiryThreadIntervalSeconds;
}
/**
* Set whether to use a blocking cache that lets read attempts block
* until the requested element is created.
* <p>If you intend to build a self-populating blocking cache,
* consider specifying a {@link #setCacheEntryFactory CacheEntryFactory}.
* @see net.sf.ehcache.constructs.blocking.BlockingCache
* @see #setCacheEntryFactory
*/
public void setBlocking(boolean blocking) {
this.blocking = blocking;
}
/**
* Set an EHCache {@link net.sf.ehcache.constructs.blocking.CacheEntryFactory}
* to use for a self-populating cache. If such a factory is specified,
* the cache will be decorated with EHCache's
* {@link net.sf.ehcache.constructs.blocking.SelfPopulatingCache}.
* <p>The specified factory can be of type
* {@link net.sf.ehcache.constructs.blocking.UpdatingCacheEntryFactory},
* which will lead to the use of an
* {@link net.sf.ehcache.constructs.blocking.UpdatingSelfPopulatingCache}.
* <p>Note: Any such self-populating cache is automatically a blocking cache.
* @see net.sf.ehcache.constructs.blocking.SelfPopulatingCache
* @see net.sf.ehcache.constructs.blocking.UpdatingSelfPopulatingCache
* @see net.sf.ehcache.constructs.blocking.UpdatingCacheEntryFactory
*/
public void setCacheEntryFactory(CacheEntryFactory cacheEntryFactory) {
this.cacheEntryFactory = cacheEntryFactory;
}
public void setBeanName(String name) {
this.beanName = name;
}
public void afterPropertiesSet() throws CacheException, IOException {
// If no CacheManager given, fetch the default.
if (this.cacheManager == null) {
if (logger.isDebugEnabled()) {
logger.debug("Using default EHCache CacheManager for cache region '" + this.cacheName + "'");
}
this.cacheManager = CacheManager.getInstance();
}
// If no cache name given, use bean name as cache name.
if (this.cacheName == null) {
this.cacheName = this.beanName;
}
// Fetch cache region: If none with the given name exists,
// create one on the fly.
Ehcache rawCache = null;
if (this.cacheManager.cacheExists(this.cacheName)) {
if (logger.isDebugEnabled()) {
logger.debug("Using existing EHCache cache region '" + this.cacheName + "'");
}
rawCache = this.cacheManager.getEhcache(this.cacheName);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Creating new EHCache cache region '" + this.cacheName + "'");
}
rawCache = createCache();
this.cacheManager.addCache(rawCache);
}
// Decorate cache if necessary.
Ehcache decoratedCache = decorateCache(rawCache);
if (decoratedCache != rawCache) {
this.cacheManager.replaceCacheWithDecoratedCache(rawCache, decoratedCache);
}
this.cache = decoratedCache;
}
/**
* Create a raw Cache object based on the configuration of this FactoryBean.
*/
private Cache createCache() {
return new Cache(
this.cacheName, this.maxElementsInMemory, this.memoryStoreEvictionPolicy,
this.overflowToDisk, null, this.eternal, this.timeToLive, this.timeToIdle,
this.diskPersistent, this.diskExpiryThreadIntervalSeconds, null, null, this.maxElementsOnDisk);
}
/**
* Decorate the given Cache, if necessary.
* @param cache the raw Cache object, based on the configuration of this FactoryBean
* @return the (potentially decorated) cache object to be registered with the CacheManager
*/
protected Ehcache decorateCache(Ehcache cache) {
if (this.cacheEntryFactory != null) {
if (this.cacheEntryFactory instanceof UpdatingCacheEntryFactory) {
return new UpdatingSelfPopulatingCache(cache, (UpdatingCacheEntryFactory) this.cacheEntryFactory);
}
else {
return new SelfPopulatingCache(cache, this.cacheEntryFactory);
}
}
if (this.blocking) {
return new BlockingCache(cache);
}
return cache;
}
public Object getObject() {
return this.cache;
}
public Class getObjectType() {
return (this.cache != null ? this.cache.getClass() : Ehcache.class);
}
public boolean isSingleton() {
return true;
}
}
/*
* Copyright 2002-2007 the original author or authors.
*
* 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.
*/
package org.springframework.cache.ehcache;
import java.io.IOException;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
/**
* FactoryBean that exposes an EHCache {@link net.sf.ehcache.CacheManager} instance
* (independent or shared), configured from a specified config location.
*
* <p>If no config location is specified, a CacheManager will be configured from
* "ehcache.xml" in the root of the class path (that is, default EHCache initialization
* - as defined in the EHCache docs - will apply).
*
* <p>Setting up a separate EhCacheManagerFactoryBean is also advisable when using
* EhCacheFactoryBean, as it provides a (by default) independent CacheManager instance
* and cares for proper shutdown of the CacheManager. EhCacheManagerFactoryBean is
* also necessary for loading EHCache configuration from a non-default config location.
*
* <p>Note: As of Spring 2.0, this FactoryBean will by default create an independent
* CacheManager instance, which requires EHCache 1.2 or higher.
*
* @author Dmitriy Kopylenko
* @author Juergen Hoeller
* @since 1.1.1
* @see #setConfigLocation
* @see #setShared
* @see EhCacheFactoryBean
* @see net.sf.ehcache.CacheManager
*/
public class EhCacheManagerFactoryBean implements FactoryBean, InitializingBean, DisposableBean {
protected final Log logger = LogFactory.getLog(getClass());
private Resource configLocation;
private boolean shared = false;
private String cacheManagerName;
private CacheManager cacheManager;
/**
* Set the location of the EHCache config file. A typical value is "/WEB-INF/ehcache.xml".
* <p>Default is "ehcache.xml" in the root of the class path, or if not found,
* "ehcache-failsafe.xml" in the EHCache jar (default EHCache initialization).
* @see net.sf.ehcache.CacheManager#create(java.io.InputStream)
* @see net.sf.ehcache.CacheManager#CacheManager(java.io.InputStream)
*/
public void setConfigLocation(Resource configLocation) {
this.configLocation = configLocation;
}
/**
* Set whether the EHCache CacheManager should be shared (as a singleton at the VM level)
* or independent (typically local within the application). Default is "false", creating
* an independent instance.
* @see net.sf.ehcache.CacheManager#create()
* @see net.sf.ehcache.CacheManager#CacheManager()
*/
public void setShared(boolean shared) {
this.shared = shared;
}
/**
* Set the name of the EHCache CacheManager (if a specific name is desired).
* @see net.sf.ehcache.CacheManager#setName(String)
*/
public void setCacheManagerName(String cacheManagerName) {
this.cacheManagerName = cacheManagerName;
}
public void afterPropertiesSet() throws IOException, CacheException {
logger.info("Initializing EHCache CacheManager");
if (this.shared) {
// Shared CacheManager singleton at the VM level.
if (this.configLocation != null) {
this.cacheManager = CacheManager.create(this.configLocation.getInputStream());
}
else {
this.cacheManager = CacheManager.create();
}
}
else {
// Independent CacheManager instance (the default).
if (this.configLocation != null) {
this.cacheManager = new CacheManager(this.configLocation.getInputStream());
}
else {
this.cacheManager = new CacheManager();
}
}
if (this.cacheManagerName != null) {
this.cacheManager.setName(this.cacheManagerName);
}
}
public Object getObject() {
return this.cacheManager;
}
public Class getObjectType() {
return (this.cacheManager != null ? this.cacheManager.getClass() : CacheManager.class);
}
public boolean isSingleton() {
return true;
}
public void destroy() {
logger.info("Shutting down EHCache CacheManager");
this.cacheManager.shutdown();
}
}
<html>
<body>
Support classes for the open source cache
<a href="http://ehcache.sourceforge.net">EHCache</a>,
allowing to set up an EHCache CacheManager and Caches
as beans in a Spring context.
</body>
</html>
/*
* Copyright 2002-2006 the original author or authors.
*
* 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.
*/
package org.springframework.mail;
/**
* Exception thrown on failed authentication.
*
* @author Dmitriy Kopylenko
* @author Juergen Hoeller
*/
public class MailAuthenticationException extends MailException {
/**
* Constructor for MailAuthenticationException.
* @param msg message
*/
public MailAuthenticationException(String msg) {
super(msg);
}
/**
* Constructor for MailAuthenticationException.
* @param msg the detail message
* @param cause the root cause from the mail API in use
*/
public MailAuthenticationException(String msg, Throwable cause) {
super(msg, cause);
}
/**
* Constructor for MailAuthenticationException.
* @param cause the root cause from the mail API in use
*/
public MailAuthenticationException(Throwable cause) {
super("Authentication failed", cause);
}
}
/*
* Copyright 2002-2006 the original author or authors.
*
* 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.
*/
package org.springframework.mail;
import org.springframework.core.NestedRuntimeException;
/**
* Base class for all mail exceptions.
*
* @author Dmitriy Kopylenko
*/
public abstract class MailException extends NestedRuntimeException {
/**
* Constructor for MailException.
* @param msg the detail message
*/
public MailException(String msg) {
super(msg);
}
/**
* Constructor for MailException.
* @param msg the detail message
* @param cause the root cause from the mail API in use
*/
public MailException(String msg, Throwable cause) {
super(msg, cause);
}
}
/*
* Copyright 2002-2005 the original author or authors.
*
* 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.
*/
package org.springframework.mail;
import java.util.Date;
/**
* This is a common interface for mail messages, allowing a user to set key
* values required in assembling a mail message, without needing to know if
* the underlying message is a simple text message or a more sophisticated
* MIME message.
*
* <p>Implemented by both SimpleMailMessage and MimeMessageHelper,
* to let message population code interact with a simple message or a
* MIME message through a common interface.
*
* @author Juergen Hoeller
* @since 1.1.5
* @see SimpleMailMessage
* @see org.springframework.mail.javamail.MimeMessageHelper
*/
public interface MailMessage {
public void setFrom(String from) throws MailParseException;
public void setReplyTo(String replyTo) throws MailParseException;
public void setTo(String to) throws MailParseException;
public void setTo(String[] to) throws MailParseException;
public void setCc(String cc) throws MailParseException;
public void setCc(String[] cc) throws MailParseException;
public void setBcc(String bcc) throws MailParseException;
public void setBcc(String[] bcc) throws MailParseException;
public void setSentDate(Date sentDate) throws MailParseException;
public void setSubject(String subject) throws MailParseException;
public void setText(String text) throws MailParseException;
}
/*
* Copyright 2002-2006 the original author or authors.
*
* 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.
*/
package org.springframework.mail;
/**
* Exception thrown if illegal message properties are encountered.
*
* @author Dmitriy Kopylenko
* @author Juergen Hoeller
*/
public class MailParseException extends MailException {
/**
* Constructor for MailParseException.
* @param msg the detail message
*/
public MailParseException(String msg) {
super(msg);
}
/**
* Constructor for MailParseException.
* @param msg the detail message
* @param cause the root cause from the mail API in use
*/
public MailParseException(String msg, Throwable cause) {
super(msg, cause);
}
/**
* Constructor for MailParseException.
* @param cause the root cause from the mail API in use
*/
public MailParseException(Throwable cause) {
super("Could not parse mail", cause);
}
}
/*
* Copyright 2002-2006 the original author or authors.
*
* 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.
*/
package org.springframework.mail;
/**
* Exception to be thrown by user code if a mail cannot be prepared properly,
* for example when a Velocity template cannot be rendered for the mail text.
*
* @author Juergen Hoeller
* @since 1.1
* @see org.springframework.ui.velocity.VelocityEngineUtils#mergeTemplateIntoString
* @see org.springframework.ui.freemarker.FreeMarkerTemplateUtils#processTemplateIntoString
*/
public class MailPreparationException extends MailException {
/**
* Constructor for MailPreparationException.
* @param msg the detail message
*/
public MailPreparationException(String msg) {
super(msg);
}
/**
* Constructor for MailPreparationException.
* @param msg the detail message
* @param cause the root cause from the mail API in use
*/
public MailPreparationException(String msg, Throwable cause) {
super(msg, cause);
}
public MailPreparationException(Throwable cause) {
super("Could not prepare mail", cause);
}
}
/*
* Copyright 2002-2007 the original author or authors.
*
* 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.
*/
package org.springframework.mail;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.util.ObjectUtils;
/**
* Exception thrown when a mail sending error is encountered.
* Can register failed messages with their exceptions.
*
* @author Dmitriy Kopylenko
* @author Juergen Hoeller
*/
public class MailSendException extends MailException {
private transient Map failedMessages;
private Exception[] messageExceptions;
/**
* Constructor for MailSendException.
* @param msg the detail message
*/
public MailSendException(String msg) {
super(msg);
}
/**
* Constructor for MailSendException.
* @param msg the detail message
* @param cause the root cause from the mail API in use
*/
public MailSendException(String msg, Throwable cause) {
super(msg, cause);
}
/**
* Constructor for registration of failed messages, with the
* messages that failed as keys, and the thrown exceptions as values.
* <p>The messages should be the same that were originally passed
* to the invoked send method.
* @param failedMessages Map of failed messages as keys and thrown
* exceptions as values
*/
public MailSendException(Map failedMessages) {
super(null);
this.failedMessages = new LinkedHashMap(failedMessages);
this.messageExceptions = (Exception[]) failedMessages.values().toArray(new Exception[failedMessages.size()]);
}
/**
* Return a Map with the failed messages as keys, and the thrown exceptions
* as values.
* <p>Note that a general mail server connection failure will not result
* in failed messages being returned here: A message will only be
* contained here if actually sending it was attempted but failed.
* <p>The messages will be the same that were originally passed to the
* invoked send method, that is, SimpleMailMessages in case of using
* the generic MailSender interface.
* <p>In case of sending MimeMessage instances via JavaMailSender,
* the messages will be of type MimeMessage.
* <p><b>NOTE:</b> This Map will not be available after serialization.
* Use {@link #getMessageExceptions()} in such a scenario, which will
* be available after serialization as well.
* @return the Map of failed messages as keys and thrown exceptions as
* values, or an empty Map if no failed messages
* @see SimpleMailMessage
* @see javax.mail.internet.MimeMessage
*/
public final Map getFailedMessages() {
return (this.failedMessages != null ? this.failedMessages : Collections.EMPTY_MAP);
}
/**
* Return an array with thrown message exceptions.
* <p>Note that a general mail server connection failure will not result
* in failed messages being returned here: A message will only be
* contained here if actually sending it was attempted but failed.
* @return the array of thrown message exceptions,
* or an empty array if no failed messages
*/
public final Exception[] getMessageExceptions() {
return (this.messageExceptions != null ? this.messageExceptions : new Exception[0]);
}
public String getMessage() {
if (ObjectUtils.isEmpty(this.messageExceptions)) {
return super.getMessage();
}
else {
StringBuffer sb = new StringBuffer("Failed messages: ");
for (int i = 0; i < this.messageExceptions.length; i++) {
Exception subEx = this.messageExceptions[i];
sb.append(subEx.toString());
if (i < this.messageExceptions.length - 1) {
sb.append("; ");
}
}
return sb.toString();
}
}
public String toString() {
if (ObjectUtils.isEmpty(this.messageExceptions)) {
return super.toString();
}
else {
StringBuffer sb = new StringBuffer(getClass().getName());
sb.append("; nested exceptions (").append(this.messageExceptions.length).append(") are:");
for (int i = 0; i < this.messageExceptions.length; i++) {
Exception subEx = this.messageExceptions[i];
sb.append('\n').append("Failed message ").append(i + 1).append(": ");
sb.append(subEx);
}
return sb.toString();
}
}
public void printStackTrace(PrintStream ps) {
if (ObjectUtils.isEmpty(this.messageExceptions)) {
super.printStackTrace(ps);
}
else {
ps.println(getClass().getName() + "; nested exception details (" +
this.messageExceptions.length + ") are:");
for (int i = 0; i < this.messageExceptions.length; i++) {
Exception subEx = this.messageExceptions[i];
ps.println("Failed message " + (i + 1) + ":");
subEx.printStackTrace(ps);
}
}
}
public void printStackTrace(PrintWriter pw) {
if (ObjectUtils.isEmpty(this.messageExceptions)) {
super.printStackTrace(pw);
}
else {
pw.println(getClass().getName() + "; nested exception details (" +
this.messageExceptions.length + ") are:");
for (int i = 0; i < this.messageExceptions.length; i++) {
Exception subEx = this.messageExceptions[i];
pw.println("Failed message " + (i + 1) + ":");
subEx.printStackTrace(pw);
}
}
}
}
/*
* Copyright 2002-2005 the original author or authors.
*
* 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.
*/
package org.springframework.mail;
/**
* This interface defines a strategy for sending simple mails. Can be
* implemented for a variety of mailing systems due to the simple requirements.
* For richer functionality like MIME messages, consider JavaMailSender.
*
* <p>Allows for easy testing of clients, as it does not depend on JavaMail's
* infrastructure classes: no mocking of JavaMail Session or Transport necessary.
*
* @author Dmitriy Kopylenko
* @author Juergen Hoeller
* @since 10.09.2003
* @see org.springframework.mail.javamail.JavaMailSender
*/
public interface MailSender {
/**
* Send the given simple mail message.
* @param simpleMessage the message to send
* @throws org.springframework.mail.MailParseException
* in case of failure when parsing the message
* @throws org.springframework.mail.MailAuthenticationException
* in case of authentication failure
* @throws org.springframework.mail.MailSendException
* in case of failure when sending the message
*/
void send(SimpleMailMessage simpleMessage) throws MailException;
/**
* Send the given array of simple mail messages in batch.
* @param simpleMessages the messages to send
* @throws org.springframework.mail.MailParseException
* in case of failure when parsing a message
* @throws org.springframework.mail.MailAuthenticationException
* in case of authentication failure
* @throws org.springframework.mail.MailSendException
* in case of failure when sending a message
*/
void send(SimpleMailMessage[] simpleMessages) throws MailException;
}
/*
* Copyright 2002-2006 the original author or authors.
*
* 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.
*/
package org.springframework.mail;
import java.io.Serializable;
import java.util.Date;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.Assert;
/**
* Models a simple mail message, including data such as the from, to, cc, subject, and text fields.
*
* <p>Consider <code>JavaMailSender</code> and JavaMail <code>MimeMessages</code> for creating
* more sophisticated messages, for example messages with attachments, special
* character encodings, or personal names that accompany mail addresses.
*
* @author Dmitriy Kopylenko
* @author Juergen Hoeller
* @since 10.09.2003
* @see MailSender
* @see org.springframework.mail.javamail.JavaMailSender
* @see org.springframework.mail.javamail.MimeMessagePreparator
* @see org.springframework.mail.javamail.MimeMessageHelper
* @see org.springframework.mail.javamail.MimeMailMessage
*/
public class SimpleMailMessage implements MailMessage, Serializable {
private String from;
private String replyTo;
private String[] to;
private String[] cc;
private String[] bcc;
private Date sentDate;
private String subject;
private String text;
/**
* Create a new <code>SimpleMailMessage</code>.
*/
public SimpleMailMessage() {
}
/**
* Copy constructor for creating a new <code>SimpleMailMessage</code> from the state
* of an existing <code>SimpleMailMessage</code> instance.
* @throws IllegalArgumentException if the supplied message is <code>null</code>
*/
public SimpleMailMessage(SimpleMailMessage original) {
Assert.notNull(original, "The 'original' message argument cannot be null");
this.from = original.getFrom();
this.replyTo = original.getReplyTo();
if (original.getTo() != null) {
this.to = copy(original.getTo());
}
if (original.getCc() != null) {
this.cc = copy(original.getCc());
}
if (original.getBcc() != null) {
this.bcc = copy(original.getBcc());
}
this.sentDate = original.getSentDate();
this.subject = original.getSubject();
this.text = original.getText();
}
public void setFrom(String from) {
this.from = from;
}
public String getFrom() {
return this.from;
}
public void setReplyTo(String replyTo) {
this.replyTo = replyTo;
}
public String getReplyTo() {
return replyTo;
}
public void setTo(String to) {
this.to = new String[] {to};
}
public void setTo(String[] to) {
this.to = to;
}
public String[] getTo() {
return this.to;
}
public void setCc(String cc) {
this.cc = new String[] {cc};
}
public void setCc(String[] cc) {
this.cc = cc;
}
public String[] getCc() {
return cc;
}
public void setBcc(String bcc) {
this.bcc = new String[] {bcc};
}
public void setBcc(String[] bcc) {
this.bcc = bcc;
}
public String[] getBcc() {
return bcc;
}
public void setSentDate(Date sentDate) {
this.sentDate = sentDate;
}
public Date getSentDate() {
return sentDate;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getSubject() {
return this.subject;
}
public void setText(String text) {
this.text = text;
}
public String getText() {
return this.text;
}
/**
* Copy the contents of this message to the given target message.
* @param target the <code>MailMessage</code> to copy to
* @throws IllegalArgumentException if the supplied <code>target</code> is <code>null</code>
*/
public void copyTo(MailMessage target) {
Assert.notNull(target, "The 'target' message argument cannot be null");
if (getFrom() != null) {
target.setFrom(getFrom());
}
if (getReplyTo() != null) {
target.setReplyTo(getReplyTo());
}
if (getTo() != null) {
target.setTo(getTo());
}
if (getCc() != null) {
target.setCc(getCc());
}
if (getBcc() != null) {
target.setBcc(getBcc());
}
if (getSentDate() != null) {
target.setSentDate(getSentDate());
}
if (getSubject() != null) {
target.setSubject(getSubject());
}
if (getText() != null) {
target.setText(getText());
}
}
public String toString() {
StringBuffer sb = new StringBuffer("SimpleMailMessage: ");
sb.append("from=").append(this.from).append("; ");
sb.append("replyTo=").append(this.replyTo).append("; ");
sb.append("to=").append(StringUtils.arrayToCommaDelimitedString(this.to)).append("; ");
sb.append("cc=").append(StringUtils.arrayToCommaDelimitedString(this.cc)).append("; ");
sb.append("bcc=").append(StringUtils.arrayToCommaDelimitedString(this.bcc)).append("; ");
sb.append("sentDate=").append(this.sentDate).append("; ");
sb.append("subject=").append(this.subject).append("; ");
sb.append("text=").append(this.text);
return sb.toString();
}
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof SimpleMailMessage)) {
return false;
}
SimpleMailMessage otherMessage = (SimpleMailMessage) other;
return (ObjectUtils.nullSafeEquals(this.from, otherMessage.from) &&
ObjectUtils.nullSafeEquals(this.replyTo, otherMessage.replyTo) &&
java.util.Arrays.equals(this.to, otherMessage.to) &&
java.util.Arrays.equals(this.cc, otherMessage.cc) &&
java.util.Arrays.equals(this.bcc, otherMessage.bcc) &&
ObjectUtils.nullSafeEquals(this.sentDate, otherMessage.sentDate) &&
ObjectUtils.nullSafeEquals(this.subject, otherMessage.subject) &&
ObjectUtils.nullSafeEquals(this.text, otherMessage.text));
}
public int hashCode() {
int hashCode = (this.from == null ? 0 : this.from.hashCode());
hashCode = 29 * hashCode + (this.replyTo == null ? 0 : this.replyTo.hashCode());
for (int i = 0; this.to != null && i < this.to.length; i++) {
hashCode = 29 * hashCode + (this.to == null ? 0 : this.to[i].hashCode());
}
for (int i = 0; this.cc != null && i < this.cc.length; i++) {
hashCode = 29 * hashCode + (this.cc == null ? 0 : this.cc[i].hashCode());
}
for (int i = 0; this.bcc != null && i < this.bcc.length; i++) {
hashCode = 29 * hashCode + (this.bcc == null ? 0 : this.bcc[i].hashCode());
}
hashCode = 29 * hashCode + (this.sentDate == null ? 0 : this.sentDate.hashCode());
hashCode = 29 * hashCode + (this.subject == null ? 0 : this.subject.hashCode());
hashCode = 29 * hashCode + (this.text == null ? 0 : this.text.hashCode());
return hashCode;
}
private static String[] copy(String[] state) {
String[] copy = new String[state.length];
System.arraycopy(state, 0, copy, 0, state.length);
return copy;
}
}
/*
* Copyright 2002-2008 the original author or authors.
*
* 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.
*/
package org.springframework.mail.javamail;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
/**
* Spring-configurable <code>FileTypeMap</code> implementation that will read
* MIME type to file extension mappings from a standard JavaMail MIME type
* mapping file, using a standard <code>MimetypesFileTypeMap</code> underneath.
*
* <p>The mapping file should be in the following format, as specified by the
* Java Activation Framework:
*
* <pre>
* # map text/html to .htm and .html files
* text/html html htm HTML HTM</pre>
*
* Lines starting with <code>#</code> are treated as comments and are ignored. All
* other lines are treated as mappings. Each mapping line should contain the MIME
* type as the first entry and then each file extension to map to that MIME type
* as subsequent entries. Each entry is separated by spaces or tabs.
*
* <p>By default, the mappings in the <code>mime.types</code> file located in the
* same package as this class are used, which cover many common file extensions
* (in contrast to the out-of-the-box mappings in <code>activation.jar</code>).
* This can be overridden using the <code>mappingLocation</code> property.
*
* <p>Additional mappings can be added via the <code>mappings</code> bean property,
* as lines that follow the <code>mime.types<code> file format.
*
* @author Rob Harrop
* @author Juergen Hoeller
* @since 1.2
* @see #setMappingLocation
* @see #setMappings
* @see javax.activation.MimetypesFileTypeMap
*/
public class ConfigurableMimeFileTypeMap extends FileTypeMap implements InitializingBean {
/**
* The <code>Resource</code> to load the mapping file from.
*/
private Resource mappingLocation = new ClassPathResource("mime.types", getClass());
/**
* Used to configure additional mappings.
*/
private String[] mappings;
/**
* The delegate FileTypeMap, compiled from the mappings in the mapping file
* and the entries in the <code>mappings</code> property.
*/
private FileTypeMap fileTypeMap;
/**
* Specify the <code>Resource</code> from which mappings are loaded.
* <p>Needs to follow the <code>mime.types<code> file format, as specified
* by the Java Activation Framework, containing lines such as:<br>
* <code>text/html html htm HTML HTM</code>
*/
public void setMappingLocation(Resource mappingLocation) {
this.mappingLocation = mappingLocation;
}
/**
* Specify additional MIME type mappings as lines that follow the
* <code>mime.types<code> file format, as specified by the
* Java Activation Framework, for example:<br>
* <code>text/html html htm HTML HTM</code>
*/
public void setMappings(String[] mappings) {
this.mappings = mappings;
}
/**
* Creates the final merged mapping set.
*/
public void afterPropertiesSet() {
getFileTypeMap();
}
/**
* Return the delegate FileTypeMap, compiled from the mappings in the mapping file
* and the entries in the <code>mappings</code> property.
* @see #setMappingLocation
* @see #setMappings
* @see #createFileTypeMap
*/
protected final FileTypeMap getFileTypeMap() {
if (this.fileTypeMap == null) {
try {
this.fileTypeMap = createFileTypeMap(this.mappingLocation, this.mappings);
}
catch (IOException ex) {
IllegalStateException ise = new IllegalStateException(
"Could not load specified MIME type mapping file: " + this.mappingLocation);
ise.initCause(ex);
throw ise;
}
}
return this.fileTypeMap;
}
/**
* Compile a {@link FileTypeMap} from the mappings in the given mapping file
* and the given mapping entries.
* <p>The default implementation creates an Activation Framework {@link MimetypesFileTypeMap},
* passing in an InputStream from the mapping resource (if any) and registering
* the mapping lines programmatically.
* @param mappingLocation a <code>mime.types</code> mapping resource (can be <code>null</code>)
* @param mappings MIME type mapping lines (can be <code>null</code>)
* @return the compiled FileTypeMap
* @throws IOException if resource access failed
* @see javax.activation.MimetypesFileTypeMap#MimetypesFileTypeMap(java.io.InputStream)
* @see javax.activation.MimetypesFileTypeMap#addMimeTypes(String)
*/
protected FileTypeMap createFileTypeMap(Resource mappingLocation, String[] mappings) throws IOException {
MimetypesFileTypeMap fileTypeMap = null;
if (mappingLocation != null) {
InputStream is = mappingLocation.getInputStream();
try {
fileTypeMap = new MimetypesFileTypeMap(is);
}
finally {
is.close();
}
}
else {
fileTypeMap = new MimetypesFileTypeMap();
}
if (mappings != null) {
for (int i = 0; i < mappings.length; i++) {
fileTypeMap.addMimeTypes(mappings[i]);
}
}
return fileTypeMap;
}
/**
* Delegates to the underlying FileTypeMap.
* @see #getFileTypeMap()
*/
public String getContentType(File file) {
return getFileTypeMap().getContentType(file);
}
/**
* Delegates to the underlying FileTypeMap.
* @see #getFileTypeMap()
*/
public String getContentType(String fileName) {
return getFileTypeMap().getContentType(fileName);
}
}
/*
* Copyright 2002-2005 the original author or authors.
*
* 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.
*/
package org.springframework.mail.javamail;
import java.beans.PropertyEditorSupport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import org.springframework.util.StringUtils;
/**
* Editor for <code>java.mail.internet.InternetAddress</code>,
* to directly populate an InternetAddress property.
*
* <p>Expects the same syntax as InternetAddress's constructor with
* a String argument. Converts empty Strings into null values.
*
* @author Juergen Hoeller
* @since 1.2.3
* @see javax.mail.internet.InternetAddress
*/
public class InternetAddressEditor extends PropertyEditorSupport {
public void setAsText(String text) throws IllegalArgumentException {
if (StringUtils.hasText(text)) {
try {
setValue(new InternetAddress(text));
}
catch (AddressException ex) {
throw new IllegalArgumentException("Could not parse mail address: " + ex.getMessage());
}
}
else {
setValue(null);
}
}
public String getAsText() {
InternetAddress value = (InternetAddress) getValue();
return (value != null ? value.toUnicodeString() : "");
}
}
/*
* Copyright 2002-2006 the original author or authors.
*
* 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.
*/
package org.springframework.mail.javamail;
import java.io.InputStream;
import javax.mail.internet.MimeMessage;
import org.springframework.mail.MailException;
import org.springframework.mail.MailSender;
/**
* Extended {@link org.springframework.mail.MailSender} interface for JavaMail,
* supporting MIME messages both as direct arguments and through preparation
* callbacks. Typically used in conjunction with the {@link MimeMessageHelper}
* class for convenient creation of JavaMail {@link MimeMessage MimeMessages},
* including attachments etc.
*
* <p>Clients should talk to the mail sender through this interface if they need
* mail functionality beyond {@link org.springframework.mail.SimpleMailMessage}.
* The production implementation is {@link JavaMailSenderImpl}; for testing,
* mocks can be created based on this interface. Clients will typically receive
* the JavaMailSender reference through dependency injection.
*
* <p>The recommended way of using this interface is the {@link MimeMessagePreparator}
* mechanism, possibly using a {@link MimeMessageHelper} for populating the message.
* See {@link MimeMessageHelper MimeMessageHelper's javadoc} for an example.
*
* <p>The entire JavaMail {@link javax.mail.Session} management is abstracted
* by the JavaMailSender. Client code should not deal with a Session in any way,
* rather leave the entire JavaMail configuration and resource handling to the
* JavaMailSender implementation. This also increases testability.
*
* <p>A JavaMailSender client is not as easy to test as a plain
* {@link org.springframework.mail.MailSender} client, but still straightforward
* compared to traditional JavaMail code: Just let {@link #createMimeMessage()}
* return a plain {@link MimeMessage} created with a
* <code>Session.getInstance(new Properties())</code> call, and check the passed-in
* messages in your mock implementations of the various <code>send</code> methods.
*
* @author Juergen Hoeller
* @since 07.10.2003
* @see javax.mail.internet.MimeMessage
* @see javax.mail.Session
* @see JavaMailSenderImpl
* @see MimeMessagePreparator
* @see MimeMessageHelper
*/
public interface JavaMailSender extends MailSender {
/**
* Create a new JavaMail MimeMessage for the underlying JavaMail Session
* of this sender. Needs to be called to create MimeMessage instances
* that can be prepared by the client and passed to send(MimeMessage).
* @return the new MimeMessage instance
* @see #send(MimeMessage)
* @see #send(MimeMessage[])
*/
MimeMessage createMimeMessage();
/**
* Create a new JavaMail MimeMessage for the underlying JavaMail Session
* of this sender, using the given input stream as the message source.
* @param contentStream the raw MIME input stream for the message
* @return the new MimeMessage instance
* @throws org.springframework.mail.MailParseException
* in case of message creation failure
*/
MimeMessage createMimeMessage(InputStream contentStream) throws MailException;
/**
* Send the given JavaMail MIME message.
* The message needs to have been created with {@link #createMimeMessage()}.
* @param mimeMessage message to send
* @throws org.springframework.mail.MailAuthenticationException
* in case of authentication failure
* @throws org.springframework.mail.MailSendException
* in case of failure when sending the message
* @see #createMimeMessage
*/
void send(MimeMessage mimeMessage) throws MailException;
/**
* Send the given array of JavaMail MIME messages in batch.
* The messages need to have been created with {@link #createMimeMessage()}.
* @param mimeMessages messages to send
* @throws org.springframework.mail.MailAuthenticationException
* in case of authentication failure
* @throws org.springframework.mail.MailSendException
* in case of failure when sending a message
* @see #createMimeMessage
*/
void send(MimeMessage[] mimeMessages) throws MailException;
/**
* Send the JavaMail MIME message prepared by the given MimeMessagePreparator.
* <p>Alternative way to prepare MimeMessage instances, instead of
* {@link #createMimeMessage()} and {@link #send(MimeMessage)} calls.
* Takes care of proper exception conversion.
* @param mimeMessagePreparator the preparator to use
* @throws org.springframework.mail.MailPreparationException
* in case of failure when preparing the message
* @throws org.springframework.mail.MailParseException
* in case of failure when parsing the message
* @throws org.springframework.mail.MailAuthenticationException
* in case of authentication failure
* @throws org.springframework.mail.MailSendException
* in case of failure when sending the message
*/
void send(MimeMessagePreparator mimeMessagePreparator) throws MailException;
/**
* Send the JavaMail MIME messages prepared by the given MimeMessagePreparators.
* <p>Alternative way to prepare MimeMessage instances, instead of
* {@link #createMimeMessage()} and {@link #send(MimeMessage[])} calls.
* Takes care of proper exception conversion.
* @param mimeMessagePreparators the preparator to use
* @throws org.springframework.mail.MailPreparationException
* in case of failure when preparing a message
* @throws org.springframework.mail.MailParseException
* in case of failure when parsing a message
* @throws org.springframework.mail.MailAuthenticationException
* in case of authentication failure
* @throws org.springframework.mail.MailSendException
* in case of failure when sending a message
*/
void send(MimeMessagePreparator[] mimeMessagePreparators) throws MailException;
}
/*
* Copyright 2002-2007 the original author or authors.
*
* 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.
*/
package org.springframework.mail.javamail;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.activation.FileTypeMap;
import javax.mail.AuthenticationFailedException;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.MimeMessage;
import org.springframework.mail.MailAuthenticationException;
import org.springframework.mail.MailException;
import org.springframework.mail.MailParseException;
import org.springframework.mail.MailPreparationException;
import org.springframework.mail.MailSendException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.util.Assert;
/**
* Production implementation of the {@link JavaMailSender} interface,
* supporting both JavaMail {@link MimeMessage MimeMessages} and Spring
* {@link SimpleMailMessage SimpleMailMessages}. Can also be used as a
* plain {@link org.springframework.mail.MailSender} implementation.
*
* <p>Allows for defining all settings locally as bean properties.
* Alternatively, a pre-configured JavaMail {@link javax.mail.Session} can be
* specified, possibly pulled from an application server's JNDI environment.
*
* <p>Non-default properties in this object will always override the settings
* in the JavaMail <code>Session</code>. Note that if overriding all values locally,
* there is no added value in setting a pre-configured <code>Session</code>.
*
* @author Dmitriy Kopylenko
* @author Juergen Hoeller
* @since 10.09.2003
* @see javax.mail.internet.MimeMessage
* @see javax.mail.Session
* @see #setSession
* @see #setJavaMailProperties
* @see #setHost
* @see #setPort
* @see #setUsername
* @see #setPassword
*/
public class JavaMailSenderImpl implements JavaMailSender {
/** The default protocol: 'smtp' */
public static final String DEFAULT_PROTOCOL = "smtp";
/** The default port: -1 */
public static final int DEFAULT_PORT = -1;
private static final String HEADER_MESSAGE_ID = "Message-ID";
private Properties javaMailProperties = new Properties();
private Session session;
private String protocol = DEFAULT_PROTOCOL;
private String host;
private int port = DEFAULT_PORT;
private String username;
private String password;
private String defaultEncoding;
private FileTypeMap defaultFileTypeMap;
/**
* Create a new instance of the <code>JavaMailSenderImpl</code> class.
* <p>Initializes the {@link #setDefaultFileTypeMap "defaultFileTypeMap"}
* property with a default {@link ConfigurableMimeFileTypeMap}.
*/
public JavaMailSenderImpl() {
ConfigurableMimeFileTypeMap fileTypeMap = new ConfigurableMimeFileTypeMap();
fileTypeMap.afterPropertiesSet();
this.defaultFileTypeMap = fileTypeMap;
}
/**
* Set JavaMail properties for the <code>Session</code>.
* <p>A new <code>Session</code> will be created with those properties.
* Use either this method or {@link #setSession}, but not both.
* <p>Non-default properties in this instance will override given
* JavaMail properties.
*/
public void setJavaMailProperties(Properties javaMailProperties) {
this.javaMailProperties = javaMailProperties;
synchronized (this) {
this.session = null;
}
}
/**
* Allow Map access to the JavaMail properties of this sender,
* with the option to add or override specific entries.
* <p>Useful for specifying entries directly, for example via
* "javaMailProperties[mail.smtp.auth]".
*/
public Properties getJavaMailProperties() {
return this.javaMailProperties;
}
/**
* Set the JavaMail <code>Session</code>, possibly pulled from JNDI.
* <p>Default is a new <code>Session</code> without defaults, that is
* completely configured via this instance's properties.
* <p>If using a pre-configured <code>Session</code>, non-default properties
* in this instance will override the settings in the <code>Session</code>.
* @see #setJavaMailProperties
*/
public synchronized void setSession(Session session) {
Assert.notNull(session, "Session must not be null");
this.session = session;
}
/**
* Return the JavaMail <code>Session</code>,
* lazily initializing it if hasn't been specified explicitly.
*/
public synchronized Session getSession() {
if (this.session == null) {
this.session = Session.getInstance(this.javaMailProperties);
}
return this.session;
}
/**
* Set the mail protocol. Default is "smtp".
*/
public void setProtocol(String protocol) {
this.protocol = protocol;
}
/**
* Return the mail protocol.
*/
public String getProtocol() {
return this.protocol;
}
/**
* Set the mail server host, typically an SMTP host.
* <p>Default is the default host of the underlying JavaMail Session.
*/
public void setHost(String host) {
this.host = host;
}
/**
* Return the mail server host.
*/
public String getHost() {
return this.host;
}
/**
* Set the mail server port.
* <p>Default is {@link #DEFAULT_PORT}, letting JavaMail use the default
* SMTP port (25).
*/
public void setPort(int port) {
this.port = port;
}
/**
* Return the mail server port.
*/
public int getPort() {
return this.port;
}
/**
* Set the username for the account at the mail host, if any.
* <p>Note that the underlying JavaMail <code>Session</code> has to be
* configured with the property <code>"mail.smtp.auth"</code> set to
* <code>true</code>, else the specified username will not be sent to the
* mail server by the JavaMail runtime. If you are not explicitly passing
* in a <code>Session</code> to use, simply specify this setting via
* {@link #setJavaMailProperties}.
* @see #setSession
* @see #setPassword
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Return the username for the account at the mail host.
*/
public String getUsername() {
return this.username;
}
/**
* Set the password for the account at the mail host, if any.
* <p>Note that the underlying JavaMail <code>Session</code> has to be
* configured with the property <code>"mail.smtp.auth"</code> set to
* <code>true</code>, else the specified password will not be sent to the
* mail server by the JavaMail runtime. If you are not explicitly passing
* in a <code>Session</code> to use, simply specify this setting via
* {@link #setJavaMailProperties}.
* @see #setSession
* @see #setUsername
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Return the password for the account at the mail host.
*/
public String getPassword() {
return this.password;
}
/**
* Set the default encoding to use for {@link MimeMessage MimeMessages}
* created by this instance.
* <p>Such an encoding will be auto-detected by {@link MimeMessageHelper}.
*/
public void setDefaultEncoding(String defaultEncoding) {
this.defaultEncoding = defaultEncoding;
}
/**
* Return the default encoding for {@link MimeMessage MimeMessages},
* or <code>null</code> if none.
*/
public String getDefaultEncoding() {
return this.defaultEncoding;
}
/**
* Set the default Java Activation {@link FileTypeMap} to use for
* {@link MimeMessage MimeMessages} created by this instance.
* <p>A <code>FileTypeMap</code> specified here will be autodetected by
* {@link MimeMessageHelper}, avoiding the need to specify the
* <code>FileTypeMap</code> for each <code>MimeMessageHelper</code> instance.
* <p>For example, you can specify a custom instance of Spring's
* {@link ConfigurableMimeFileTypeMap} here. If not explicitly specified,
* a default <code>ConfigurableMimeFileTypeMap</code> will be used, containing
* an extended set of MIME type mappings (as defined by the
* <code>mime.types</code> file contained in the Spring jar).
* @see MimeMessageHelper#setFileTypeMap
*/
public void setDefaultFileTypeMap(FileTypeMap defaultFileTypeMap) {
this.defaultFileTypeMap = defaultFileTypeMap;
}
/**
* Return the default Java Activation {@link FileTypeMap} for
* {@link MimeMessage MimeMessages}, or <code>null</code> if none.
*/
public FileTypeMap getDefaultFileTypeMap() {
return this.defaultFileTypeMap;
}
//---------------------------------------------------------------------
// Implementation of MailSender
//---------------------------------------------------------------------
public void send(SimpleMailMessage simpleMessage) throws MailException {
send(new SimpleMailMessage[] { simpleMessage });
}
public void send(SimpleMailMessage[] simpleMessages) throws MailException {
List mimeMessages = new ArrayList(simpleMessages.length);
for (int i = 0; i < simpleMessages.length; i++) {
SimpleMailMessage simpleMessage = simpleMessages[i];
MimeMailMessage message = new MimeMailMessage(createMimeMessage());
simpleMessage.copyTo(message);
mimeMessages.add(message.getMimeMessage());
}
doSend((MimeMessage[]) mimeMessages.toArray(new MimeMessage[mimeMessages.size()]), simpleMessages);
}
//---------------------------------------------------------------------
// Implementation of JavaMailSender
//---------------------------------------------------------------------
/**
* This implementation creates a SmartMimeMessage, holding the specified
* default encoding and default FileTypeMap. This special defaults-carrying
* message will be autodetected by {@link MimeMessageHelper}, which will use
* the carried encoding and FileTypeMap unless explicitly overridden.
* @see #setDefaultEncoding
* @see #setDefaultFileTypeMap
*/
public MimeMessage createMimeMessage() {
return new SmartMimeMessage(getSession(), getDefaultEncoding(), getDefaultFileTypeMap());
}
public MimeMessage createMimeMessage(InputStream contentStream) throws MailException {
try {
return new MimeMessage(getSession(), contentStream);
}
catch (MessagingException ex) {
throw new MailParseException("Could not parse raw MIME content", ex);
}
}
public void send(MimeMessage mimeMessage) throws MailException {
send(new MimeMessage[] { mimeMessage });
}
public void send(MimeMessage[] mimeMessages) throws MailException {
doSend(mimeMessages, null);
}
public void send(MimeMessagePreparator mimeMessagePreparator) throws MailException {
send(new MimeMessagePreparator[] { mimeMessagePreparator });
}
public void send(MimeMessagePreparator[] mimeMessagePreparators) throws MailException {
try {
List mimeMessages = new ArrayList(mimeMessagePreparators.length);
for (int i = 0; i < mimeMessagePreparators.length; i++) {
MimeMessage mimeMessage = createMimeMessage();
mimeMessagePreparators[i].prepare(mimeMessage);
mimeMessages.add(mimeMessage);
}
send((MimeMessage[]) mimeMessages.toArray(new MimeMessage[mimeMessages.size()]));
}
catch (MailException ex) {
throw ex;
}
catch (MessagingException ex) {
throw new MailParseException(ex);
}
catch (IOException ex) {
throw new MailPreparationException(ex);
}
catch (Exception ex) {
throw new MailPreparationException(ex);
}
}
/**
* Actually send the given array of MimeMessages via JavaMail.
* @param mimeMessages MimeMessage objects to send
* @param originalMessages corresponding original message objects
* that the MimeMessages have been created from (with same array
* length and indices as the "mimeMessages" array), if any
* @throws org.springframework.mail.MailAuthenticationException
* in case of authentication failure
* @throws org.springframework.mail.MailSendException
* in case of failure when sending a message
*/
protected void doSend(MimeMessage[] mimeMessages, Object[] originalMessages) throws MailException {
Map failedMessages = new LinkedHashMap();
try {
Transport transport = getTransport(getSession());
transport.connect(getHost(), getPort(), getUsername(), getPassword());
try {
for (int i = 0; i < mimeMessages.length; i++) {
MimeMessage mimeMessage = mimeMessages[i];
try {
if (mimeMessage.getSentDate() == null) {
mimeMessage.setSentDate(new Date());
}
String messageId = mimeMessage.getMessageID();
mimeMessage.saveChanges();
if (messageId != null) {
// Preserve explicitly specified message id...
mimeMessage.setHeader(HEADER_MESSAGE_ID, messageId);
}
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
}
catch (MessagingException ex) {
Object original = (originalMessages != null ? originalMessages[i] : mimeMessage);
failedMessages.put(original, ex);
}
}
}
finally {
transport.close();
}
}
catch (AuthenticationFailedException ex) {
throw new MailAuthenticationException(ex);
}
catch (MessagingException ex) {
throw new MailSendException("Mail server connection failed", ex);
}
if (!failedMessages.isEmpty()) {
throw new MailSendException(failedMessages);
}
}
/**
* Obtain a Transport object from the given JavaMail Session,
* using the configured protocol.
* <p>Can be overridden in subclasses, e.g. to return a mock Transport object.
* @see javax.mail.Session#getTransport(String)
* @see #getProtocol()
*/
protected Transport getTransport(Session session) throws NoSuchProviderException {
return session.getTransport(getProtocol());
}
}
/*
* Copyright 2002-2005 the original author or authors.
*
* 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.
*/
package org.springframework.mail.javamail;
import java.util.Date;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.springframework.mail.MailMessage;
import org.springframework.mail.MailParseException;
/**
* Implementation of the MailMessage interface for a JavaMail MIME message,
* to let message population code interact with a simple message or a MIME
* message through a common interface.
*
* <p>Uses a MimeMessageHelper underneath. Can either be created with a
* MimeMessageHelper instance or with a JavaMail MimeMessage instance.
*
* @author Juergen Hoeller
* @since 1.1.5
* @see MimeMessageHelper
* @see javax.mail.internet.MimeMessage
*/
public class MimeMailMessage implements MailMessage {
private final MimeMessageHelper helper;
/**
* Create a new MimeMailMessage based on the given MimeMessageHelper.
* @param mimeMessageHelper the MimeMessageHelper
*/
public MimeMailMessage(MimeMessageHelper mimeMessageHelper) {
this.helper = mimeMessageHelper;
}
/**
* Create a new MimeMailMessage based on the given JavaMail MimeMessage.
* @param mimeMessage the JavaMail MimeMessage
*/
public MimeMailMessage(MimeMessage mimeMessage) {
this.helper = new MimeMessageHelper(mimeMessage);
}
/**
* Return the MimeMessageHelper that this MimeMailMessage is based on.
*/
public final MimeMessageHelper getMimeMessageHelper() {
return this.helper;
}
/**
* Return the JavaMail MimeMessage that this MimeMailMessage is based on.
*/
public final MimeMessage getMimeMessage() {
return this.helper.getMimeMessage();
}
public void setFrom(String from) throws MailParseException {
try {
this.helper.setFrom(from);
}
catch (MessagingException ex) {
throw new MailParseException(ex);
}
}
public void setReplyTo(String replyTo) throws MailParseException {
try {
this.helper.setReplyTo(replyTo);
}
catch (MessagingException ex) {
throw new MailParseException(ex);
}
}
public void setTo(String to) throws MailParseException {
try {
this.helper.setTo(to);
}
catch (MessagingException ex) {
throw new MailParseException(ex);
}
}
public void setTo(String[] to) throws MailParseException {
try {
this.helper.setTo(to);
}
catch (MessagingException ex) {
throw new MailParseException(ex);
}
}
public void setCc(String cc) throws MailParseException {
try {
this.helper.setCc(cc);
}
catch (MessagingException ex) {
throw new MailParseException(ex);
}
}
public void setCc(String[] cc) throws MailParseException {
try {
this.helper.setCc(cc);
}
catch (MessagingException ex) {
throw new MailParseException(ex);
}
}
public void setBcc(String bcc) throws MailParseException {
try {
this.helper.setBcc(bcc);
}
catch (MessagingException ex) {
throw new MailParseException(ex);
}
}
public void setBcc(String[] bcc) throws MailParseException {
try {
this.helper.setBcc(bcc);
}
catch (MessagingException ex) {
throw new MailParseException(ex);
}
}
public void setSentDate(Date sentDate) throws MailParseException {
try {
this.helper.setSentDate(sentDate);
}
catch (MessagingException ex) {
throw new MailParseException(ex);
}
}
public void setSubject(String subject) throws MailParseException {
try {
this.helper.setSubject(subject);
}
catch (MessagingException ex) {
throw new MailParseException(ex);
}
}
public void setText(String text) throws MailParseException {
try {
this.helper.setText(text);
}
catch (MessagingException ex) {
throw new MailParseException(ex);
}
}
}
/*
* Copyright 2002-2006 the original author or authors.
*
* 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.
*/
package org.springframework.mail.javamail;
import javax.mail.internet.MimeMessage;
/**
* Callback interface for the preparation of JavaMail MIME messages.
*
* <p>The corresponding <code>send</code> methods of {@link JavaMailSender}
* will take care of the actual creation of a {@link MimeMessage} instance,
* and of proper exception conversion.
*
* <p>It is often convenient to use a {@link MimeMessageHelper} for populating
* the passed-in MimeMessage, in particular when working with attachments or
* special character encodings.
* See {@link MimeMessageHelper MimeMessageHelper's javadoc} for an example.
*
* @author Juergen Hoeller
* @since 07.10.2003
* @see JavaMailSender#send(MimeMessagePreparator)
* @see JavaMailSender#send(MimeMessagePreparator[])
* @see MimeMessageHelper
*/
public interface MimeMessagePreparator {
/**
* Prepare the given new MimeMessage instance.
* @param mimeMessage the message to prepare
* @throws javax.mail.MessagingException passing any exceptions thrown by MimeMessage
* methods through for automatic conversion to the MailException hierarchy
* @throws java.io.IOException passing any exceptions thrown by MimeMessage methods
* through for automatic conversion to the MailException hierarchy
* @throws Exception if mail preparation failed, for example when a
* Velocity template cannot be rendered for the mail text
*/
void prepare(MimeMessage mimeMessage) throws Exception;
}
/*
* Copyright 2002-2008 the original author or authors.
*
* 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.
*/
package org.springframework.mail.javamail;
import javax.activation.FileTypeMap;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
/**
* Special subclass of the standard JavaMail {@link MimeMessage}, carrying a
* default encoding to be used when populating the message and a default Java
* Activation {@link FileTypeMap} to be used for resolving attachment types.
*
* <p>Created by {@link JavaMailSenderImpl} in case of a specified default encoding
* and/or default FileTypeMap. Autodetected by {@link MimeMessageHelper}, which
* will use the carried encoding and FileTypeMap unless explicitly overridden.
*
* @author Juergen Hoeller
* @since 1.2
* @see JavaMailSenderImpl#createMimeMessage()
* @see MimeMessageHelper#getDefaultEncoding(javax.mail.internet.MimeMessage)
* @see MimeMessageHelper#getDefaultFileTypeMap(javax.mail.internet.MimeMessage)
*/
class SmartMimeMessage extends MimeMessage {
private final String defaultEncoding;
private final FileTypeMap defaultFileTypeMap;
/**
* Create a new SmartMimeMessage.
* @param session the JavaMail Session to create the message for
* @param defaultEncoding the default encoding, or <code>null</code> if none
* @param defaultFileTypeMap the default FileTypeMap, or <code>null</code> if none
*/
public SmartMimeMessage(Session session, String defaultEncoding, FileTypeMap defaultFileTypeMap) {
super(session);
this.defaultEncoding = defaultEncoding;
this.defaultFileTypeMap = defaultFileTypeMap;
}
/**
* Return the default encoding of this message, or <code>null</code> if none.
*/
public final String getDefaultEncoding() {
return this.defaultEncoding;
}
/**
* Return the default FileTypeMap of this message, or <code>null</code> if none.
*/
public final FileTypeMap getDefaultFileTypeMap() {
return this.defaultFileTypeMap;
}
}
################################################################################
#
# Defaults for the Java Activation Framework
# Additional extensions registered in this file:
# text/plain java c c++ pl cc h
#
################################################################################
text/html html htm HTML HTM
text/plain txt text TXT TEXT java c c++ pl cc h
image/gif gif GIF
image/ief ief
image/jpeg jpeg jpg jpe JPG
image/tiff tiff tif
image/x-xwindowdump xwd
application/postscript ai eps ps
application/rtf rtf
application/x-tex tex
application/x-texinfo texinfo texi
application/x-troff t tr roff
audio/basic au
audio/midi midi mid
audio/x-aifc aifc
audio/x-aiff aif aiff
audio/x-mpeg mpeg mpg
audio/x-wav wav
video/mpeg mpeg mpg mpe
video/quicktime qt mov
video/x-msvideo avi
################################################################################
#
# Additional file types adapted from
# http://www.utoronto.ca/webdocs/HTMLdocs/Book/Book-3ed/appb/mimetype.html
#
################################################################################
# TEXT TYPES
text/x-speech talk
text/css css
text/csv csv
# IMAGE TYPES
# X-Windows bitmap (b/w)
image/x-xbitmap xbm
# X-Windows pixelmap (8-bit color)
image/x-xpixmap xpm
# Portable Network Graphics
image/x-png png
# Image Exchange Format (RFC 1314)
image/ief ief
# JPEG
image/jpeg jpeg jpg jpe
# RGB
image/rgb rgb
# Group III Fax (RFC 1494)
image/g3fax g3f
# X Windowdump format
image/x-xwindowdump xwd
# Macintosh PICT format
image/x-pict pict
# PPM (UNIX PPM package)
image/x-portable-pixmap ppm
# PGM (UNIX PPM package)
image/x-portable-graymap pgm
# PBM (UNIX PPM package)
image/x-portable-bitmap pbm
# PNM (UNIX PPM package)
image/x-portable-anymap pnm
# Microsoft Windows bitmap
image/x-ms-bmp bmp
# CMU raster
image/x-cmu-raster ras
# Kodak Photo-CD
image/x-photo-cd pcd
# Computer Graphics Metafile
image/cgm cgm
# CALS Type 1 or 2
image/x-cals mil cal
# Fractal Image Format (Iterated Systems)
image/fif fif
# QuickSilver active image (Micrografx)
image/x-mgx-dsf dsf
# CMX vector image (Corel)
image/x-cmx cmx
# Wavelet-compressed (Summus)
image/wavelet wi
# AutoCad Drawing (SoftSource)
image/vnd.dwg dwg
# AutoCad DXF file (SoftSource)
image/vnd.dxf dxf
# Simple Vector Format (SoftSource)
image/vnd.svf svf
# AUDIO/VOICE/MUSIC RELATED TYPES
# """basic""audio - 8-bit u-law PCM"
audio/basic au snd
# Macintosh audio format (AIpple)
audio/x-aiff aif aiff aifc
# Microsoft audio
audio/x-wav wav
# MPEG audio
audio/x-mpeg mpa abs mpega
# MPEG-2 audio
audio/x-mpeg-2 mp2a mpa2
# compressed speech (Echo Speech Corp.)
audio/echospeech es
# Toolvox speech audio (Voxware)
audio/voxware vox
# RapidTransit compressed audio (Fast Man)
application/fastman lcc
# Realaudio (Progressive Networks)
application/x-pn-realaudio ra ram
# MIDI music data
x-music/x-midi mmid
# Koan music data (SSeyo)
application/vnd.koan skp
# Speech synthesis data (MVP Solutions)
text/x-speech talk
# VIDEO TYPES
# MPEG video
video/mpeg mpeg mpg mpe
# MPEG-2 video
video/mpeg-2 mpv2 mp2v
# Macintosh Quicktime
video/quicktime qt mov
# Microsoft video
video/x-msvideo avi
# SGI Movie format
video/x-sgi-movie movie
# VDOlive streaming video (VDOnet)
video/vdo vdo
# Vivo streaming video (Vivo software)
video/vnd.vivo viv
# SPECIAL HTTP/WEB APPLICATION TYPES
# Proxy autoconfiguration (Netscape browsers)
application/x-ns-proxy-autoconfig pac
# Netscape Cooltalk chat data (Netscape)
x-conference/x-cooltalk ice
# TEXT-RELATED
# PostScript
application/postscript ai eps ps
# Microsoft Rich Text Format
application/rtf rtf
# Adobe Acrobat PDF
application/pdf pdf
# Maker Interchange Format (FrameMaker)
application/vnd.mif mif
# Troff document
application/x-troff t tr roff
# Troff document with MAN macros
application/x-troff-man man
# Troff document with ME macros
application/x-troff-me me
# Troff document with MS macros
application/x-troff-ms ms
# LaTeX document
application/x-latex latex
# Tex/LateX document
application/x-tex tex
# GNU TexInfo document
application/x-texinfo texinfo texi
# TeX dvi format
application/x-dvi dvi
# MS word document
application/msword doc DOC
# Office Document Architecture
application/oda oda
# Envoy Document
application/envoy evy
# ARCHIVE/COMPRESSED ARCHIVES
# Gnu tar format
application/x-gtar gtar
# 4.3BSD tar format
application/x-tar tar
# POSIX tar format
application/x-ustar ustar
# Old CPIO format
application/x-bcpio bcpio
# POSIX CPIO format
application/x-cpio cpio
# UNIX sh shell archive
application/x-shar shar
# DOS/PC - Pkzipped archive
application/zip zip
# Macintosh Binhexed archive
application/mac-binhex40 hqx
# Macintosh Stuffit Archive
application/x-stuffit sit sea
# Fractal Image Format
application/fractals fif
# "Binary UUencoded"
application/octet-stream bin uu
# PC executable
application/octet-stream exe
# "WAIS ""sources"""
application/x-wais-source src wsrc
# NCSA HDF data format
application/hdf hdf
# DOWNLOADABLE PROGRAM/SCRIPTS
# Javascript program
text/javascript js ls mocha
# UNIX bourne shell program
application/x-sh sh
# UNIX c-shell program
application/x-csh csh
# Perl program
application/x-perl pl
# Tcl (Tool Control Language) program
application/x-tcl tcl
# ANIMATION/MULTIMEDIA
# FutureSplash vector animation (FutureWave)
application/futuresplash spl
# mBED multimedia data (mBED)
application/mbedlet mbd
# PowerMedia multimedia (RadMedia)
application/x-rad-powermedia rad
# PRESENTATION
# PowerPoint presentation (Microsoft)
application/mspowerpoint ppz
# ASAP WordPower (Software Publishing Corp.)
application/x-asap asp
# Astound Web Player multimedia data (GoldDisk)
application/astound asn
# SPECIAL EMBEDDED OBJECT
# OLE script e.g. Visual Basic (Ncompass)
application/x-olescript axs
# OLE Object (Microsoft/NCompass)
application/x-oleobject ods
# OpenScape OLE/OCX objects (Business@Web)
x-form/x-openscape opp
# Visual Basic objects (Amara)
application/x-webbasic wba
# Specialized data entry forms (Alpha Software)
application/x-alpha-form frm
# client-server objects (Wayfarer Communications)
x-script/x-wfxclient wfx
# GENERAL APPLICATIONS
# Undefined binary data (often executable progs)
application/octet-stream exe com
# Pointcast news data (Pointcast)
application/x-pcn pcn
# Excel spreadsheet (Microsoft)
application/vnd.ms-excel xls
# PowerPoint (Microsoft)
application/vnd.ms-powerpoint ppt
# Microsoft Project (Microsoft)
application/vnd.ms-project mpp
# SourceView document (Dataware Electronics)
application/vnd.svd svd
# Net Install - software install (20/20 Software)
application/x-net-install ins
# Carbon Copy - remote control/access (Microcom)
application/ccv ccv
# Spreadsheets (Visual Components)
workbook/formulaone vts
# 2D/3D DATA/VIRTUAL REALITY TYPES
# VRML data file
x-world/x-vrml wrl vrml
# WIRL - VRML data (VREAM)
x-world/x-vream vrw
# Play3D 3d scene data (Play3D)
application/x-p3d p3d
# Viscape Interactive 3d world data (Superscape)
x-world/x-svr svr
# WebActive 3d data (Plastic Thought)
x-world/x-wvr wvr
# QuickDraw3D scene data (Apple)
x-world/x-3dmf 3dmf
# SCIENTIFIC/MATH/CAD TYPES
# Mathematica notebook
application/mathematica ma
# Computational meshes for numerical simulations
x-model/x-mesh msh
# Vis5D 5-dimensional data
application/vis5d v5d
# IGES models -- CAD/CAM (CGM) data
application/iges igs
# Autocad WHIP vector drawings
drawing/x-dwf dwf
<html>
<body>
JavaMail support for Spring's mail infrastructure.
Provides an extended JavaMailSender interface and a MimeMessageHelper
class for convenient population of a JavaMail MimeMessage.
</body>
</html>
<html>
<body>
Spring's generic mail infrastructure.
Concrete implementations are provided in the subpackages.
</body>
</html>
/*
* Copyright 2002-2005 the original author or authors.
*
* 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.
*/
package org.springframework.scheduling.commonj;
import commonj.timers.Timer;
import commonj.timers.TimerListener;
import org.springframework.util.Assert;
/**
* Simple TimerListener adapter that delegates to a given Runnable.
*
* @author Juergen Hoeller
* @since 2.0
* @see commonj.timers.TimerListener
* @see java.lang.Runnable
*/
public class DelegatingTimerListener implements TimerListener {
private final Runnable runnable;
/**
* Create a new DelegatingTimerListener.
* @param runnable the Runnable implementation to delegate to
*/
public DelegatingTimerListener(Runnable runnable) {
Assert.notNull(runnable, "Runnable is required");
this.runnable = runnable;
}
/**
* Delegates execution to the underlying Runnable.
*/
public void timerExpired(Timer timer) {
this.runnable.run();
}
}
/*
* Copyright 2002-2007 the original author or authors.
*
* 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.
*/
package org.springframework.scheduling.commonj;
import commonj.work.Work;
import org.springframework.scheduling.SchedulingAwareRunnable;
import org.springframework.util.Assert;
/**
* Simple Work adapter that delegates to a given Runnable.
*
* @author Juergen Hoeller
* @since 2.0
* @see commonj.work.Work
* @see java.lang.Runnable
*/
public class DelegatingWork implements Work {
private final Runnable delegate;
/**
* Create a new DelegatingWork.
* @param delegate the Runnable implementation to delegate to
* (may be a SchedulingAwareRunnable for extended support)
* @see org.springframework.scheduling.SchedulingAwareRunnable
* @see #isDaemon()
*/
public DelegatingWork(Runnable delegate) {
Assert.notNull(delegate, "Delegate must not be null");
this.delegate = delegate;
}
/**
* Return the wrapped Runnable implementation.
*/
public final Runnable getDelegate() {
return this.delegate;
}
/**
* Delegates execution to the underlying Runnable.
*/
public void run() {
this.delegate.run();
}
/**
* This implementation delegates to
* {@link org.springframework.scheduling.SchedulingAwareRunnable#isLongLived()},
* if available.
*/
public boolean isDaemon() {
return (this.delegate instanceof SchedulingAwareRunnable &&
((SchedulingAwareRunnable) this.delegate).isLongLived());
}
/**
* This implementation is empty, since we expect the Runnable
* to terminate based on some specific shutdown signal.
*/
public void release() {
}
}
/*
* Copyright 2002-2007 the original author or authors.
*
* 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.
*/
package org.springframework.scheduling.commonj;
import commonj.timers.TimerListener;
/**
* JavaBean that describes a scheduled TimerListener, consisting of
* the TimerListener itself (or a Runnable to create a TimerListener for)
* and a delay plus period. Period needs to be specified;
* there is no point in a default for it.
*
* <p>The CommonJ TimerManager does not offer more sophisticated scheduling
* options such as cron expressions. Consider using Quartz for such
* advanced needs.
*
* <p>Note that the TimerManager uses a TimerListener instance that is
* shared between repeated executions, in contrast to Quartz which
* instantiates a new Job for each execution.
*
* @author Juergen Hoeller
* @since 2.0
* @see commonj.timers.TimerListener
* @see commonj.timers.TimerManager#schedule(commonj.timers.TimerListener, long, long)
* @see commonj.timers.TimerManager#scheduleAtFixedRate(commonj.timers.TimerListener, long, long)
*/
public class ScheduledTimerListener {
private TimerListener timerListener;
private long delay = 0;
private long period = -1;
private boolean fixedRate = false;
/**
* Create a new ScheduledTimerListener,
* to be populated via bean properties.
* @see #setTimerListener
* @see #setDelay
* @see #setPeriod
* @see #setFixedRate
*/
public ScheduledTimerListener() {
}
/**
* Create a new ScheduledTimerListener, with default
* one-time execution without delay.
* @param timerListener the TimerListener to schedule
*/
public ScheduledTimerListener(TimerListener timerListener) {
this.timerListener = timerListener;
}
/**
* Create a new ScheduledTimerListener, with default
* one-time execution with the given delay.
* @param timerListener the TimerListener to schedule
* @param delay the delay before starting the task for the first time (ms)
*/
public ScheduledTimerListener(TimerListener timerListener, long delay) {
this.timerListener = timerListener;
this.delay = delay;
}
/**
* Create a new ScheduledTimerListener.
* @param timerListener the TimerListener to schedule
* @param delay the delay before starting the task for the first time (ms)
* @param period the period between repeated task executions (ms)
* @param fixedRate whether to schedule as fixed-rate execution
*/
public ScheduledTimerListener(TimerListener timerListener, long delay, long period, boolean fixedRate) {
this.timerListener = timerListener;
this.delay = delay;
this.period = period;
this.fixedRate = fixedRate;
}
/**
* Create a new ScheduledTimerListener, with default
* one-time execution without delay.
* @param timerTask the Runnable to schedule as TimerListener
*/
public ScheduledTimerListener(Runnable timerTask) {
setRunnable(timerTask);
}
/**
* Create a new ScheduledTimerListener, with default
* one-time execution with the given delay.
* @param timerTask the Runnable to schedule as TimerListener
* @param delay the delay before starting the task for the first time (ms)
*/
public ScheduledTimerListener(Runnable timerTask, long delay) {
setRunnable(timerTask);
this.delay = delay;
}
/**
* Create a new ScheduledTimerListener.
* @param timerTask the Runnable to schedule as TimerListener
* @param delay the delay before starting the task for the first time (ms)
* @param period the period between repeated task executions (ms)
* @param fixedRate whether to schedule as fixed-rate execution
*/
public ScheduledTimerListener(Runnable timerTask, long delay, long period, boolean fixedRate) {
setRunnable(timerTask);
this.delay = delay;
this.period = period;
this.fixedRate = fixedRate;
}
/**
* Set the Runnable to schedule as TimerListener.
* @see DelegatingTimerListener
*/
public void setRunnable(Runnable timerTask) {
this.timerListener = new DelegatingTimerListener(timerTask);
}
/**
* Set the TimerListener to schedule.
*/
public void setTimerListener(TimerListener timerListener) {
this.timerListener = timerListener;
}
/**
* Return the TimerListener to schedule.
*/
public TimerListener getTimerListener() {
return this.timerListener;
}
/**
* Set the delay before starting the task for the first time,
* in milliseconds. Default is 0, immediately starting the
* task after successful scheduling.
* <p>If the "firstTime" property is specified, this property will be ignored.
* Specify one or the other, not both.
*/
public void setDelay(long delay) {
this.delay = delay;
}
/**
* Return the delay before starting the job for the first time.
*/
public long getDelay() {
return this.delay;
}
/**
* Set the period between repeated task executions, in milliseconds.
* <p>Default is -1, leading to one-time execution. In case of zero or a
* positive value, the task will be executed repeatedly, with the given
* interval inbetween executions.
* <p>Note that the semantics of the period value vary between fixed-rate
* and fixed-delay execution.
* <p><b>Note:</b> A period of 0 (for example as fixed delay) <i>is</i>
* supported, because the CommonJ specification defines this as a legal value.
* Hence a value of 0 will result in immediate re-execution after a job has
* finished (not in one-time execution like with <code>java.util.Timer</code>).
* @see #setFixedRate
* @see #isOneTimeTask()
* @see commonj.timers.TimerManager#schedule(commonj.timers.TimerListener, long, long)
*/
public void setPeriod(long period) {
this.period = period;
}
/**
* Return the period between repeated task executions.
*/
public long getPeriod() {
return this.period;
}
/**
* Is this task only ever going to execute once?
* @return <code>true</code> if this task is only ever going to execute once
* @see #getPeriod()
*/
public boolean isOneTimeTask() {
return (this.period < 0);
}
/**
* Set whether to schedule as fixed-rate execution, rather than
* fixed-delay execution. Default is "false", i.e. fixed delay.
* <p>See TimerManager javadoc for details on those execution modes.
* @see commonj.timers.TimerManager#schedule(commonj.timers.TimerListener, long, long)
* @see commonj.timers.TimerManager#scheduleAtFixedRate(commonj.timers.TimerListener, long, long)
*/
public void setFixedRate(boolean fixedRate) {
this.fixedRate = fixedRate;
}
/**
* Return whether to schedule as fixed-rate execution.
*/
public boolean isFixedRate() {
return this.fixedRate;
}
}
/*
* Copyright 2002-2007 the original author or authors.
*
* 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.
*/
package org.springframework.scheduling.commonj;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.naming.NamingException;
import commonj.timers.Timer;
import commonj.timers.TimerManager;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.Lifecycle;
import org.springframework.jndi.JndiLocatorSupport;
/**
* {@link org.springframework.beans.factory.FactoryBean} that retrieves a
* CommonJ {@link commonj.timers.TimerManager} and exposes it for bean references.
*
* <p><b>This is the central convenience class for setting up a
* CommonJ TimerManager in a Spring context.</b>
*
* <p>Allows for registration of ScheduledTimerListeners. This is the main
* purpose of this class; the TimerManager itself could also be fetched
* from JNDI via {@link org.springframework.jndi.JndiObjectFactoryBean}.
* In scenarios that just require static registration of tasks at startup,
* there is no need to access the TimerManager itself in application code.
*
* <p>Note that the TimerManager uses a TimerListener instance that is
* shared between repeated executions, in contrast to Quartz which
* instantiates a new Job for each execution.
*
* @author Juergen Hoeller
* @since 2.0
* @see ScheduledTimerListener
* @see commonj.timers.TimerManager
* @see commonj.timers.TimerListener
*/
public class TimerManagerFactoryBean extends JndiLocatorSupport
implements FactoryBean, InitializingBean, DisposableBean, Lifecycle {
private TimerManager timerManager;
private String timerManagerName;
private boolean shared = false;
private ScheduledTimerListener[] scheduledTimerListeners;
private final List timers = new LinkedList();
/**
* Specify the CommonJ TimerManager to delegate to.
* <p>Note that the given TimerManager's lifecycle will be managed
* by this FactoryBean.
* <p>Alternatively (and typically), you can specify the JNDI name
* of the target TimerManager.
* @see #setTimerManagerName
*/
public void setTimerManager(TimerManager timerManager) {
this.timerManager = timerManager;
}
/**
* Set the JNDI name of the CommonJ TimerManager.
* <p>This can either be a fully qualified JNDI name, or the JNDI name relative
* to the current environment naming context if "resourceRef" is set to "true".
* @see #setTimerManager
* @see #setResourceRef
*/
public void setTimerManagerName(String timerManagerName) {
this.timerManagerName = timerManagerName;
}
/**
* Specify whether the TimerManager obtained by this FactoryBean
* is a shared instance ("true") or an independent instance ("false").
* The lifecycle of the former is supposed to be managed by the application
* server, while the lifecycle of the latter is up to the application.
* <p>Default is "false", i.e. managing an independent TimerManager instance.
* This is what the CommonJ specification suggests that application servers
* are supposed to offer via JNDI lookups, typically declared as a
* <code>resource-ref</code> of type <code>commonj.timers.TimerManager</code>
* in <code>web.xml<code>, with <code>res-sharing-scope</code> set to 'Unshareable'.
* <p>Switch this flag to "true" if you are obtaining a shared TimerManager,
* typically through specifying the JNDI location of a TimerManager that
* has been explicitly declared as 'Shareable'. Note that WebLogic's
* cluster-aware Job Scheduler is a shared TimerManager too.
* <p>The sole difference between this FactoryBean being in shared or
* non-shared mode is that it will only attempt to suspend / resume / stop
* the underlying TimerManager in case of an independent (non-shared) instance.
* This only affects the {@link org.springframework.context.Lifecycle} support
* as well as application context shutdown.
* @see #stop()
* @see #start()
* @see #destroy()
* @see commonj.timers.TimerManager
*/
public void setShared(boolean shared) {
this.shared = shared;
}
/**
* Register a list of ScheduledTimerListener objects with the TimerManager
* that this FactoryBean creates. Depending on each ScheduledTimerListener's settings,
* it will be registered via one of TimerManager's schedule methods.
* @see commonj.timers.TimerManager#schedule(commonj.timers.TimerListener, long)
* @see commonj.timers.TimerManager#schedule(commonj.timers.TimerListener, long, long)
* @see commonj.timers.TimerManager#scheduleAtFixedRate(commonj.timers.TimerListener, long, long)
*/
public void setScheduledTimerListeners(ScheduledTimerListener[] scheduledTimerListeners) {
this.scheduledTimerListeners = scheduledTimerListeners;
}
//---------------------------------------------------------------------
// Implementation of InitializingBean interface
//---------------------------------------------------------------------
public void afterPropertiesSet() throws NamingException {
if (this.timerManager == null) {
if (this.timerManagerName == null) {
throw new IllegalArgumentException("Either 'timerManager' or 'timerManagerName' must be specified");
}
this.timerManager = (TimerManager) lookup(this.timerManagerName, TimerManager.class);
}
if (this.scheduledTimerListeners != null) {
for (int i = 0; i < this.scheduledTimerListeners.length; i++) {
ScheduledTimerListener scheduledTask = this.scheduledTimerListeners[i];
Timer timer = null;
if (scheduledTask.isOneTimeTask()) {
timer = this.timerManager.schedule(scheduledTask.getTimerListener(), scheduledTask.getDelay());
}
else {
if (scheduledTask.isFixedRate()) {
timer = this.timerManager.scheduleAtFixedRate(
scheduledTask.getTimerListener(), scheduledTask.getDelay(), scheduledTask.getPeriod());
}
else {
timer = this.timerManager.schedule(
scheduledTask.getTimerListener(), scheduledTask.getDelay(), scheduledTask.getPeriod());
}
}
this.timers.add(timer);
}
}
}
//---------------------------------------------------------------------
// Implementation of FactoryBean interface
//---------------------------------------------------------------------
public Object getObject() {
return this.timerManager;
}
public Class getObjectType() {
return (this.timerManager != null ? this.timerManager.getClass() : TimerManager.class);
}
public boolean isSingleton() {
return true;
}
//---------------------------------------------------------------------
// Implementation of Lifecycle interface
//---------------------------------------------------------------------
/**
* Resumes the underlying TimerManager (if not shared).
* @see commonj.timers.TimerManager#resume()
*/
public void start() {
if (!this.shared) {
this.timerManager.resume();
}
}
/**
* Suspends the underlying TimerManager (if not shared).
* @see commonj.timers.TimerManager#suspend()
*/
public void stop() {
if (!this.shared) {
this.timerManager.suspend();
}
}
/**
* Considers the underlying TimerManager as running if it is
* neither suspending nor stopping.
* @see commonj.timers.TimerManager#isSuspending()
* @see commonj.timers.TimerManager#isStopping()
*/
public boolean isRunning() {
return (!this.timerManager.isSuspending() && !this.timerManager.isStopping());
}
//---------------------------------------------------------------------
// Implementation of DisposableBean interface
//---------------------------------------------------------------------
/**
* Cancels all statically registered Timers on shutdown,
* and stops the underlying TimerManager (if not shared).
* @see commonj.timers.Timer#cancel()
* @see commonj.timers.TimerManager#stop()
*/
public void destroy() {
// Cancel all registered timers.
for (Iterator it = this.timers.iterator(); it.hasNext();) {
Timer timer = (Timer) it.next();
try {
timer.cancel();
}
catch (Throwable ex) {
logger.warn("Could not cancel CommonJ Timer", ex);
}
}
this.timers.clear();
// Stop the entire TimerManager, if necessary.
if (!this.shared) {
// May return early, but at least we already cancelled all known Timers.
this.timerManager.stop();
}
}
}
/*
* Copyright 2002-2008 the original author or authors.
*
* 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.
*/
package org.springframework.scheduling.commonj;
import java.util.Collection;
import javax.naming.NamingException;
import commonj.work.Work;
import commonj.work.WorkException;
import commonj.work.WorkItem;
import commonj.work.WorkListener;
import commonj.work.WorkManager;
import commonj.work.WorkRejectedException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.task.TaskRejectedException;
import org.springframework.jndi.JndiLocatorSupport;
import org.springframework.scheduling.SchedulingException;
import org.springframework.scheduling.SchedulingTaskExecutor;
import org.springframework.util.Assert;
/**
* TaskExecutor implementation that delegates to a CommonJ WorkManager,
* implementing the {@link commonj.work.WorkManager} interface,
* which either needs to be specified as reference or through the JNDI name.
*
* <p><b>This is the central convenience class for setting up a
* CommonJ WorkManager in a Spring context.</b>
*
* <p>Also implements the CommonJ WorkManager interface itself, delegating all
* calls to the target WorkManager. Hence, a caller can choose whether it wants
* to talk to this executor through the Spring TaskExecutor interface or the
* CommonJ WorkManager interface.
*
* <p>The CommonJ WorkManager will usually be retrieved from the application
* server's JNDI environment, as defined in the server's management console.
*
* <p><b>Note: At the time of this writing, the CommonJ WorkManager facility
* is only supported on IBM WebSphere 6.0+ and BEA WebLogic 9.0+,
* despite being such a crucial API for an application server.</b>
* (There is a similar facility available on WebSphere 5.1 Enterprise,
* though, which we will discuss below.)
*
* <p><b>On JBoss and GlassFish, a similar facility is available through
* the JCA WorkManager.</b> See the
* {@link org.springframework.jca.work.jboss.JBossWorkManagerTaskExecutor}
* {@link org.springframework.jca.work.glassfish.GlassFishWorkManagerTaskExecutor}
* classes which are the direct equivalent of this CommonJ adapter class.
*
* <p>A similar facility is available on WebSphere 5.1, under the name
* "Asynch Beans". Its central interface is called WorkManager too and is
* also obtained from JNDI, just like a standard CommonJ WorkManager.
* However, this WorkManager variant is notably different: The central
* execution method is called "startWork" instead of "schedule",
* and takes a slightly different Work interface as parameter.
*
* <p>Support for this WebSphere 5.1 variant can be built with this class
* and its helper DelegatingWork as template: Call the WorkManager's
* <code>startWork(Work)</code> instead of <code>schedule(Work)</code>
* in the <code>execute(Runnable)</code> implementation. Furthermore,
* for simplicity's sake, drop the entire "Implementation of the CommonJ
* WorkManager interface" section (and the corresponding
* <code>implements WorkManager</code> clause at the class level).
* Of course, you also need to change all <code>commonj.work</code> imports in
* your WorkManagerTaskExecutor and DelegatingWork variants to the corresponding
* WebSphere API imports (<code>com.ibm.websphere.asynchbeans.WorkManager</code>
* and <code>com.ibm.websphere.asynchbeans.Work</code>, respectively).
* This should be sufficient to get a TaskExecutor adapter for WebSphere 5.
*
* @author Juergen Hoeller
* @since 2.0
*/
public class WorkManagerTaskExecutor extends JndiLocatorSupport
implements SchedulingTaskExecutor, WorkManager, InitializingBean {
private WorkManager workManager;
private String workManagerName;
private WorkListener workListener;
/**
* Specify the CommonJ WorkManager to delegate to.
* <p>Alternatively, you can also specify the JNDI name
* of the target WorkManager.
* @see #setWorkManagerName
*/
public void setWorkManager(WorkManager workManager) {
this.workManager = workManager;
}
/**
* Set the JNDI name of the CommonJ WorkManager.
* <p>This can either be a fully qualified JNDI name,
* or the JNDI name relative to the current environment
* naming context if "resourceRef" is set to "true".
* @see #setWorkManager
* @see #setResourceRef
*/
public void setWorkManagerName(String workManagerName) {
this.workManagerName = workManagerName;
}
/**
* Specify a CommonJ WorkListener to apply, if any.
* <p>This shared WorkListener instance will be passed on to the
* WorkManager by all {@link #execute} calls on this TaskExecutor.
*/
public void setWorkListener(WorkListener workListener) {
this.workListener = workListener;
}
public void afterPropertiesSet() throws NamingException {
if (this.workManager == null) {
if (this.workManagerName == null) {
throw new IllegalArgumentException("Either 'workManager' or 'workManagerName' must be specified");
}
this.workManager = (WorkManager) lookup(this.workManagerName, WorkManager.class);
}
}
//-------------------------------------------------------------------------
// Implementation of the Spring SchedulingTaskExecutor interface
//-------------------------------------------------------------------------
public void execute(Runnable task) {
Assert.state(this.workManager != null, "No WorkManager specified");
Work work = new DelegatingWork(task);
try {
if (this.workListener != null) {
this.workManager.schedule(work, this.workListener);
}
else {
this.workManager.schedule(work);
}
}
catch (WorkRejectedException ex) {
throw new TaskRejectedException("CommonJ WorkManager did not accept task: " + task, ex);
}
catch (WorkException ex) {
throw new SchedulingException("Could not schedule task on CommonJ WorkManager", ex);
}
}
/**
* This task executor prefers short-lived work units.
*/
public boolean prefersShortLivedTasks() {
return true;
}
//-------------------------------------------------------------------------
// Implementation of the CommonJ WorkManager interface
//-------------------------------------------------------------------------
public WorkItem schedule(Work work)
throws WorkException, IllegalArgumentException {
return this.workManager.schedule(work);
}
public WorkItem schedule(Work work, WorkListener workListener)
throws WorkException, IllegalArgumentException {
return this.workManager.schedule(work, workListener);
}
public boolean waitForAll(Collection workItems, long timeout)
throws InterruptedException, IllegalArgumentException {
return this.workManager.waitForAll(workItems, timeout);
}
public Collection waitForAny(Collection workItems, long timeout)
throws InterruptedException, IllegalArgumentException {
return this.workManager.waitForAny(workItems, timeout);
}
}
<html>
<body>
Convenience classes for scheduling based on the CommonJ WorkManager/TimerManager
facility, as supported by IBM WebSphere 6.0+ and BEA WebLogic 9.0+.
</body>
</html>
/*
* Copyright 2002-2006 the original author or authors.
*
* 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.
*/
package org.springframework.scheduling.quartz;
import org.quartz.Job;
import org.quartz.SchedulerException;
import org.quartz.spi.JobFactory;
import org.quartz.spi.TriggerFiredBundle;
/**
* JobFactory implementation that supports {@link java.lang.Runnable}
* objects as well as standard Quartz {@link org.quartz.Job} instances.
*
* @author Juergen Hoeller
* @since 2.0
* @see DelegatingJob
* @see #adaptJob(Object)
*/
public class AdaptableJobFactory implements JobFactory {
public Job newJob(TriggerFiredBundle bundle) throws SchedulerException {
try {
Object jobObject = createJobInstance(bundle);
return adaptJob(jobObject);
}
catch (Exception ex) {
throw new SchedulerException("Job instantiation failed", ex);
}
}
/**
* Create an instance of the specified job class.
* <p>Can be overridden to post-process the job instance.
* @param bundle the TriggerFiredBundle from which the JobDetail
* and other info relating to the trigger firing can be obtained
* @return the job instance
* @throws Exception if job instantiation failed
*/
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
return bundle.getJobDetail().getJobClass().newInstance();
}
/**
* Adapt the given job object to the Quartz Job interface.
* <p>The default implementation supports straight Quartz Jobs
* as well as Runnables, which get wrapped in a DelegatingJob.
* @param jobObject the original instance of the specified job class
* @return the adapted Quartz Job instance
* @throws Exception if the given job could not be adapted
* @see DelegatingJob
*/
protected Job adaptJob(Object jobObject) throws Exception {
if (jobObject instanceof Job) {
return (Job) jobObject;
}
else if (jobObject instanceof Runnable) {
return new DelegatingJob((Runnable) jobObject);
}
else {
throw new IllegalArgumentException("Unable to execute job class [" + jobObject.getClass().getName() +
"]: only [org.quartz.Job] and [java.lang.Runnable] supported.");
}
}
}
/*
* Copyright 2002-2007 the original author or authors.
*
* 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.
*/
package org.springframework.scheduling.quartz;
import java.text.ParseException;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Constants;
/**
* Convenience subclass of Quartz's {@link org.quartz.CronTrigger}
* class, making bean-style usage easier.
*
* <p>CronTrigger itself is already a JavaBean but lacks sensible defaults.
* This class uses the Spring bean name as job name, the Quartz default group
* ("DEFAULT") as job group, the current time as start time, and indefinite
* repetition, if not specified.
*
* <p>This class will also register the trigger with the job name and group of
* a given {@link org.quartz.JobDetail}. This allows {@link SchedulerFactoryBean}
* to automatically register a trigger for the corresponding JobDetail,
* instead of registering the JobDetail separately.
*
* <p><b>NOTE:</b> This convenience subclass does not work with trigger
* persistence in Quartz 1.6, due to a change in Quartz's trigger handling.
* Use Quartz 1.5 if you rely on trigger persistence based on this class,
* or the standard Quartz {@link org.quartz.CronTrigger} class instead.
*
* @author Juergen Hoeller
* @since 18.02.2004
* @see #setName
* @see #setGroup
* @see #setStartTime
* @see #setJobName
* @see #setJobGroup
* @see #setJobDetail
* @see SchedulerFactoryBean#setTriggers
* @see SchedulerFactoryBean#setJobDetails
* @see SimpleTriggerBean
*/
public class CronTriggerBean extends CronTrigger
implements JobDetailAwareTrigger, BeanNameAware, InitializingBean {
/** Constants for the CronTrigger class */
private static final Constants constants = new Constants(CronTrigger.class);
private JobDetail jobDetail;
private String beanName;
/**
* Register objects in the JobDataMap via a given Map.
* <p>These objects will be available to this Trigger only,
* in contrast to objects in the JobDetail's data map.
* @param jobDataAsMap Map with String keys and any objects as values
* (for example Spring-managed beans)
* @see JobDetailBean#setJobDataAsMap
*/
public void setJobDataAsMap(Map jobDataAsMap) {
getJobDataMap().putAll(jobDataAsMap);
}
/**
* Set the misfire instruction via the name of the corresponding
* constant in the {@link org.quartz.CronTrigger} class.
* Default is <code>MISFIRE_INSTRUCTION_SMART_POLICY</code>.
* @see org.quartz.CronTrigger#MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
* @see org.quartz.CronTrigger#MISFIRE_INSTRUCTION_DO_NOTHING
* @see org.quartz.Trigger#MISFIRE_INSTRUCTION_SMART_POLICY
*/
public void setMisfireInstructionName(String constantName) {
setMisfireInstruction(constants.asNumber(constantName).intValue());
}
/**
* Set a list of TriggerListener names for this job, referring to
* non-global TriggerListeners registered with the Scheduler.
* <p>A TriggerListener name always refers to the name returned
* by the TriggerListener implementation.
* @see SchedulerFactoryBean#setTriggerListeners
* @see org.quartz.TriggerListener#getName
*/
public void setTriggerListenerNames(String[] names) {
for (int i = 0; i < names.length; i++) {
addTriggerListener(names[i]);
}
}
/**
* Set the JobDetail that this trigger should be associated with.
* <p>This is typically used with a bean reference if the JobDetail
* is a Spring-managed bean. Alternatively, the trigger can also
* be associated with a job by name and group.
* @see #setJobName
* @see #setJobGroup
*/
public void setJobDetail(JobDetail jobDetail) {
this.jobDetail = jobDetail;
}
public JobDetail getJobDetail() {
return this.jobDetail;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public void afterPropertiesSet() throws ParseException {
if (getName() == null) {
setName(this.beanName);
}
if (getGroup() == null) {
setGroup(Scheduler.DEFAULT_GROUP);
}
if (getStartTime() == null) {
setStartTime(new Date());
}
if (getTimeZone() == null) {
setTimeZone(TimeZone.getDefault());
}
if (this.jobDetail != null) {
setJobName(this.jobDetail.getName());
setJobGroup(this.jobDetail.getGroup());
}
}
}
<html>
<body>
Support classes for the open source scheduler
<a href="http://www.opensymphony.com/quartz">Quartz</a>,
allowing to set up Quartz Schedulers, JobDetails and
Triggers as beans in a Spring context. Also provides
convenience classes for implementing Quartz Jobs.
</body>
</html>
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册