Initial commit
This commit is contained in:
6
ch-10/account-parent/.classpath
Normal file
6
ch-10/account-parent/.classpath
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
ch-10/account-parent/.project
Normal file
23
ch-10/account-parent/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>account-aggregator</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.maven.ide.eclipse.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.maven.ide.eclipse.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,5 @@
|
||||
#Sun Feb 14 15:24:57 CST 2010
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
|
||||
org.eclipse.jdt.core.compiler.compliance=1.4
|
||||
org.eclipse.jdt.core.compiler.source=1.3
|
||||
@@ -0,0 +1,9 @@
|
||||
#Sun Feb 14 15:24:57 CST 2010
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
fullBuildGoals=process-test-resources
|
||||
includeModules=false
|
||||
resolveWorkspaceProjects=true
|
||||
resourceFilterGoals=process-resources resources\:testResources
|
||||
skipCompilerPlugin=true
|
||||
version=1
|
||||
10
ch-10/account-parent/account-captcha/.classpath
Normal file
10
ch-10/account-parent/account-captcha/.classpath
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
|
||||
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
ch-10/account-parent/account-captcha/.project
Normal file
23
ch-10/account-parent/account-captcha/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>account-captcha</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.maven.ide.eclipse.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.maven.ide.eclipse.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,6 @@
|
||||
#Wed Mar 24 17:07:29 CST 2010
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.5
|
||||
@@ -0,0 +1,9 @@
|
||||
#Wed Mar 24 16:30:18 CST 2010
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
fullBuildGoals=process-test-resources
|
||||
includeModules=false
|
||||
resolveWorkspaceProjects=true
|
||||
resourceFilterGoals=process-resources resources\:testResources
|
||||
skipCompilerPlugin=true
|
||||
version=1
|
||||
55
ch-10/account-parent/account-captcha/pom.xml
Normal file
55
ch-10/account-parent/account-captcha/pom.xml
Normal file
@@ -0,0 +1,55 @@
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.juvenxu.mvnbook.account</groupId>
|
||||
<artifactId>account-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>account-captcha</artifactId>
|
||||
<name>Account Captcha</name>
|
||||
|
||||
<properties>
|
||||
<kaptcha.version>2.3</kaptcha.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.code.kaptcha</groupId>
|
||||
<artifactId>kaptcha</artifactId>
|
||||
<version>${kaptcha.version}</version>
|
||||
<classifier>jdk15</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sonatype-forge</id>
|
||||
<name>Sonatype Forge</name>
|
||||
<url>http://repository.sonatype.org/content/groups/forge/</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.juvenxu.mvnbook.account.captcha;
|
||||
|
||||
public class AccountCaptchaException
|
||||
extends Exception
|
||||
{
|
||||
private static final long serialVersionUID = 1339439433313285858L;
|
||||
|
||||
public AccountCaptchaException( String message )
|
||||
{
|
||||
super( message );
|
||||
}
|
||||
|
||||
public AccountCaptchaException( String message, Throwable throwable )
|
||||
{
|
||||
super( message, throwable );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.juvenxu.mvnbook.account.captcha;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface AccountCaptchaService
|
||||
{
|
||||
String generateCaptchaKey()
|
||||
throws AccountCaptchaException;
|
||||
|
||||
byte[] generateCaptchaImage( String captchaKey )
|
||||
throws AccountCaptchaException;
|
||||
|
||||
boolean validateCaptcha( String captchaKey, String captchaValue )
|
||||
throws AccountCaptchaException;
|
||||
|
||||
List<String> getPreDefinedTexts();
|
||||
|
||||
void setPreDefinedTexts( List<String> preDefinedTexts );
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.juvenxu.mvnbook.account.captcha;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import com.google.code.kaptcha.impl.DefaultKaptcha;
|
||||
import com.google.code.kaptcha.util.Config;
|
||||
|
||||
public class AccountCaptchaServiceImpl
|
||||
implements AccountCaptchaService, InitializingBean
|
||||
{
|
||||
private DefaultKaptcha producer;
|
||||
|
||||
private Map<String, String> captchaMap = new HashMap<String, String>();
|
||||
|
||||
private List<String> preDefinedTexts;
|
||||
|
||||
private int textCount = 0;
|
||||
|
||||
public void afterPropertiesSet()
|
||||
throws Exception
|
||||
{
|
||||
producer = new DefaultKaptcha();
|
||||
|
||||
producer.setConfig( new Config( new Properties() ) );
|
||||
}
|
||||
|
||||
public String generateCaptchaKey()
|
||||
{
|
||||
String key = RandomGenerator.getRandomString();
|
||||
|
||||
String value = getCaptchaText();
|
||||
|
||||
captchaMap.put( key, value );
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
public List<String> getPreDefinedTexts()
|
||||
{
|
||||
return preDefinedTexts;
|
||||
}
|
||||
|
||||
public void setPreDefinedTexts( List<String> preDefinedTexts )
|
||||
{
|
||||
this.preDefinedTexts = preDefinedTexts;
|
||||
}
|
||||
|
||||
private String getCaptchaText()
|
||||
{
|
||||
if ( preDefinedTexts != null && !preDefinedTexts.isEmpty() )
|
||||
{
|
||||
String text = preDefinedTexts.get( textCount );
|
||||
|
||||
textCount = ( textCount + 1 ) % preDefinedTexts.size();
|
||||
|
||||
return text;
|
||||
}
|
||||
else
|
||||
{
|
||||
return producer.createText();
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] generateCaptchaImage( String captchaKey )
|
||||
throws AccountCaptchaException
|
||||
{
|
||||
String text = captchaMap.get( captchaKey );
|
||||
|
||||
if ( text == null )
|
||||
{
|
||||
throw new AccountCaptchaException( "Captch key '" + captchaKey + "' not found!" );
|
||||
}
|
||||
|
||||
BufferedImage image = producer.createImage( text );
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
try
|
||||
{
|
||||
ImageIO.write( image, "jpg", out );
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
throw new AccountCaptchaException( "Failed to write captcha stream!", e );
|
||||
}
|
||||
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
public boolean validateCaptcha( String captchaKey, String captchaValue )
|
||||
throws AccountCaptchaException
|
||||
{
|
||||
String text = captchaMap.get( captchaKey );
|
||||
|
||||
if ( text == null )
|
||||
{
|
||||
throw new AccountCaptchaException( "Captch key '" + captchaKey + "' not found!" );
|
||||
}
|
||||
|
||||
if ( text.equals( captchaValue ) )
|
||||
{
|
||||
captchaMap.remove( captchaKey );
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.juvenxu.mvnbook.account.captcha;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class RandomGenerator
|
||||
{
|
||||
private static String range = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
public static synchronized String getRandomString()
|
||||
{
|
||||
Random random = new Random();
|
||||
|
||||
StringBuffer result = new StringBuffer();
|
||||
|
||||
for ( int i = 0; i < 8; i++ )
|
||||
{
|
||||
result.append( range.charAt( random.nextInt( range.length() ) ) );
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<bean id="accountCaptchaService"
|
||||
class="com.juvenxu.mvnbook.account.captcha.AccountCaptchaServiceImpl">
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.juvenxu.mvnbook.account.captcha;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
public class AccountCaptchaServiceTest
|
||||
{
|
||||
private AccountCaptchaService service;
|
||||
|
||||
@Before
|
||||
public void prepare()
|
||||
throws Exception
|
||||
{
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext( "account-captcha.xml" );
|
||||
service = (AccountCaptchaService) ctx.getBean( "accountCaptchaService" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateCaptcha()
|
||||
throws Exception
|
||||
{
|
||||
String captchaKey = service.generateCaptchaKey();
|
||||
assertNotNull( captchaKey );
|
||||
|
||||
byte[] captchaImage = service.generateCaptchaImage( captchaKey );
|
||||
assertTrue( captchaImage.length > 0 );
|
||||
|
||||
File image = new File( "target/" + captchaKey + ".jpg" );
|
||||
OutputStream output = null;
|
||||
try
|
||||
{
|
||||
output = new FileOutputStream( image );
|
||||
output.write( captchaImage );
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ( output != null )
|
||||
{
|
||||
output.close();
|
||||
}
|
||||
}
|
||||
assertTrue( image.exists() && image.length() > 0 );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCaptchaCorrect()
|
||||
throws Exception
|
||||
{
|
||||
List<String> preDefinedTexts = new ArrayList<String>();
|
||||
preDefinedTexts.add( "12345" );
|
||||
preDefinedTexts.add( "abcde" );
|
||||
service.setPreDefinedTexts( preDefinedTexts );
|
||||
|
||||
String captchaKey = service.generateCaptchaKey();
|
||||
service.generateCaptchaImage( captchaKey );
|
||||
assertTrue( service.validateCaptcha( captchaKey, "12345" ) );
|
||||
|
||||
captchaKey = service.generateCaptchaKey();
|
||||
service.generateCaptchaImage( captchaKey );
|
||||
assertTrue( service.validateCaptcha( captchaKey, "abcde" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCaptchaIncorrect()
|
||||
throws Exception
|
||||
{
|
||||
List<String> preDefinedTexts = new ArrayList<String>();
|
||||
preDefinedTexts.add( "12345" );
|
||||
service.setPreDefinedTexts( preDefinedTexts );
|
||||
|
||||
String captchaKey = service.generateCaptchaKey();
|
||||
service.generateCaptchaImage( captchaKey );
|
||||
assertFalse( service.validateCaptcha( captchaKey, "67890" ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.juvenxu.mvnbook.account.captcha;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class RandomGeneratorTest
|
||||
{
|
||||
@Test
|
||||
public void testGetRandomString()
|
||||
throws Exception
|
||||
{
|
||||
Set<String> randoms = new HashSet<String>( 100 );
|
||||
|
||||
for ( int i = 0; i < 100; i++ )
|
||||
{
|
||||
String random = RandomGenerator.getRandomString();
|
||||
|
||||
assertFalse( randoms.contains( random ) );
|
||||
|
||||
randoms.add( random );
|
||||
}
|
||||
}
|
||||
}
|
||||
10
ch-10/account-parent/account-email/.classpath
Normal file
10
ch-10/account-parent/account-email/.classpath
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
|
||||
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
ch-10/account-parent/account-email/.project
Normal file
23
ch-10/account-parent/account-email/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>account-email</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.maven.ide.eclipse.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.maven.ide.eclipse.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,6 @@
|
||||
#Wed Mar 24 16:29:49 CST 2010
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.5
|
||||
@@ -0,0 +1,9 @@
|
||||
#Mon Feb 15 22:20:48 CST 2010
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
fullBuildGoals=process-test-resources
|
||||
includeModules=false
|
||||
resolveWorkspaceProjects=true
|
||||
resourceFilterGoals=process-resources resources\:testResources
|
||||
skipCompilerPlugin=true
|
||||
version=1
|
||||
56
ch-10/account-parent/account-email/pom.xml
Normal file
56
ch-10/account-parent/account-email/pom.xml
Normal file
@@ -0,0 +1,56 @@
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.juvenxu.mvnbook.account</groupId>
|
||||
<artifactId>account-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>account-email</artifactId>
|
||||
<name>Account Email</name>
|
||||
|
||||
<properties>
|
||||
<javax.mail.version>1.4.1</javax.mail.version>
|
||||
<greenmail.version>1.3.1b</greenmail.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.mail</groupId>
|
||||
<artifactId>mail</artifactId>
|
||||
<version>${javax.mail.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.icegreen</groupId>
|
||||
<artifactId>greenmail</artifactId>
|
||||
<version>${greenmail.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.juvenxu.mvnbook.account.email;
|
||||
|
||||
public class AccountEmailException
|
||||
extends Exception
|
||||
{
|
||||
private static final long serialVersionUID = -4817386460334501672L;
|
||||
|
||||
public AccountEmailException( String message )
|
||||
{
|
||||
super( message );
|
||||
}
|
||||
|
||||
public AccountEmailException( String message, Throwable throwable )
|
||||
{
|
||||
super( message, throwable );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.juvenxu.mvnbook.account.email;
|
||||
|
||||
public interface AccountEmailService
|
||||
{
|
||||
void sendMail( String to, String subject, String htmlText )
|
||||
throws AccountEmailException;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.juvenxu.mvnbook.account.email;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||
|
||||
public class AccountEmailServiceImpl
|
||||
implements AccountEmailService
|
||||
{
|
||||
private JavaMailSender javaMailSender;
|
||||
|
||||
private String systemEmail;
|
||||
|
||||
public void sendMail( String to, String subject, String htmlText )
|
||||
throws AccountEmailException
|
||||
{
|
||||
try
|
||||
{
|
||||
MimeMessage msg = javaMailSender.createMimeMessage();
|
||||
MimeMessageHelper msgHelper = new MimeMessageHelper( msg );
|
||||
|
||||
msgHelper.setFrom( systemEmail );
|
||||
msgHelper.setTo( to );
|
||||
msgHelper.setSubject( subject );
|
||||
msgHelper.setText( htmlText, true );
|
||||
|
||||
javaMailSender.send( msg );
|
||||
}
|
||||
catch ( MessagingException e )
|
||||
{
|
||||
throw new AccountEmailException( "Faild to send mail.", e );
|
||||
}
|
||||
}
|
||||
|
||||
public JavaMailSender getJavaMailSender()
|
||||
{
|
||||
return javaMailSender;
|
||||
}
|
||||
|
||||
public void setJavaMailSender( JavaMailSender javaMailSender )
|
||||
{
|
||||
this.javaMailSender = javaMailSender;
|
||||
}
|
||||
|
||||
public String getSystemEmail()
|
||||
{
|
||||
return systemEmail;
|
||||
}
|
||||
|
||||
public void setSystemEmail( String systemEmail )
|
||||
{
|
||||
this.systemEmail = systemEmail;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<bean id="propertyConfigurer"
|
||||
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
|
||||
<property name="location" value="classpath:service.properties" />
|
||||
</bean>
|
||||
|
||||
<bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
|
||||
<property name="protocol" value="${email.protocol}" />
|
||||
<property name="host" value="${email.host}" />
|
||||
<property name="port" value="${email.port}" />
|
||||
<property name="username" value="${email.username}" />
|
||||
<property name="password" value="${email.password}" />
|
||||
<property name="javaMailProperties">
|
||||
<props>
|
||||
<prop key="mail.${email.protocol}.auth">${email.auth}</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="accountEmailService"
|
||||
class="com.juvenxu.mvnbook.account.email.AccountEmailServiceImpl">
|
||||
<property name="javaMailSender" ref="javaMailSender" />
|
||||
<property name="systemEmail" value="${email.systemEmail}" />
|
||||
</bean>
|
||||
</beans>
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.juvenxu.mvnbook.account.email;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import javax.mail.Message;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
import com.icegreen.greenmail.util.GreenMail;
|
||||
import com.icegreen.greenmail.util.GreenMailUtil;
|
||||
import com.icegreen.greenmail.util.ServerSetup;
|
||||
|
||||
public class AccountEmailServiceTest
|
||||
{
|
||||
private GreenMail greenMail;
|
||||
|
||||
@Before
|
||||
public void startMailServer()
|
||||
throws Exception
|
||||
{
|
||||
greenMail = new GreenMail( ServerSetup.SMTP );
|
||||
greenMail.setUser( "test@juvenxu.com", "123456" );
|
||||
greenMail.start();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendMail()
|
||||
throws Exception
|
||||
{
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext( "account-email.xml" );
|
||||
AccountEmailService accountEmailService = (AccountEmailService) ctx.getBean( "accountEmailService" );
|
||||
|
||||
String subject = "Test Subject";
|
||||
String htmlText = "<h3>Test</h3>";
|
||||
accountEmailService.sendMail( "test2@juvenxu.com", subject, htmlText );
|
||||
|
||||
greenMail.waitForIncomingEmail( 2000, 1 );
|
||||
|
||||
Message[] msgs = greenMail.getReceivedMessages();
|
||||
assertEquals( 1, msgs.length );
|
||||
assertEquals( subject, msgs[0].getSubject() );
|
||||
assertEquals( htmlText, GreenMailUtil.getBody( msgs[0] ).trim() );
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopMailServer()
|
||||
throws Exception
|
||||
{
|
||||
greenMail.stop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#email.protocol=smtps
|
||||
#email.host=smtp.gmail.com
|
||||
#email.port=465
|
||||
#email.username=your-id@gmail.com
|
||||
#email.password=your-password
|
||||
#email.auth=true
|
||||
#email.systemEmail=your-id@gmail.com
|
||||
|
||||
email.protocol=smtp
|
||||
email.host=localhost
|
||||
email.port=25
|
||||
email.username=test@juvenxu.com
|
||||
email.password=123456
|
||||
email.auth=true
|
||||
email.systemEmail=test1@juvenxu.com
|
||||
10
ch-10/account-parent/account-persist/.classpath
Normal file
10
ch-10/account-parent/account-persist/.classpath
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
|
||||
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
ch-10/account-parent/account-persist/.project
Normal file
23
ch-10/account-parent/account-persist/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>account-persist</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.maven.ide.eclipse.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.maven.ide.eclipse.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,6 @@
|
||||
#Wed Mar 24 16:29:49 CST 2010
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.5
|
||||
@@ -0,0 +1,9 @@
|
||||
#Mon Feb 15 22:20:48 CST 2010
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
fullBuildGoals=process-test-resources
|
||||
includeModules=false
|
||||
resolveWorkspaceProjects=true
|
||||
resourceFilterGoals=process-resources resources\:testResources
|
||||
skipCompilerPlugin=true
|
||||
version=1
|
||||
50
ch-10/account-parent/account-persist/pom.xml
Normal file
50
ch-10/account-parent/account-persist/pom.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.juvenxu.mvnbook.account</groupId>
|
||||
<artifactId>account-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>account-persist</artifactId>
|
||||
<name>Account Persist</name>
|
||||
|
||||
<properties>
|
||||
<dom4j.version>1.6.1</dom4j.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>${dom4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>src/test/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</testResource>
|
||||
</testResources>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.juvenxu.mvnbook.account.persist;
|
||||
|
||||
public class Account
|
||||
{
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String email;
|
||||
|
||||
private String password;
|
||||
|
||||
private boolean activated;
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId( String id )
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName( String name )
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getEmail()
|
||||
{
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail( String email )
|
||||
{
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPassword()
|
||||
{
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword( String password )
|
||||
{
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public boolean isActivated()
|
||||
{
|
||||
return activated;
|
||||
}
|
||||
|
||||
public void setActivated( boolean activated )
|
||||
{
|
||||
this.activated = activated;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.juvenxu.mvnbook.account.persist;
|
||||
|
||||
public class AccountPersistException
|
||||
extends Exception
|
||||
{
|
||||
private static final long serialVersionUID = -8334988626147289624L;
|
||||
|
||||
public AccountPersistException( String message )
|
||||
{
|
||||
super( message );
|
||||
}
|
||||
|
||||
public AccountPersistException( String message, Throwable throwable )
|
||||
{
|
||||
super( message, throwable );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.juvenxu.mvnbook.account.persist;
|
||||
|
||||
public interface AccountPersistService
|
||||
{
|
||||
Account createAccount( Account account )
|
||||
throws AccountPersistException;
|
||||
|
||||
Account readAccount( String id )
|
||||
throws AccountPersistException;
|
||||
|
||||
Account updateAccount( Account account )
|
||||
throws AccountPersistException;
|
||||
|
||||
void deleteAccount( String id )
|
||||
throws AccountPersistException;
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
package com.juvenxu.mvnbook.account.persist;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.DocumentFactory;
|
||||
import org.dom4j.Element;
|
||||
import org.dom4j.io.OutputFormat;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.dom4j.io.XMLWriter;
|
||||
|
||||
public class AccountPersistServiceImpl
|
||||
implements AccountPersistService
|
||||
{
|
||||
private static final String ELEMENT_ROOT = "account-persist";
|
||||
private static final String ELEMENT_ACCOUNTS = "accounts";
|
||||
private static final String ELEMENT_ACCOUNT = "account";
|
||||
private static final String ELEMENT_ACCOUNT_ID = "id";
|
||||
private static final String ELEMENT_ACCOUNT_NAME = "name";
|
||||
private static final String ELEMENT_ACCOUNT_EMAIL = "email";
|
||||
private static final String ELEMENT_ACCOUNT_PASSWORD = "password";
|
||||
private static final String ELEMENT_ACCOUNT_ACTIVATED = "activated";
|
||||
|
||||
private String file;
|
||||
|
||||
private SAXReader reader = new SAXReader();
|
||||
|
||||
public String getFile()
|
||||
{
|
||||
return file;
|
||||
}
|
||||
|
||||
public void setFile( String file )
|
||||
{
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public Account createAccount( Account account )
|
||||
throws AccountPersistException
|
||||
{
|
||||
Document doc = readDocument();
|
||||
|
||||
Element accountsEle = doc.getRootElement().element(ELEMENT_ACCOUNTS);
|
||||
|
||||
accountsEle.add( buildAccountElement( account ) );
|
||||
|
||||
writeDocument( doc );
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void deleteAccount( String id )
|
||||
throws AccountPersistException
|
||||
{
|
||||
Document doc = readDocument();
|
||||
|
||||
Element accountsEle = doc.getRootElement().element( ELEMENT_ACCOUNTS );
|
||||
|
||||
for ( Element accountEle : (List<Element>) accountsEle.elements() )
|
||||
{
|
||||
if ( accountEle.elementText( ELEMENT_ACCOUNT_ID ).equals( id ) )
|
||||
{
|
||||
accountEle.detach();
|
||||
|
||||
writeDocument( doc );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Account readAccount( String id )
|
||||
throws AccountPersistException
|
||||
{
|
||||
Document doc = readDocument();
|
||||
|
||||
Element accountsEle = doc.getRootElement().element( ELEMENT_ACCOUNTS );
|
||||
|
||||
for ( Element accountEle : (List<Element>) accountsEle.elements() )
|
||||
{
|
||||
if ( accountEle.elementText( ELEMENT_ACCOUNT_ID ).equals( id ) )
|
||||
{
|
||||
return buildAccount( accountEle );
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Account updateAccount( Account account )
|
||||
throws AccountPersistException
|
||||
{
|
||||
if ( readAccount( account.getId() ) != null )
|
||||
{
|
||||
deleteAccount( account.getId() );
|
||||
|
||||
return createAccount ( account );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Account buildAccount( Element element )
|
||||
{
|
||||
Account account = new Account();
|
||||
|
||||
account.setId( element.elementText( ELEMENT_ACCOUNT_ID ) );
|
||||
account.setName( element.elementText( ELEMENT_ACCOUNT_NAME ) );
|
||||
account.setEmail( element.elementText( ELEMENT_ACCOUNT_EMAIL ) );
|
||||
account.setPassword( element.elementText( ELEMENT_ACCOUNT_PASSWORD ) );
|
||||
account.setActivated( ( "true".equals( element.elementText( ELEMENT_ACCOUNT_ACTIVATED ) ) ? true : false ) );
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
private Element buildAccountElement( Account account )
|
||||
{
|
||||
Element element = DocumentFactory.getInstance().createElement( ELEMENT_ACCOUNT );
|
||||
|
||||
element.addElement( ELEMENT_ACCOUNT_ID ).setText( account.getId() );
|
||||
element.addElement( ELEMENT_ACCOUNT_NAME ).setText( account.getName() );
|
||||
element.addElement( ELEMENT_ACCOUNT_EMAIL ).setText( account.getEmail() );
|
||||
element.addElement( ELEMENT_ACCOUNT_PASSWORD ).setText( account.getPassword() );
|
||||
element.addElement( ELEMENT_ACCOUNT_ACTIVATED ).setText( account.isActivated() ? "true" : "false" );
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
private Document readDocument()
|
||||
throws AccountPersistException
|
||||
{
|
||||
File dataFile = new File( file );
|
||||
|
||||
if( !dataFile.exists() )
|
||||
{
|
||||
dataFile.getParentFile().mkdirs();
|
||||
|
||||
Document doc = DocumentFactory.getInstance().createDocument();
|
||||
|
||||
Element rootEle = doc.addElement( ELEMENT_ROOT );
|
||||
|
||||
rootEle.addElement( ELEMENT_ACCOUNTS );
|
||||
|
||||
writeDocument( doc );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return reader.read( new File( file ) );
|
||||
}
|
||||
catch ( DocumentException e )
|
||||
{
|
||||
throw new AccountPersistException( "Unable to read persist data xml", e );
|
||||
}
|
||||
}
|
||||
|
||||
private void writeDocument( Document doc )
|
||||
throws AccountPersistException
|
||||
{
|
||||
Writer out = null;
|
||||
|
||||
try
|
||||
{
|
||||
out = new OutputStreamWriter( new FileOutputStream( file ), "utf-8" );
|
||||
|
||||
XMLWriter writer = new XMLWriter( out, OutputFormat.createPrettyPrint() );
|
||||
|
||||
writer.write( doc );
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
throw new AccountPersistException( "Unable to write persist data xml", e );
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( out != null)
|
||||
{
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
throw new AccountPersistException( "Unable to close persist data xml writer", e );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<bean id="propertyConfigurer"
|
||||
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
|
||||
<property name="location" value="classpath:account-service.properties" />
|
||||
</bean>
|
||||
|
||||
<bean id="accountPersistService"
|
||||
class="com.juvenxu.mvnbook.account.persist.AccountPersistServiceImpl">
|
||||
<property name="file" value="${persist.file}" />
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.juvenxu.mvnbook.account.persist;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
public class AccountPersistServiceTest
|
||||
{
|
||||
private AccountPersistService service;
|
||||
|
||||
@Before
|
||||
public void prepare()
|
||||
throws Exception
|
||||
{
|
||||
File persistDataFile = new File ( "target/test-classes/persist-data.xml" );
|
||||
|
||||
if ( persistDataFile.exists() )
|
||||
{
|
||||
persistDataFile.delete();
|
||||
}
|
||||
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext( "account-persist.xml" );
|
||||
|
||||
service = (AccountPersistService) ctx.getBean( "accountPersistService" );
|
||||
|
||||
Account account = new Account();
|
||||
account.setId("juven");
|
||||
account.setName("Juven Xu");
|
||||
account.setEmail("juven@changeme.com");
|
||||
account.setPassword("this_should_be_encrypted");
|
||||
account.setActivated(true);
|
||||
|
||||
service.createAccount(account);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadAccount()
|
||||
throws Exception
|
||||
{
|
||||
Account account = service.readAccount( "juven" );
|
||||
|
||||
assertNotNull( account );
|
||||
assertEquals( "juven", account.getId() );
|
||||
assertEquals( "Juven Xu", account.getName() );
|
||||
assertEquals( "juven@changeme.com", account.getEmail() );
|
||||
assertEquals( "this_should_be_encrypted", account.getPassword() );
|
||||
assertTrue( account.isActivated() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteAccount()
|
||||
throws Exception
|
||||
{
|
||||
assertNotNull( service.readAccount( "juven" ) );
|
||||
service.deleteAccount( "juven" );
|
||||
assertNull( service.readAccount( "juven" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAccount()
|
||||
throws Exception
|
||||
{
|
||||
assertNull( service.readAccount( "mike" ) );
|
||||
|
||||
Account account = new Account();
|
||||
account.setId("mike");
|
||||
account.setName("Mike");
|
||||
account.setEmail("mike@changeme.com");
|
||||
account.setPassword("this_should_be_encrypted");
|
||||
account.setActivated(true);
|
||||
|
||||
service.createAccount(account);
|
||||
|
||||
assertNotNull( service.readAccount( "mike" ));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAccount()
|
||||
throws Exception
|
||||
{
|
||||
Account account = service.readAccount( "juven" );
|
||||
|
||||
account.setName("Juven Xu 1");
|
||||
account.setEmail("juven1@changeme.com");
|
||||
account.setPassword("this_still_should_be_encrypted");
|
||||
account.setActivated(false);
|
||||
|
||||
service.updateAccount( account );
|
||||
|
||||
account = service.readAccount( "juven" );
|
||||
|
||||
assertEquals( "Juven Xu 1", account.getName() );
|
||||
assertEquals( "juven1@changeme.com", account.getEmail() );
|
||||
assertEquals( "this_still_should_be_encrypted", account.getPassword() );
|
||||
assertFalse( account.isActivated() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
persist.file=${project.build.testOutputDirectory}/persist-data.xml
|
||||
69
ch-10/account-parent/pom.xml
Normal file
69
ch-10/account-parent/pom.xml
Normal file
@@ -0,0 +1,69 @@
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.juvenxu.mvnbook.account</groupId>
|
||||
<artifactId>account-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Account Parent</name>
|
||||
<modules>
|
||||
<module>account-email</module>
|
||||
<module>account-persist</module>
|
||||
<module>account-captcha</module>
|
||||
</modules>
|
||||
<properties>
|
||||
<springframework.version>2.5.6</springframework.version>
|
||||
<junit.version>4.7</junit.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>${springframework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>${springframework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${springframework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<version>${springframework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.5</source>
|
||||
<target>1.5</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<configuration>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
6
ch-12/account-parent/.classpath
Normal file
6
ch-12/account-parent/.classpath
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
ch-12/account-parent/.project
Normal file
23
ch-12/account-parent/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>account-aggregator</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.maven.ide.eclipse.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.maven.ide.eclipse.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,5 @@
|
||||
#Sun Feb 14 15:24:57 CST 2010
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
|
||||
org.eclipse.jdt.core.compiler.compliance=1.4
|
||||
org.eclipse.jdt.core.compiler.source=1.3
|
||||
@@ -0,0 +1,9 @@
|
||||
#Sun Feb 14 15:24:57 CST 2010
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
fullBuildGoals=process-test-resources
|
||||
includeModules=false
|
||||
resolveWorkspaceProjects=true
|
||||
resourceFilterGoals=process-resources resources\:testResources
|
||||
skipCompilerPlugin=true
|
||||
version=1
|
||||
10
ch-12/account-parent/account-captcha/.classpath
Normal file
10
ch-12/account-parent/account-captcha/.classpath
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
|
||||
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
ch-12/account-parent/account-captcha/.project
Normal file
23
ch-12/account-parent/account-captcha/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>account-captcha</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.maven.ide.eclipse.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.maven.ide.eclipse.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,6 @@
|
||||
#Thu Jul 01 16:54:16 CST 2010
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.5
|
||||
@@ -0,0 +1,9 @@
|
||||
#Wed Mar 24 16:30:18 CST 2010
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
fullBuildGoals=process-test-resources
|
||||
includeModules=false
|
||||
resolveWorkspaceProjects=true
|
||||
resourceFilterGoals=process-resources resources\:testResources
|
||||
skipCompilerPlugin=true
|
||||
version=1
|
||||
55
ch-12/account-parent/account-captcha/pom.xml
Normal file
55
ch-12/account-parent/account-captcha/pom.xml
Normal file
@@ -0,0 +1,55 @@
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.juvenxu.mvnbook.account</groupId>
|
||||
<artifactId>account-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>account-captcha</artifactId>
|
||||
<name>Account Captcha</name>
|
||||
|
||||
<properties>
|
||||
<kaptcha.version>2.3</kaptcha.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.code.kaptcha</groupId>
|
||||
<artifactId>kaptcha</artifactId>
|
||||
<version>${kaptcha.version}</version>
|
||||
<classifier>jdk15</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sonatype-forge</id>
|
||||
<name>Sonatype Forge</name>
|
||||
<url>http://repository.sonatype.org/content/groups/forge/</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.juvenxu.mvnbook.account.captcha;
|
||||
|
||||
public class AccountCaptchaException
|
||||
extends Exception
|
||||
{
|
||||
private static final long serialVersionUID = 1339439433313285858L;
|
||||
|
||||
public AccountCaptchaException( String message )
|
||||
{
|
||||
super( message );
|
||||
}
|
||||
|
||||
public AccountCaptchaException( String message, Throwable throwable )
|
||||
{
|
||||
super( message, throwable );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.juvenxu.mvnbook.account.captcha;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface AccountCaptchaService
|
||||
{
|
||||
String generateCaptchaKey()
|
||||
throws AccountCaptchaException;
|
||||
|
||||
byte[] generateCaptchaImage( String captchaKey )
|
||||
throws AccountCaptchaException;
|
||||
|
||||
boolean validateCaptcha( String captchaKey, String captchaValue )
|
||||
throws AccountCaptchaException;
|
||||
|
||||
List<String> getPreDefinedTexts();
|
||||
|
||||
void setPreDefinedTexts( List<String> preDefinedTexts );
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.juvenxu.mvnbook.account.captcha;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import com.google.code.kaptcha.impl.DefaultKaptcha;
|
||||
import com.google.code.kaptcha.util.Config;
|
||||
|
||||
public class AccountCaptchaServiceImpl
|
||||
implements AccountCaptchaService, InitializingBean
|
||||
{
|
||||
private DefaultKaptcha producer;
|
||||
|
||||
private Map<String, String> captchaMap = new HashMap<String, String>();
|
||||
|
||||
private List<String> preDefinedTexts;
|
||||
|
||||
private int textCount = 0;
|
||||
|
||||
public void afterPropertiesSet()
|
||||
throws Exception
|
||||
{
|
||||
producer = new DefaultKaptcha();
|
||||
|
||||
producer.setConfig( new Config( new Properties() ) );
|
||||
}
|
||||
|
||||
public String generateCaptchaKey()
|
||||
{
|
||||
String key = RandomGenerator.getRandomString();
|
||||
|
||||
String value = getCaptchaText();
|
||||
|
||||
captchaMap.put( key, value );
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
public List<String> getPreDefinedTexts()
|
||||
{
|
||||
return preDefinedTexts;
|
||||
}
|
||||
|
||||
public void setPreDefinedTexts( List<String> preDefinedTexts )
|
||||
{
|
||||
this.preDefinedTexts = preDefinedTexts;
|
||||
}
|
||||
|
||||
private String getCaptchaText()
|
||||
{
|
||||
if ( preDefinedTexts != null && !preDefinedTexts.isEmpty() )
|
||||
{
|
||||
String text = preDefinedTexts.get( textCount );
|
||||
|
||||
textCount = ( textCount + 1 ) % preDefinedTexts.size();
|
||||
|
||||
return text;
|
||||
}
|
||||
else
|
||||
{
|
||||
return producer.createText();
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] generateCaptchaImage( String captchaKey )
|
||||
throws AccountCaptchaException
|
||||
{
|
||||
String text = captchaMap.get( captchaKey );
|
||||
|
||||
if ( text == null )
|
||||
{
|
||||
throw new AccountCaptchaException( "Captch key '" + captchaKey + "' not found!" );
|
||||
}
|
||||
|
||||
BufferedImage image = producer.createImage( text );
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
try
|
||||
{
|
||||
ImageIO.write( image, "jpg", out );
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
throw new AccountCaptchaException( "Failed to write captcha stream!", e );
|
||||
}
|
||||
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
public boolean validateCaptcha( String captchaKey, String captchaValue )
|
||||
throws AccountCaptchaException
|
||||
{
|
||||
String text = captchaMap.get( captchaKey );
|
||||
|
||||
if ( text == null )
|
||||
{
|
||||
throw new AccountCaptchaException( "Captch key '" + captchaKey + "' not found!" );
|
||||
}
|
||||
|
||||
if ( text.equals( captchaValue ) )
|
||||
{
|
||||
captchaMap.remove( captchaKey );
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.juvenxu.mvnbook.account.captcha;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class RandomGenerator
|
||||
{
|
||||
private static String range = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
public static synchronized String getRandomString()
|
||||
{
|
||||
Random random = new Random();
|
||||
|
||||
StringBuffer result = new StringBuffer();
|
||||
|
||||
for ( int i = 0; i < 8; i++ )
|
||||
{
|
||||
result.append( range.charAt( random.nextInt( range.length() ) ) );
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<bean id="accountCaptchaService"
|
||||
class="com.juvenxu.mvnbook.account.captcha.AccountCaptchaServiceImpl">
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.juvenxu.mvnbook.account.captcha;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
public class AccountCaptchaServiceTest
|
||||
{
|
||||
private AccountCaptchaService service;
|
||||
|
||||
@Before
|
||||
public void prepare()
|
||||
throws Exception
|
||||
{
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext( "account-captcha.xml" );
|
||||
service = (AccountCaptchaService) ctx.getBean( "accountCaptchaService" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateCaptcha()
|
||||
throws Exception
|
||||
{
|
||||
String captchaKey = service.generateCaptchaKey();
|
||||
assertNotNull( captchaKey );
|
||||
|
||||
byte[] captchaImage = service.generateCaptchaImage( captchaKey );
|
||||
assertTrue( captchaImage.length > 0 );
|
||||
|
||||
File image = new File( "target/" + captchaKey + ".jpg" );
|
||||
OutputStream output = null;
|
||||
try
|
||||
{
|
||||
output = new FileOutputStream( image );
|
||||
output.write( captchaImage );
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ( output != null )
|
||||
{
|
||||
output.close();
|
||||
}
|
||||
}
|
||||
assertTrue( image.exists() && image.length() > 0 );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCaptchaCorrect()
|
||||
throws Exception
|
||||
{
|
||||
List<String> preDefinedTexts = new ArrayList<String>();
|
||||
preDefinedTexts.add( "12345" );
|
||||
preDefinedTexts.add( "abcde" );
|
||||
service.setPreDefinedTexts( preDefinedTexts );
|
||||
|
||||
String captchaKey = service.generateCaptchaKey();
|
||||
service.generateCaptchaImage( captchaKey );
|
||||
assertTrue( service.validateCaptcha( captchaKey, "12345" ) );
|
||||
|
||||
captchaKey = service.generateCaptchaKey();
|
||||
service.generateCaptchaImage( captchaKey );
|
||||
assertTrue( service.validateCaptcha( captchaKey, "abcde" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCaptchaIncorrect()
|
||||
throws Exception
|
||||
{
|
||||
List<String> preDefinedTexts = new ArrayList<String>();
|
||||
preDefinedTexts.add( "12345" );
|
||||
service.setPreDefinedTexts( preDefinedTexts );
|
||||
|
||||
String captchaKey = service.generateCaptchaKey();
|
||||
service.generateCaptchaImage( captchaKey );
|
||||
assertFalse( service.validateCaptcha( captchaKey, "67890" ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.juvenxu.mvnbook.account.captcha;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class RandomGeneratorTest
|
||||
{
|
||||
@Test
|
||||
public void testGetRandomString()
|
||||
throws Exception
|
||||
{
|
||||
Set<String> randoms = new HashSet<String>( 100 );
|
||||
|
||||
for ( int i = 0; i < 100; i++ )
|
||||
{
|
||||
String random = RandomGenerator.getRandomString();
|
||||
|
||||
assertFalse( randoms.contains( random ) );
|
||||
|
||||
randoms.add( random );
|
||||
}
|
||||
}
|
||||
}
|
||||
10
ch-12/account-parent/account-email/.classpath
Normal file
10
ch-12/account-parent/account-email/.classpath
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
|
||||
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
ch-12/account-parent/account-email/.project
Normal file
23
ch-12/account-parent/account-email/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>account-email</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.maven.ide.eclipse.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.maven.ide.eclipse.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,6 @@
|
||||
#Fri Sep 03 14:42:20 CST 2010
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.5
|
||||
@@ -0,0 +1,9 @@
|
||||
#Mon Feb 15 22:20:48 CST 2010
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
fullBuildGoals=process-test-resources
|
||||
includeModules=false
|
||||
resolveWorkspaceProjects=true
|
||||
resourceFilterGoals=process-resources resources\:testResources
|
||||
skipCompilerPlugin=true
|
||||
version=1
|
||||
56
ch-12/account-parent/account-email/pom.xml
Normal file
56
ch-12/account-parent/account-email/pom.xml
Normal file
@@ -0,0 +1,56 @@
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.juvenxu.mvnbook.account</groupId>
|
||||
<artifactId>account-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>account-email</artifactId>
|
||||
<name>Account Email</name>
|
||||
|
||||
<properties>
|
||||
<javax.mail.version>1.4.1</javax.mail.version>
|
||||
<greenmail.version>1.3.1b</greenmail.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.mail</groupId>
|
||||
<artifactId>mail</artifactId>
|
||||
<version>${javax.mail.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.icegreen</groupId>
|
||||
<artifactId>greenmail</artifactId>
|
||||
<version>${greenmail.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.juvenxu.mvnbook.account.email;
|
||||
|
||||
public class AccountEmailException
|
||||
extends Exception
|
||||
{
|
||||
private static final long serialVersionUID = -4817386460334501672L;
|
||||
|
||||
public AccountEmailException( String message )
|
||||
{
|
||||
super( message );
|
||||
}
|
||||
|
||||
public AccountEmailException( String message, Throwable throwable )
|
||||
{
|
||||
super( message, throwable );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.juvenxu.mvnbook.account.email;
|
||||
|
||||
public interface AccountEmailService
|
||||
{
|
||||
void sendMail( String to, String subject, String htmlText )
|
||||
throws AccountEmailException;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.juvenxu.mvnbook.account.email;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||
|
||||
public class AccountEmailServiceImpl
|
||||
implements AccountEmailService
|
||||
{
|
||||
private JavaMailSender javaMailSender;
|
||||
|
||||
private String systemEmail;
|
||||
|
||||
public void sendMail( String to, String subject, String htmlText )
|
||||
throws AccountEmailException
|
||||
{
|
||||
try
|
||||
{
|
||||
MimeMessage msg = javaMailSender.createMimeMessage();
|
||||
MimeMessageHelper msgHelper = new MimeMessageHelper( msg );
|
||||
|
||||
msgHelper.setFrom( systemEmail );
|
||||
msgHelper.setTo( to );
|
||||
msgHelper.setSubject( subject );
|
||||
msgHelper.setText( htmlText, true );
|
||||
|
||||
javaMailSender.send( msg );
|
||||
}
|
||||
catch ( MessagingException e )
|
||||
{
|
||||
throw new AccountEmailException( "Faild to send mail.", e );
|
||||
}
|
||||
}
|
||||
|
||||
public JavaMailSender getJavaMailSender()
|
||||
{
|
||||
return javaMailSender;
|
||||
}
|
||||
|
||||
public void setJavaMailSender( JavaMailSender javaMailSender )
|
||||
{
|
||||
this.javaMailSender = javaMailSender;
|
||||
}
|
||||
|
||||
public String getSystemEmail()
|
||||
{
|
||||
return systemEmail;
|
||||
}
|
||||
|
||||
public void setSystemEmail( String systemEmail )
|
||||
{
|
||||
this.systemEmail = systemEmail;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<bean id="propertyConfigurer"
|
||||
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
|
||||
<property name="location" value="classpath:account-service.properties" />
|
||||
</bean>
|
||||
|
||||
<bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
|
||||
<property name="protocol" value="${email.protocol}" />
|
||||
<property name="host" value="${email.host}" />
|
||||
<property name="port" value="${email.port}" />
|
||||
<property name="username" value="${email.username}" />
|
||||
<property name="password" value="${email.password}" />
|
||||
<property name="javaMailProperties">
|
||||
<props>
|
||||
<prop key="mail.${email.protocol}.auth">${email.auth}</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="accountEmailService"
|
||||
class="com.juvenxu.mvnbook.account.email.AccountEmailServiceImpl">
|
||||
<property name="javaMailSender" ref="javaMailSender" />
|
||||
<property name="systemEmail" value="${email.systemEmail}" />
|
||||
</bean>
|
||||
</beans>
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.juvenxu.mvnbook.account.email;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import javax.mail.Message;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
import com.icegreen.greenmail.util.GreenMail;
|
||||
import com.icegreen.greenmail.util.GreenMailUtil;
|
||||
import com.icegreen.greenmail.util.ServerSetup;
|
||||
|
||||
public class AccountEmailServiceTest
|
||||
{
|
||||
private GreenMail greenMail;
|
||||
|
||||
@Before
|
||||
public void startMailServer()
|
||||
throws Exception
|
||||
{
|
||||
greenMail = new GreenMail( ServerSetup.SMTP );
|
||||
greenMail.setUser( "test@juvenxu.com", "123456" );
|
||||
greenMail.start();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendMail()
|
||||
throws Exception
|
||||
{
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext( "account-email.xml" );
|
||||
AccountEmailService accountEmailService = (AccountEmailService) ctx.getBean( "accountEmailService" );
|
||||
|
||||
String subject = "Test Subject";
|
||||
String htmlText = "<h3>Test</h3>";
|
||||
accountEmailService.sendMail( "test2@juvenxu.com", subject, htmlText );
|
||||
|
||||
greenMail.waitForIncomingEmail( 2000, 1 );
|
||||
|
||||
Message[] msgs = greenMail.getReceivedMessages();
|
||||
assertEquals( 1, msgs.length );
|
||||
assertEquals( "admin@juvenxu.com", msgs[0].getFrom()[0].toString() );
|
||||
assertEquals( subject, msgs[0].getSubject() );
|
||||
assertEquals( htmlText, GreenMailUtil.getBody( msgs[0] ).trim() );
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopMailServer()
|
||||
throws Exception
|
||||
{
|
||||
greenMail.stop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#email.protocol=smtps
|
||||
#email.host=smtp.gmail.com
|
||||
#email.port=465
|
||||
#email.username=juvenshun@gmail.com
|
||||
#email.password=googleh8z5v0
|
||||
#email.auth=true
|
||||
|
||||
email.protocol=smtp
|
||||
email.host=localhost
|
||||
email.port=25
|
||||
email.username=test@juvenxu.com
|
||||
email.password=123456
|
||||
email.auth=true
|
||||
email.systemEmail=admin@juvenxu.com
|
||||
10
ch-12/account-parent/account-persist/.classpath
Normal file
10
ch-12/account-parent/account-persist/.classpath
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
|
||||
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
ch-12/account-parent/account-persist/.project
Normal file
23
ch-12/account-parent/account-persist/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>account-persist</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.maven.ide.eclipse.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.maven.ide.eclipse.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,6 @@
|
||||
#Thu Jul 01 16:54:16 CST 2010
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.5
|
||||
@@ -0,0 +1,9 @@
|
||||
#Mon Feb 15 22:20:48 CST 2010
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
fullBuildGoals=process-test-resources
|
||||
includeModules=false
|
||||
resolveWorkspaceProjects=true
|
||||
resourceFilterGoals=process-resources resources\:testResources
|
||||
skipCompilerPlugin=true
|
||||
version=1
|
||||
50
ch-12/account-parent/account-persist/pom.xml
Normal file
50
ch-12/account-parent/account-persist/pom.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.juvenxu.mvnbook.account</groupId>
|
||||
<artifactId>account-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>account-persist</artifactId>
|
||||
<name>Account Persist</name>
|
||||
|
||||
<properties>
|
||||
<dom4j.version>1.6.1</dom4j.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>${dom4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>src/test/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</testResource>
|
||||
</testResources>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.juvenxu.mvnbook.account.persist;
|
||||
|
||||
public class Account
|
||||
{
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String email;
|
||||
|
||||
private String password;
|
||||
|
||||
private boolean activated;
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId( String id )
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName( String name )
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getEmail()
|
||||
{
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail( String email )
|
||||
{
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPassword()
|
||||
{
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword( String password )
|
||||
{
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public boolean isActivated()
|
||||
{
|
||||
return activated;
|
||||
}
|
||||
|
||||
public void setActivated( boolean activated )
|
||||
{
|
||||
this.activated = activated;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.juvenxu.mvnbook.account.persist;
|
||||
|
||||
public class AccountPersistException
|
||||
extends Exception
|
||||
{
|
||||
private static final long serialVersionUID = -8334988626147289624L;
|
||||
|
||||
public AccountPersistException( String message )
|
||||
{
|
||||
super( message );
|
||||
}
|
||||
|
||||
public AccountPersistException( String message, Throwable throwable )
|
||||
{
|
||||
super( message, throwable );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.juvenxu.mvnbook.account.persist;
|
||||
|
||||
public interface AccountPersistService
|
||||
{
|
||||
Account createAccount( Account account )
|
||||
throws AccountPersistException;
|
||||
|
||||
Account readAccount( String id )
|
||||
throws AccountPersistException;
|
||||
|
||||
Account updateAccount( Account account )
|
||||
throws AccountPersistException;
|
||||
|
||||
void deleteAccount( String id )
|
||||
throws AccountPersistException;
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
package com.juvenxu.mvnbook.account.persist;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.DocumentFactory;
|
||||
import org.dom4j.Element;
|
||||
import org.dom4j.io.OutputFormat;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.dom4j.io.XMLWriter;
|
||||
|
||||
public class AccountPersistServiceImpl
|
||||
implements AccountPersistService
|
||||
{
|
||||
private static final String ELEMENT_ROOT = "account-persist";
|
||||
private static final String ELEMENT_ACCOUNTS = "accounts";
|
||||
private static final String ELEMENT_ACCOUNT = "account";
|
||||
private static final String ELEMENT_ACCOUNT_ID = "id";
|
||||
private static final String ELEMENT_ACCOUNT_NAME = "name";
|
||||
private static final String ELEMENT_ACCOUNT_EMAIL = "email";
|
||||
private static final String ELEMENT_ACCOUNT_PASSWORD = "password";
|
||||
private static final String ELEMENT_ACCOUNT_ACTIVATED = "activated";
|
||||
|
||||
private String file;
|
||||
|
||||
private SAXReader reader = new SAXReader();
|
||||
|
||||
public String getFile()
|
||||
{
|
||||
return file;
|
||||
}
|
||||
|
||||
public void setFile( String file )
|
||||
{
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public Account createAccount( Account account )
|
||||
throws AccountPersistException
|
||||
{
|
||||
Document doc = readDocument();
|
||||
|
||||
Element accountsEle = doc.getRootElement().element(ELEMENT_ACCOUNTS);
|
||||
|
||||
accountsEle.add( buildAccountElement( account ) );
|
||||
|
||||
writeDocument( doc );
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void deleteAccount( String id )
|
||||
throws AccountPersistException
|
||||
{
|
||||
Document doc = readDocument();
|
||||
|
||||
Element accountsEle = doc.getRootElement().element( ELEMENT_ACCOUNTS );
|
||||
|
||||
for ( Element accountEle : (List<Element>) accountsEle.elements() )
|
||||
{
|
||||
if ( accountEle.elementText( ELEMENT_ACCOUNT_ID ).equals( id ) )
|
||||
{
|
||||
accountEle.detach();
|
||||
|
||||
writeDocument( doc );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Account readAccount( String id )
|
||||
throws AccountPersistException
|
||||
{
|
||||
Document doc = readDocument();
|
||||
|
||||
Element accountsEle = doc.getRootElement().element( ELEMENT_ACCOUNTS );
|
||||
|
||||
for ( Element accountEle : (List<Element>) accountsEle.elements() )
|
||||
{
|
||||
if ( accountEle.elementText( ELEMENT_ACCOUNT_ID ).equals( id ) )
|
||||
{
|
||||
return buildAccount( accountEle );
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Account updateAccount( Account account )
|
||||
throws AccountPersistException
|
||||
{
|
||||
if ( readAccount( account.getId() ) != null )
|
||||
{
|
||||
deleteAccount( account.getId() );
|
||||
|
||||
return createAccount ( account );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Account buildAccount( Element element )
|
||||
{
|
||||
Account account = new Account();
|
||||
|
||||
account.setId( element.elementText( ELEMENT_ACCOUNT_ID ) );
|
||||
account.setName( element.elementText( ELEMENT_ACCOUNT_NAME ) );
|
||||
account.setEmail( element.elementText( ELEMENT_ACCOUNT_EMAIL ) );
|
||||
account.setPassword( element.elementText( ELEMENT_ACCOUNT_PASSWORD ) );
|
||||
account.setActivated( ( "true".equals( element.elementText( ELEMENT_ACCOUNT_ACTIVATED ) ) ? true : false ) );
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
private Element buildAccountElement( Account account )
|
||||
{
|
||||
Element element = DocumentFactory.getInstance().createElement( ELEMENT_ACCOUNT );
|
||||
|
||||
element.addElement( ELEMENT_ACCOUNT_ID ).setText( account.getId() );
|
||||
element.addElement( ELEMENT_ACCOUNT_NAME ).setText( account.getName() );
|
||||
element.addElement( ELEMENT_ACCOUNT_EMAIL ).setText( account.getEmail() );
|
||||
element.addElement( ELEMENT_ACCOUNT_PASSWORD ).setText( account.getPassword() );
|
||||
element.addElement( ELEMENT_ACCOUNT_ACTIVATED ).setText( account.isActivated() ? "true" : "false" );
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
private Document readDocument()
|
||||
throws AccountPersistException
|
||||
{
|
||||
File dataFile = new File( file );
|
||||
|
||||
if( !dataFile.exists() )
|
||||
{
|
||||
dataFile.getParentFile().mkdirs();
|
||||
|
||||
Document doc = DocumentFactory.getInstance().createDocument();
|
||||
|
||||
Element rootEle = doc.addElement( ELEMENT_ROOT );
|
||||
|
||||
rootEle.addElement( ELEMENT_ACCOUNTS );
|
||||
|
||||
writeDocument( doc );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return reader.read( new File( file ) );
|
||||
}
|
||||
catch ( DocumentException e )
|
||||
{
|
||||
throw new AccountPersistException( "Unable to read persist data xml", e );
|
||||
}
|
||||
}
|
||||
|
||||
private void writeDocument( Document doc )
|
||||
throws AccountPersistException
|
||||
{
|
||||
Writer out = null;
|
||||
|
||||
try
|
||||
{
|
||||
out = new OutputStreamWriter( new FileOutputStream( file ), "utf-8" );
|
||||
|
||||
XMLWriter writer = new XMLWriter( out, OutputFormat.createPrettyPrint() );
|
||||
|
||||
writer.write( doc );
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
throw new AccountPersistException( "Unable to write persist data xml", e );
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( out != null)
|
||||
{
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
throw new AccountPersistException( "Unable to close persist data xml writer", e );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<bean id="propertyConfigurer"
|
||||
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
|
||||
<property name="location" value="classpath:account-service.properties" />
|
||||
</bean>
|
||||
|
||||
<bean id="accountPersistService"
|
||||
class="com.juvenxu.mvnbook.account.persist.AccountPersistServiceImpl">
|
||||
<property name="file" value="${persist.file}" />
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.juvenxu.mvnbook.account.persist;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
public class AccountPersistServiceTest
|
||||
{
|
||||
private AccountPersistService service;
|
||||
|
||||
@Before
|
||||
public void prepare()
|
||||
throws Exception
|
||||
{
|
||||
File persistDataFile = new File ( "target/test-classes/persist-data.xml" );
|
||||
|
||||
if ( persistDataFile.exists() )
|
||||
{
|
||||
persistDataFile.delete();
|
||||
}
|
||||
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext( "account-persist.xml" );
|
||||
|
||||
service = (AccountPersistService) ctx.getBean( "accountPersistService" );
|
||||
|
||||
Account account = new Account();
|
||||
account.setId("juven");
|
||||
account.setName("Juven Xu");
|
||||
account.setEmail("juven@changeme.com");
|
||||
account.setPassword("this_should_be_encrypted");
|
||||
account.setActivated(true);
|
||||
|
||||
service.createAccount(account);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadAccount()
|
||||
throws Exception
|
||||
{
|
||||
Account account = service.readAccount( "juven" );
|
||||
|
||||
assertNotNull( account );
|
||||
assertEquals( "juven", account.getId() );
|
||||
assertEquals( "Juven Xu", account.getName() );
|
||||
assertEquals( "juven@changeme.com", account.getEmail() );
|
||||
assertEquals( "this_should_be_encrypted", account.getPassword() );
|
||||
assertTrue( account.isActivated() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteAccount()
|
||||
throws Exception
|
||||
{
|
||||
assertNotNull( service.readAccount( "juven" ) );
|
||||
service.deleteAccount( "juven" );
|
||||
assertNull( service.readAccount( "juven" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAccount()
|
||||
throws Exception
|
||||
{
|
||||
assertNull( service.readAccount( "mike" ) );
|
||||
|
||||
Account account = new Account();
|
||||
account.setId("mike");
|
||||
account.setName("Mike");
|
||||
account.setEmail("mike@changeme.com");
|
||||
account.setPassword("this_should_be_encrypted");
|
||||
account.setActivated(true);
|
||||
|
||||
service.createAccount(account);
|
||||
|
||||
assertNotNull( service.readAccount( "mike" ));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAccount()
|
||||
throws Exception
|
||||
{
|
||||
Account account = service.readAccount( "juven" );
|
||||
|
||||
account.setName("Juven Xu 1");
|
||||
account.setEmail("juven1@changeme.com");
|
||||
account.setPassword("this_still_should_be_encrypted");
|
||||
account.setActivated(false);
|
||||
|
||||
service.updateAccount( account );
|
||||
|
||||
account = service.readAccount( "juven" );
|
||||
|
||||
assertEquals( "Juven Xu 1", account.getName() );
|
||||
assertEquals( "juven1@changeme.com", account.getEmail() );
|
||||
assertEquals( "this_still_should_be_encrypted", account.getPassword() );
|
||||
assertFalse( account.isActivated() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
persist.file=${project.build.testOutputDirectory}/persist-data.xml
|
||||
10
ch-12/account-parent/account-service/.classpath
Normal file
10
ch-12/account-parent/account-service/.classpath
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
|
||||
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
ch-12/account-parent/account-service/.project
Normal file
23
ch-12/account-parent/account-service/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>account-service</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.maven.ide.eclipse.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.maven.ide.eclipse.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,6 @@
|
||||
#Thu Jul 01 16:54:17 CST 2010
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.5
|
||||
@@ -0,0 +1,9 @@
|
||||
#Sun May 09 19:38:56 CST 2010
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
fullBuildGoals=process-test-resources
|
||||
includeModules=false
|
||||
resolveWorkspaceProjects=true
|
||||
resourceFilterGoals=process-resources resources\:testResources
|
||||
skipCompilerPlugin=true
|
||||
version=1
|
||||
53
ch-12/account-parent/account-service/pom.xml
Normal file
53
ch-12/account-parent/account-service/pom.xml
Normal file
@@ -0,0 +1,53 @@
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.juvenxu.mvnbook.account</groupId>
|
||||
<artifactId>account-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>account-service</artifactId>
|
||||
<name>Account Service</name>
|
||||
|
||||
<properties>
|
||||
<greenmail.version>1.3.1b</greenmail.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>account-email</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>account-persist</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>account-captcha</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.icegreen</groupId>
|
||||
<artifactId>greenmail</artifactId>
|
||||
<version>${greenmail.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>src/test/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</testResource>
|
||||
</testResources>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.juvenxu.mvnbook.account.service;
|
||||
|
||||
public interface AccountService
|
||||
{
|
||||
String generateCaptchaKey()
|
||||
throws AccountServiceException;
|
||||
|
||||
byte[] generateCaptchaImage( String captchaKey )
|
||||
throws AccountServiceException;
|
||||
|
||||
void signUp( SignUpRequest signUpRequest )
|
||||
throws AccountServiceException;
|
||||
|
||||
void activate( String activationNumber )
|
||||
throws AccountServiceException;
|
||||
|
||||
void login( String id, String password )
|
||||
throws AccountServiceException;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.juvenxu.mvnbook.account.service;
|
||||
|
||||
public class AccountServiceException
|
||||
extends Exception
|
||||
{
|
||||
private static final long serialVersionUID = 949282286716874926L;
|
||||
|
||||
public AccountServiceException( String message )
|
||||
{
|
||||
super( message );
|
||||
}
|
||||
|
||||
public AccountServiceException( String message, Throwable throwable )
|
||||
{
|
||||
super( message, throwable );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package com.juvenxu.mvnbook.account.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.juvenxu.mvnbook.account.captcha.AccountCaptchaException;
|
||||
import com.juvenxu.mvnbook.account.captcha.AccountCaptchaService;
|
||||
import com.juvenxu.mvnbook.account.captcha.RandomGenerator;
|
||||
import com.juvenxu.mvnbook.account.email.AccountEmailException;
|
||||
import com.juvenxu.mvnbook.account.email.AccountEmailService;
|
||||
import com.juvenxu.mvnbook.account.persist.Account;
|
||||
import com.juvenxu.mvnbook.account.persist.AccountPersistException;
|
||||
import com.juvenxu.mvnbook.account.persist.AccountPersistService;
|
||||
|
||||
public class AccountServiceImpl
|
||||
implements AccountService
|
||||
{
|
||||
private Map<String, String> activationMap = new HashMap<String, String>();
|
||||
|
||||
private AccountPersistService accountPersistService;
|
||||
|
||||
private AccountEmailService accountEmailService;
|
||||
|
||||
private AccountCaptchaService accountCaptchaService;
|
||||
|
||||
public AccountPersistService getAccountPersistService()
|
||||
{
|
||||
return accountPersistService;
|
||||
}
|
||||
|
||||
public void setAccountPersistService( AccountPersistService accountPersistService )
|
||||
{
|
||||
this.accountPersistService = accountPersistService;
|
||||
}
|
||||
|
||||
public AccountEmailService getAccountEmailService()
|
||||
{
|
||||
return accountEmailService;
|
||||
}
|
||||
|
||||
public void setAccountEmailService( AccountEmailService accountEmailService )
|
||||
{
|
||||
this.accountEmailService = accountEmailService;
|
||||
}
|
||||
|
||||
public AccountCaptchaService getAccountCaptchaService()
|
||||
{
|
||||
return accountCaptchaService;
|
||||
}
|
||||
|
||||
public void setAccountCaptchaService( AccountCaptchaService accountCaptchaService )
|
||||
{
|
||||
this.accountCaptchaService = accountCaptchaService;
|
||||
}
|
||||
|
||||
public byte[] generateCaptchaImage( String captchaKey )
|
||||
throws AccountServiceException
|
||||
{
|
||||
try
|
||||
{
|
||||
return accountCaptchaService.generateCaptchaImage( captchaKey );
|
||||
}
|
||||
catch ( AccountCaptchaException e )
|
||||
{
|
||||
throw new AccountServiceException( "Unable to generate Captcha Image.", e );
|
||||
}
|
||||
}
|
||||
|
||||
public String generateCaptchaKey()
|
||||
throws AccountServiceException
|
||||
{
|
||||
try
|
||||
{
|
||||
return accountCaptchaService.generateCaptchaKey();
|
||||
}
|
||||
catch ( AccountCaptchaException e )
|
||||
{
|
||||
throw new AccountServiceException( "Unable to generate Captcha key.", e );
|
||||
}
|
||||
}
|
||||
|
||||
public void signUp( SignUpRequest signUpRequest )
|
||||
throws AccountServiceException
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( !signUpRequest.getPassword().equals( signUpRequest.getConfirmPassword() ) )
|
||||
{
|
||||
throw new AccountServiceException( "2 passwords do not match." );
|
||||
}
|
||||
|
||||
if ( !accountCaptchaService
|
||||
.validateCaptcha( signUpRequest.getCaptchaKey(), signUpRequest.getCaptchaValue() ) )
|
||||
{
|
||||
|
||||
throw new AccountServiceException( "Incorrect Captcha." );
|
||||
}
|
||||
|
||||
Account account = new Account();
|
||||
account.setId( signUpRequest.getId() );
|
||||
account.setEmail( signUpRequest.getEmail() );
|
||||
account.setName( signUpRequest.getName() );
|
||||
account.setPassword( signUpRequest.getPassword() );
|
||||
account.setActivated( false );
|
||||
|
||||
accountPersistService.createAccount( account );
|
||||
|
||||
String activationId = RandomGenerator.getRandomString();
|
||||
|
||||
activationMap.put( activationId, account.getId() );
|
||||
|
||||
String link = signUpRequest.getActivateServiceUrl().endsWith( "/" ) ? signUpRequest.getActivateServiceUrl()
|
||||
+ activationId : signUpRequest.getActivateServiceUrl() + "?key=" + activationId;
|
||||
|
||||
accountEmailService.sendMail( account.getEmail(), "Please Activate Your Account", link );
|
||||
}
|
||||
catch ( AccountCaptchaException e )
|
||||
{
|
||||
throw new AccountServiceException( "Unable to validate captcha.", e );
|
||||
}
|
||||
catch ( AccountPersistException e )
|
||||
{
|
||||
throw new AccountServiceException( "Unable to create account.", e );
|
||||
}
|
||||
catch ( AccountEmailException e )
|
||||
{
|
||||
throw new AccountServiceException( "Unable to send actiavtion mail.", e );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void activate( String activationId )
|
||||
throws AccountServiceException
|
||||
{
|
||||
String accountId = activationMap.get( activationId );
|
||||
|
||||
if ( accountId == null )
|
||||
{
|
||||
throw new AccountServiceException( "Invalid account activation ID." );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Account account = accountPersistService.readAccount( accountId );
|
||||
account.setActivated( true );
|
||||
accountPersistService.updateAccount( account );
|
||||
}
|
||||
catch ( AccountPersistException e )
|
||||
{
|
||||
throw new AccountServiceException( "Unable to activate account." );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void login( String id, String password )
|
||||
throws AccountServiceException
|
||||
{
|
||||
try
|
||||
{
|
||||
Account account = accountPersistService.readAccount( id );
|
||||
|
||||
if ( account == null )
|
||||
{
|
||||
throw new AccountServiceException( "Account does not exist." );
|
||||
}
|
||||
|
||||
if ( !account.isActivated() )
|
||||
{
|
||||
throw new AccountServiceException( "Account is disabled." );
|
||||
}
|
||||
|
||||
if ( !account.getPassword().equals( password ) )
|
||||
{
|
||||
throw new AccountServiceException( "Incorrect password." );
|
||||
}
|
||||
}
|
||||
catch ( AccountPersistException e )
|
||||
{
|
||||
throw new AccountServiceException( "Unable to log in.", e );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.juvenxu.mvnbook.account.service;
|
||||
|
||||
public class SignUpRequest
|
||||
{
|
||||
private String id;
|
||||
|
||||
private String email;
|
||||
|
||||
private String name;
|
||||
|
||||
private String password;
|
||||
|
||||
private String confirmPassword;
|
||||
|
||||
private String captchaKey;
|
||||
|
||||
private String captchaValue;
|
||||
|
||||
private String activateServiceUrl;
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId( String id )
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getEmail()
|
||||
{
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail( String email )
|
||||
{
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName( String name )
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPassword()
|
||||
{
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword( String password )
|
||||
{
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getConfirmPassword()
|
||||
{
|
||||
return confirmPassword;
|
||||
}
|
||||
|
||||
public void setConfirmPassword( String confirmPassword )
|
||||
{
|
||||
this.confirmPassword = confirmPassword;
|
||||
}
|
||||
|
||||
public String getCaptchaKey()
|
||||
{
|
||||
return captchaKey;
|
||||
}
|
||||
|
||||
public void setCaptchaKey( String captchaKey )
|
||||
{
|
||||
this.captchaKey = captchaKey;
|
||||
}
|
||||
|
||||
public String getCaptchaValue()
|
||||
{
|
||||
return captchaValue;
|
||||
}
|
||||
|
||||
public void setCaptchaValue( String captchaValue )
|
||||
{
|
||||
this.captchaValue = captchaValue;
|
||||
}
|
||||
|
||||
public String getActivateServiceUrl()
|
||||
{
|
||||
return activateServiceUrl;
|
||||
}
|
||||
|
||||
public void setActivateServiceUrl( String activateServiceUrl )
|
||||
{
|
||||
this.activateServiceUrl = activateServiceUrl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<bean id="accountService" class="com.juvenxu.mvnbook.account.service.AccountServiceImpl">
|
||||
<property name="accountPersistService" ref="accountPersistService" />
|
||||
<property name="accountEmailService" ref="accountEmailService" />
|
||||
<property name="accountCaptchaService" ref="accountCaptchaService" />
|
||||
</bean>
|
||||
</beans>
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.juvenxu.mvnbook.account.service;
|
||||
|
||||
import static junit.framework.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.mail.Message;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
import com.icegreen.greenmail.util.GreenMail;
|
||||
import com.icegreen.greenmail.util.GreenMailUtil;
|
||||
import com.icegreen.greenmail.util.ServerSetup;
|
||||
import com.juvenxu.mvnbook.account.captcha.AccountCaptchaService;
|
||||
|
||||
public class AccountServiceTest
|
||||
{
|
||||
private GreenMail greenMail;
|
||||
|
||||
private AccountService accountService;
|
||||
|
||||
@Before
|
||||
public void prepare()
|
||||
throws Exception
|
||||
{
|
||||
String[] springConfigFiles = {
|
||||
"account-email.xml",
|
||||
"account-persist.xml",
|
||||
"account-captcha.xml",
|
||||
"account-service.xml" };
|
||||
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext( springConfigFiles );
|
||||
|
||||
AccountCaptchaService accountCaptchaService = (AccountCaptchaService) ctx.getBean( "accountCaptchaService" );
|
||||
|
||||
List<String> preDefinedTexts = new ArrayList<String>();
|
||||
preDefinedTexts.add( "12345" );
|
||||
preDefinedTexts.add( "abcde" );
|
||||
accountCaptchaService.setPreDefinedTexts( preDefinedTexts );
|
||||
|
||||
accountService = (AccountService) ctx.getBean( "accountService" );
|
||||
|
||||
greenMail = new GreenMail( ServerSetup.SMTP );
|
||||
greenMail.setUser( "test@juvenxu.com", "123456" );
|
||||
greenMail.start();
|
||||
|
||||
File persistDataFile = new File( "target/test-classes/persist-data.xml" );
|
||||
if ( persistDataFile.exists() )
|
||||
{
|
||||
persistDataFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccountService()
|
||||
throws Exception
|
||||
{
|
||||
// 1. Get captcha
|
||||
String captchaKey = accountService.generateCaptchaKey();
|
||||
accountService.generateCaptchaImage( captchaKey );
|
||||
String captchaValue = "12345";
|
||||
|
||||
// 2. Submit sign up Request
|
||||
SignUpRequest signUpRequest = new SignUpRequest();
|
||||
signUpRequest.setCaptchaKey( captchaKey );
|
||||
signUpRequest.setCaptchaValue( captchaValue );
|
||||
signUpRequest.setId( "juven" );
|
||||
signUpRequest.setEmail( "test@juvenxu.com" );
|
||||
signUpRequest.setName( "Juven Xu" );
|
||||
signUpRequest.setPassword( "admin123" );
|
||||
signUpRequest.setConfirmPassword( "admin123" );
|
||||
signUpRequest.setActivateServiceUrl( "http://localhost:8080/account/activate" );
|
||||
accountService.signUp( signUpRequest );
|
||||
|
||||
// 3. Read activation link
|
||||
greenMail.waitForIncomingEmail( 2000, 1 );
|
||||
Message[] msgs = greenMail.getReceivedMessages();
|
||||
assertEquals( 1, msgs.length );
|
||||
assertEquals( "Please Activate Your Account", msgs[0].getSubject() );
|
||||
String activationLink = GreenMailUtil.getBody( msgs[0] ).trim();
|
||||
|
||||
// 3a. Try login but not activated
|
||||
try
|
||||
{
|
||||
accountService.login( "juven", "admin123" );
|
||||
fail( "Disabled account shouldn't be able to log in." );
|
||||
}
|
||||
catch ( AccountServiceException e )
|
||||
{
|
||||
}
|
||||
|
||||
// 4. Activate account
|
||||
String activationCode = activationLink.substring( activationLink.lastIndexOf( "=" ) + 1 );
|
||||
accountService.activate( activationCode );
|
||||
|
||||
// 5. Login with correct id and password
|
||||
accountService.login( "juven", "admin123" );
|
||||
|
||||
// 5a. Login with incorrect password
|
||||
try
|
||||
{
|
||||
accountService.login( "juven", "admin456" );
|
||||
fail( "Password is incorrect, shouldn't be able to login." );
|
||||
}
|
||||
catch ( AccountServiceException e )
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopMailServer()
|
||||
throws Exception
|
||||
{
|
||||
greenMail.stop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
email.protocol=smtp
|
||||
email.host=localhost
|
||||
email.port=25
|
||||
email.username=test@juvenxu.com
|
||||
email.password=123456
|
||||
email.auth=true
|
||||
email.systemEmail=admin@juvenxu.com
|
||||
|
||||
persist.file=${project.build.testOutputDirectory}/persist-data.xml
|
||||
8
ch-12/account-parent/account-web/.classpath
Normal file
8
ch-12/account-parent/account-web/.classpath
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
|
||||
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
ch-12/account-parent/account-web/.project
Normal file
23
ch-12/account-parent/account-web/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>account-web</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.maven.ide.eclipse.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.maven.ide.eclipse.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,6 @@
|
||||
#Thu Jul 01 16:54:17 CST 2010
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.5
|
||||
@@ -0,0 +1,9 @@
|
||||
#Sun May 09 19:55:57 CST 2010
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
fullBuildGoals=process-test-resources
|
||||
includeModules=false
|
||||
resolveWorkspaceProjects=true
|
||||
resourceFilterGoals=process-resources resources\:testResources
|
||||
skipCompilerPlugin=true
|
||||
version=1
|
||||
63
ch-12/account-parent/account-web/pom.xml
Normal file
63
ch-12/account-parent/account-web/pom.xml
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0"?>
|
||||
<project
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.juvenxu.mvnbook.account</groupId>
|
||||
<artifactId>account-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>account-web</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>Account Web</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>account-service</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet.jsp</groupId>
|
||||
<artifactId>jsp-api</artifactId>
|
||||
<version>2.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
<version>7.1.0.RC1</version>
|
||||
<configuration>
|
||||
<scanIntervalSeconds>10</scanIntervalSeconds>
|
||||
<webAppConfig>
|
||||
<contextPath>/account</contextPath>
|
||||
</webAppConfig>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.juvenxu.mvnbook.account.web;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
import com.juvenxu.mvnbook.account.service.AccountService;
|
||||
import com.juvenxu.mvnbook.account.service.AccountServiceException;
|
||||
|
||||
public class ActivateServlet
|
||||
extends HttpServlet
|
||||
{
|
||||
private static final long serialVersionUID = 3668445055149826106L;
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
throws ServletException
|
||||
{
|
||||
super.init();
|
||||
context = WebApplicationContextUtils.getWebApplicationContext( getServletContext() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet( HttpServletRequest req, HttpServletResponse resp )
|
||||
throws ServletException,
|
||||
IOException
|
||||
{
|
||||
String key = req.getParameter( "key" );
|
||||
|
||||
if ( key == null || key.length() == 0 )
|
||||
{
|
||||
resp.sendError( 400, "No activation key provided." );
|
||||
return;
|
||||
}
|
||||
|
||||
AccountService service = (AccountService) context.getBean( "accountService" );
|
||||
|
||||
try
|
||||
{
|
||||
service.activate( key );
|
||||
resp.getWriter().write( "Account is activated, now you can login." );
|
||||
}
|
||||
catch ( AccountServiceException e )
|
||||
{
|
||||
resp.sendError( 400, "Unable to activate account" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.juvenxu.mvnbook.account.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
import com.juvenxu.mvnbook.account.service.AccountService;
|
||||
import com.juvenxu.mvnbook.account.service.AccountServiceException;
|
||||
|
||||
public class CaptchaImageServlet
|
||||
extends HttpServlet
|
||||
{
|
||||
private ApplicationContext context;
|
||||
|
||||
private static final long serialVersionUID = 5274323889605521606L;
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
throws ServletException
|
||||
{
|
||||
super.init();
|
||||
context = WebApplicationContextUtils.getWebApplicationContext( getServletContext() );
|
||||
}
|
||||
|
||||
public void doGet( HttpServletRequest request, HttpServletResponse response )
|
||||
throws ServletException,
|
||||
IOException
|
||||
{
|
||||
String key = request.getParameter( "key" );
|
||||
|
||||
if ( key == null || key.length() == 0 )
|
||||
{
|
||||
response.sendError( 400, "No Captcha Key Found" );
|
||||
}
|
||||
else
|
||||
{
|
||||
AccountService service = (AccountService) context.getBean( "accountService" );
|
||||
|
||||
try
|
||||
{
|
||||
response.setContentType( "image/jpeg" );
|
||||
OutputStream out = response.getOutputStream();
|
||||
out.write( service.generateCaptchaImage( key ) );
|
||||
out.close();
|
||||
}
|
||||
catch ( AccountServiceException e )
|
||||
{
|
||||
response.sendError( 400, e.getMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.juvenxu.mvnbook.account.web;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
import com.juvenxu.mvnbook.account.service.AccountService;
|
||||
import com.juvenxu.mvnbook.account.service.AccountServiceException;
|
||||
|
||||
public class LoginServlet
|
||||
extends HttpServlet
|
||||
{
|
||||
private static final long serialVersionUID = 929160785365121624L;
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
throws ServletException
|
||||
{
|
||||
super.init();
|
||||
context = WebApplicationContextUtils.getWebApplicationContext( getServletContext() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost( HttpServletRequest req, HttpServletResponse resp )
|
||||
throws ServletException,
|
||||
IOException
|
||||
{
|
||||
String id = req.getParameter( "id" );
|
||||
String password = req.getParameter( "password" );
|
||||
|
||||
if ( id == null || id.length() == 0 || password == null || password.length() == 0 )
|
||||
{
|
||||
resp.sendError( 400, "incomplete parameter" );
|
||||
return;
|
||||
}
|
||||
|
||||
AccountService service = (AccountService) context.getBean( "accountService" );
|
||||
|
||||
try
|
||||
{
|
||||
service.login( id, password );
|
||||
resp.getWriter().print( "Login Successful!" );
|
||||
}
|
||||
catch ( AccountServiceException e )
|
||||
{
|
||||
resp.sendError( 400, e.getMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.juvenxu.mvnbook.account.web;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
import com.juvenxu.mvnbook.account.service.AccountService;
|
||||
import com.juvenxu.mvnbook.account.service.AccountServiceException;
|
||||
import com.juvenxu.mvnbook.account.service.SignUpRequest;
|
||||
|
||||
public class SignUpServlet
|
||||
extends HttpServlet
|
||||
{
|
||||
private static final long serialVersionUID = 4784742296013868199L;
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
throws ServletException
|
||||
{
|
||||
super.init();
|
||||
context = WebApplicationContextUtils.getWebApplicationContext( getServletContext() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost( HttpServletRequest req, HttpServletResponse resp )
|
||||
throws ServletException,
|
||||
IOException
|
||||
{
|
||||
String id = req.getParameter( "id" );
|
||||
String email = req.getParameter( "email" );
|
||||
String name = req.getParameter( "name" );
|
||||
String password = req.getParameter( "password" );
|
||||
String confirmPassword = req.getParameter( "confirm_password" );
|
||||
String captchaKey = req.getParameter( "captcha_key" );
|
||||
String captchaValue = req.getParameter( "captcha_value" );
|
||||
|
||||
if ( id == null || id.length() == 0 || email == null || email.length() == 0 || name == null
|
||||
|| name.length() == 0 || password == null || password.length() == 0 || confirmPassword == null
|
||||
|| confirmPassword.length() == 0 || captchaKey == null || captchaKey.length() == 0 || captchaValue == null
|
||||
|| captchaValue.length() == 0 )
|
||||
{
|
||||
resp.sendError( 400, "Parameter Incomplete." );
|
||||
return;
|
||||
}
|
||||
|
||||
AccountService service = (AccountService) context.getBean( "accountService" );
|
||||
|
||||
SignUpRequest request = new SignUpRequest();
|
||||
|
||||
request.setId( id );
|
||||
request.setEmail( email );
|
||||
request.setName( name );
|
||||
request.setPassword( password );
|
||||
request.setConfirmPassword( confirmPassword );
|
||||
request.setCaptchaKey( captchaKey );
|
||||
request.setCaptchaValue( captchaValue );
|
||||
|
||||
request.setActivateServiceUrl( getServletContext().getRealPath( "/" ) + "activate" );
|
||||
|
||||
try
|
||||
{
|
||||
service.signUp( request );
|
||||
resp.getWriter().print( "Account is created, please check your mail box for activation link." );
|
||||
}
|
||||
catch ( AccountServiceException e )
|
||||
{
|
||||
resp.sendError( 400, e.getMessage() );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user