View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.example.tapedeck;
21  
22  import static org.apache.mina.statemachine.event.IoFilterEvents.*;
23  
24  import org.apache.mina.core.filterchain.IoFilter.NextFilter;
25  import org.apache.mina.core.future.IoFutureListener;
26  import org.apache.mina.core.session.IoSession;
27  import org.apache.mina.core.write.WriteRequest;
28  import org.apache.mina.example.tapedeck.TapeDeckServer.TapeDeckContext;
29  import org.apache.mina.statemachine.StateControl;
30  import org.apache.mina.statemachine.annotation.IoFilterTransition;
31  import org.apache.mina.statemachine.annotation.State;
32  import org.apache.mina.statemachine.context.AbstractStateContext;
33  
34  /**
35   * TODO Add documentation
36   * 
37   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
38   */
39  public class AuthenticationHandler {
40      @State public static final String ROOT = "Root";
41      @State(ROOT) public static final String START = "Start";
42      @State(ROOT) public static final String WAIT_USER = "WaitUser";
43      @State(ROOT) public static final String WAIT_PASSWORD = "WaitPassword";
44      @State(ROOT) public static final String DONE = "Done";
45      @State(ROOT) public static final String FAILED = "Failed";
46  
47      static class AuthenticationContext extends AbstractStateContext {
48          private String user;
49          private String password;
50          private int tries = 0;
51      }
52  
53      @IoFilterTransition(on = SESSION_OPENED, in = START, next = WAIT_USER)
54      public void sendAuthRequest(NextFilter nextFilter, IoSession session) {
55          session.write("+ Greetings from your tape deck!. Please authenticate yourself.");
56      }
57      
58      @IoFilterTransition(on = MESSAGE_RECEIVED, in = WAIT_USER, next = WAIT_PASSWORD)
59      public void user(AuthenticationContext context, NextFilter nextFilter, IoSession session, UserCommand cmd) {
60          context.user = cmd.getUsername();
61          session.write("+ Give me your password (hint: try your username backwards)");
62      }
63      
64      @IoFilterTransition(on = MESSAGE_RECEIVED, in = WAIT_PASSWORD, next = DONE)
65      public void password(AuthenticationContext context, NextFilter nextFilter, IoSession session, PasswordCommand cmd) {
66          context.password = cmd.getPassword();
67          if (context.password.equals(reverse(context.user))) {
68              session.write("+ Authentication succeeded! Your tape deck has been unlocked.");
69          } else {
70              context.tries++;
71              if (context.tries < 3) {
72                  session.write("- Authentication failed! Please try again.");
73                  StateControl.breakAndGotoNext(WAIT_USER);
74              } else {
75                  session.write("- Authentication failed too many times! Bye bye.").addListener(IoFutureListener.CLOSE);
76                  StateControl.breakAndGotoNext(FAILED);
77              }
78          }
79      }
80      
81      
82      @IoFilterTransition(on = MESSAGE_RECEIVED, in = ROOT)
83      public void quit(TapeDeckContext context, IoSession session, QuitCommand cmd) {
84          session.write("+ Bye! Please come back!").addListener(IoFutureListener.CLOSE);
85      }
86      
87      private String reverse(String s) {
88          char[] expectedPassword = new char[s.length()];
89          for (int i = 0; i < expectedPassword.length; i++) {
90              expectedPassword[i] = s.charAt(s.length() - i - 1);
91          }
92          return new String(expectedPassword);
93      }
94      
95      @IoFilterTransition(on = MESSAGE_RECEIVED, in = WAIT_USER, weight = 10)
96      public void errorWaitingForUser(IoSession session, Command cmd) {
97          if (cmd instanceof QuitCommand) {
98              StateControl.breakAndContinue();
99          }
100         session.write("Unexpected command '" + cmd.getName() + "'. Expected 'user <username>'.");
101     }
102     
103     @IoFilterTransition(on = MESSAGE_RECEIVED, in = WAIT_PASSWORD, weight = 10)
104     public void errorWaitingForPassword(IoSession session, Command cmd) {
105         if (cmd instanceof QuitCommand) {
106             StateControl.breakAndContinue();
107         }
108         session.write("Unexpected command '" + cmd.getName() + "'. Expected 'password <password>'.");
109     }
110     
111     @IoFilterTransition(on = EXCEPTION_CAUGHT, in = ROOT)
112     public void commandSyntaxError(IoSession session, CommandSyntaxException e) {
113         session.write("- " + e.getMessage());
114     }
115     
116     @IoFilterTransition(on = EXCEPTION_CAUGHT, in = ROOT, weight = 10)
117     public void exceptionCaught(IoSession session, Exception e) {
118         e.printStackTrace();
119         session.close(true);
120     }
121     
122     @IoFilterTransition(on = SESSION_CLOSED, in = DONE)
123     public void sessionClosed(NextFilter nextFilter, IoSession session) {
124         nextFilter.sessionClosed(session);
125     }
126     @IoFilterTransition(on = EXCEPTION_CAUGHT, in = DONE)
127     public void exceptionCaught(NextFilter nextFilter, IoSession session, Throwable cause) {
128         nextFilter.exceptionCaught(session, cause);
129     }
130     @IoFilterTransition(on = MESSAGE_RECEIVED, in = DONE)
131     public void messageReceived(NextFilter nextFilter, IoSession session, Object message) {
132         nextFilter.messageReceived(session, message);
133     }
134     @IoFilterTransition(on = MESSAGE_SENT, in = DONE)
135     public void messageSent(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) {
136         nextFilter.messageSent(session, writeRequest);
137     }
138     
139     @IoFilterTransition(on = CLOSE, in = ROOT)
140     public void filterClose(NextFilter nextFilter, IoSession session) {
141         nextFilter.filterClose(session);
142     }
143     @IoFilterTransition(on = WRITE, in = ROOT)
144     public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) {
145         nextFilter.filterWrite(session, writeRequest);
146     }
147 }