POP3クライアントをSocketとJavaMailで作る その2
はじめに
その1で別々だったSocket版とJavaMail版のプログラムを一つにまとめてみた.
ユースケース図・クラス図・シーケンス図
プログラムが結構でかくなったので,UMLで図など描いた.
ソース
Socket版とJavaMail版で異なるのはMailserverBySocket.javaとMailserverByJavaMail.javaのみである.
//Mailserver.java public abstract class Mailserver extends java.util.Observable{ protected String name; public Mailserver(String name){ this.name=name; } public void execute() throws Exception{ setChanged(); notifyObservers(); } public abstract void connect(User user) throws Exception; public abstract void close() throws Exception; public abstract int getMessageCount() throws Exception; public abstract Object getMessage(int messageNumber) throws Exception; } //end MailserverBySocket.java import java.net.Socket; import java.io.*; public class MailserverBySocket extends Mailserver{ private Socket socket; private BufferedReader reader; private BufferedWriter writer; public MailserverBySocket(String name){ super(name); } public void connect(User user) throws Exception{ socket=new Socket(name,110); reader=new BufferedReader(new InputStreamReader(socket.getInputStream())); writer=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); if(isReady()&&isReady("USER "+user.getName())&&isReady("PASS "+user.getPassword())){ //メールサーバにログインできれば何もしない } else{ socket.close(); } } public void close() throws Exception{ if(isReady("quit")){ socket.close(); } } public int getMessageCount() throws Exception{ return isReady("list")? Integer.parseInt(getMessageOrCount().toString()): 0; } public Object getMessage(int messageNumber) throws Exception{ return isReady("retr "+messageNumber)? getMessageOrCount(): "NG"; } private boolean isReady() throws IOException{ final boolean OK=true; final boolean NG=!OK; return reader.readLine().matches("^\\+OK.*$")? OK: NG; } private boolean isReady(String command) throws IOException{ final String end="\r\n"; writer.write(command+end); writer.flush(); return isReady(); } private Object getMessageOrCount() throws Exception{ StringBuffer message=new StringBuffer(); while(true){ String s=reader.readLine(); if(s.equals(".")){ if(message.length()>0){ message.deleteCharAt(message.length()-1); } break; } else{ message.append(s+"\n"); } } if(message.toString().matches("\\d+ \\d+")){ message=new StringBuffer(message.toString().split(" ")[0]); } return message; } } //end //MailserverByJavaMail import java.io.*; import java.util.Properties; import javax.mail.*; import javax.mail.internet.*; public class MailserverByJavaMail extends Mailserver{ private Store store; private Folder folder; public MailserverByJavaMail(String name){ super(name); } public void connect(final User user) throws Exception{ //userをfinalにしないとAuthenticatorの無名クラスへインスタンスを渡せない Properties prop=new Properties(); prop.put("mail.host",name); prop.put("mail.store.protocol","pop3"); Session session=Session.getDefaultInstance(prop,new Authenticator(){ protected PasswordAuthentication getPasswordAuthentication(){ return new PasswordAuthentication(user.getName(),user.getPassword()); } }); store=session.getStore(); store.connect(); folder = store.getFolder("INBOX"); folder.open(Folder.READ_ONLY); } public void close() throws Exception{ folder.close(false); store.close(); } public int getMessageCount() throws Exception{ return folder.getMessageCount(); } public Object getMessage(int messageNumber) throws Exception{ ByteArrayOutputStream out=new ByteArrayOutputStream(); folder.getMessage(messageNumber).writeTo(out); return out; } } //end //MailserverDispatcher.java public class MailserverDispatcher{ private static MailserverDispatcher dispatcher=new MailserverDispatcher(); private MailserverDispatcher(){ } public static MailserverDispatcher getInstance(){ return dispatcher; } public Mailserver getMailserver(String name,User user,Connect connect) throws Exception{ Mailserver mailserver= connect==Connect.SOCKET? (Mailserver)new MailserverBySocket(name): (Mailserver)new MailserverByJavaMail(name); mailserver.connect(user); return mailserver; } } //end //Command.java public abstract class Command{ protected Mailserver mailserver; public Command(Mailserver mailserver){ this.mailserver=mailserver; } public abstract Object execute() throws Exception; } //end //ListCommand.java public class ListCommand extends Command{ public ListCommand(Mailserver mailserver){ super(mailserver); } public Object execute() throws Exception{ return new Integer(mailserver.getMessageCount()); } } //end //ReadCommand.java public class ReadCommand extends Command{ private int messageNumber; public ReadCommand(Mailserver mailserver){ super(mailserver); } public void setMessageNumber(int messageNumber){ this.messageNumber=messageNumber; } public Object execute() throws Exception{ return mailserver.getMessage(messageNumber); } } //end //QuitCommand.java public class QuitCommand extends Command{ public QuitCommand(Mailserver mailserver){ super(mailserver); } public Object execute() throws Exception{ mailserver.close(); return "quit"; } } //end //CommandDispatcher.java import java.util.Properties; import java.lang.reflect.*; public class CommandDispatcher{ private static CommandDispatcher dispatcher=new CommandDispatcher(); private static Properties commandList=new Properties(); static{ commandList.put("list","ListCommand"); commandList.put("read","ReadCommand"); commandList.put("quit","QuitCommand"); } private CommandDispatcher(){ } public static CommandDispatcher getInstance(){ return dispatcher; } public static Command getCommand(Mailserver mailserver,String command) throws Exception{ int messageNumber=1; if(command.matches("(?i)^read \\d+$")){ messageNumber=Integer.parseInt(command.replaceAll("(?i)read\\s","")); command="read"; } Command com=(Command)Class.forName(commandList.get(command.toLowerCase()).toString()) .getConstructor(new Class[]{Mailserver.class}) .newInstance(new Object[]{mailserver}); //getConstructor(new Class[]{Mailserver.class})ではなくgetConstructor(new Class[]{mailserver.getClass()})ではエラー(NoSuchMethodException)になる. //mailserver.getClass()で帰ってくるのはMailserverByJavaMailかMailserverBySocket //Commandクラスのコンストラクタの引数はMailserver.MailserverByJavaMail/MailserverBySocketを引数に持つコンストラクタはない. //違いはSystem.out.println(Mailserver.class+"<==>"+mailserver.getClass());で確認できる. if(command=="read"){ ((ReadCommand)com).setMessageNumber(messageNumber); } return com; } } //end //User.java public class User{ private String name; private String password; public User(String name,String password){ this.name=name; this.password=password; } public String getName(){ return name; } public String getPassword(){ return password; } } //end //Connect.java public final class Connect{ public static final Connect SOCKET=new Connect(); public static final Connect JAVAMAIL=new Connect(); } //end //Controller.java import java.util.Observer; public class Controller{ private Mailserver mailserver; public Controller(Mailserver mailserver) throws Exception{ this.mailserver=mailserver; } public void addObserver(Observer observer){ mailserver.addObserver(observer); } public void actionPerformed() throws Exception{ mailserver.execute(); } } //end //View.java import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Observer; import java.util.Observable; import java.util.Properties; public class View implements java.util.Observer{ private String command; private Controller controller; private static Properties isContinue=new Properties(); static{ isContinue.put("list",new Boolean(true)); isContinue.put("read",new Boolean(true)); isContinue.put("quit",new Boolean(false)); } public View(Controller controller){ this.controller=controller; } public void show() throws Exception{ BufferedReader reader=new BufferedReader(new InputStreamReader(System.in)); System.out.print("ready: "); command=reader.readLine(); controller.actionPerformed(); //イベントは発生しないので,自分でactionPerformedを呼ぶ } public void update(Observable observer,Object object){ try{ System.out.println( CommandDispatcher.getInstance().getCommand((Mailserver)observer,command).execute()); if(((Boolean)isContinue.get(command.split(" ")[0])).booleanValue()){ show(); } } catch(Exception e){ e.printStackTrace(); } } } //end //Main.java import java.util.Observer; public class Main{ public static void main(String[] args){ try{ Controller controller=new Controller( MailserverDispatcher.getInstance() .getMailserver("mailserver", new User("username","password"), args[0].equalsIgnoreCase("socket")? Connect.SOCKET: Connect.JAVAMAIL)); //mailserver,username,passwordは適当に書換える. View view=new View(controller); controller.addObserver((Observer)view); view.show(); } catch(Exception e){ e.printStackTrace(); } } } //end
参考文献・サイト
- 北山洋幸著,Javaによるはじめてのインターネットプログラミング,技術評論社
- JavaでHello Workd JavaMail(POP)編
- JavaMail API
- JavaBeans Activation Framework
- Jude...Java and UML Developers' Environment