001         package com.croftsoft.apps.wyrm.server;
002    
003         import java.rmi.*;
004         import java.util.*;
005         import javax.naming.*;
006         import javax.rmi.*;
007    
008         import javax.ejb.*;
009    
010         import javax.xml.bind.JAXBException;
011    
012         import com.croftsoft.core.lang.NullArgumentException;
013         import com.croftsoft.core.math.MathLib;
014    
015         import com.croftsoft.apps.wyrm.WyrmConstants;
016         import com.croftsoft.apps.wyrm.entity.PcLocal;
017         import com.croftsoft.apps.wyrm.entity.PcLocalHome;
018         import com.croftsoft.apps.wyrm.entity.UserLocal;
019         import com.croftsoft.apps.wyrm.entity.UserLocalHome;
020         import com.croftsoft.apps.wyrm.xjc.*;
021    
022         /*********************************************************************
023         * Wyrm server stateless session EJB.
024         *
025         * @version
026         *   2002-11-04
027         * @since
028         *   2002-10-17
029         * @author
030         *   <a href="http://alumni.caltech.edu/~croft">David Wallace Croft</a>
031         *********************************************************************/
032    
033         public class  WyrmServerBean
034           implements SessionBean, WyrmConstants
035         //////////////////////////////////////////////////////////////////////
036         //////////////////////////////////////////////////////////////////////
037         {
038    
039         private static final String  JNDI_PC_LOCAL_HOME
040           = "java:comp/env/ejb/PcLocalHome";
041    
042         private static final String  JNDI_USER_LOCAL_HOME
043           = "java:comp/env/ejb/UserLocalHome";
044    
045         private static final String  JNDI_INIT_HEALTH
046           = "java:comp/env/initial_health";
047    
048         //
049    
050         private static final String  STATE_DUNGEON   = "dungeon";
051    
052         private static final String  STATE_HEALER    = "healer";
053    
054         private static final String  STATE_TOWN      = "town";
055    
056         //
057    
058         private static final double  INIT_USER_CREDITS = 0.0;
059    
060         //
061    
062         private static final String  INIT_PC_NAME       = "Unnamed Hero";
063    
064         private static final String  INIT_PC_STATE      = STATE_TOWN;
065    
066         private static final long    INIT_PC_HEALTH     = 10;
067    
068         private static final long    INIT_PC_WEALTH     = 100;
069    
070         private static final long    INIT_PC_LEVEL      = 0;
071    
072         private static final long    INIT_PC_EXPERIENCE = 0;
073    
074         //
075    
076         private static final int  HEALING_COST = 10;
077    
078         //
079    
080         private static final Random  random = new Random ( );
081    
082         //////////////////////////////////////////////////////////////////////
083         //////////////////////////////////////////////////////////////////////
084    
085         public Object  serve ( Object  requestObject )
086         //////////////////////////////////////////////////////////////////////
087         {
088           try
089           {
090             NullArgumentException.check ( requestObject );
091    
092             if ( !( requestObject instanceof Request ) )
093             {
094               String  type = requestObject.getClass ( ).getName ( );
095    
096               return createResponse (
097                 type,
098                 false,
099                 "unknown request type:  " + type,
100                 null );
101             }
102    
103             Request  request = ( Request ) requestObject;
104    
105             String  requestType = request.getType ( );
106    
107             if ( requestType == null )
108             {
109               return createResponse (
110                 null,
111                 false,
112                 "null request type",
113                 null );
114             }
115    
116             requestType = requestType.trim ( );
117    
118             String  username = request.getUsername ( );
119    
120             String  password = request.getPassword ( );
121    
122             if ( requestType.equals ( TYPE_CREATE_USER ) )
123             {
124               return serveRequestCreateUser ( username, password );
125             }
126    
127             if ( username == null )
128             {
129               return createResponse (
130                 TYPE_LOGIN,
131                 false,
132                 "Welcome to the Wyrm!",
133                 null );
134             }
135    
136             if ( password == null )
137             {
138               return createResponse (
139                 TYPE_LOGIN,
140                 false,
141                 "Null password.",
142                 username );
143             }
144    
145             UserLocal  userLocal = getUserLocal ( username, password );
146    
147             if ( userLocal == null )
148             {
149               return createResponse (
150                 TYPE_LOGIN,
151                 false,
152                 "Unknown username or incorrect password.",
153                 username );
154             }
155    
156             try
157             {
158               if ( requestType.equals ( TYPE_ACCOUNT ) )
159               {
160                 return serveRequestAccount ( userLocal );
161               }
162    
163               if ( requestType.equals ( TYPE_DESTROY_USER ) )
164               {
165                 return serveRequestDestroyUser ( userLocal );
166               }
167    
168               if ( requestType.equals ( TYPE_DUNGEON ) )
169               {
170                 return serveRequestDungeon ( userLocal );
171               }
172    
173               if ( requestType.equals ( TYPE_FIGHT ) )
174               {
175                 return serveRequestFight ( userLocal );
176               }
177    
178               if ( requestType.equals ( TYPE_FLEE ) )
179               {
180                 return serveRequestFlee ( userLocal );
181               }
182    
183               if ( requestType.equals ( TYPE_HEAL ) )
184               {
185                 return serveRequestHeal ( userLocal );
186               }
187    
188               if ( requestType.equals ( TYPE_HEALER ) )
189               {
190                 return serveRequestHealer ( userLocal );
191               }
192    
193               if ( requestType.equals ( TYPE_LOGIN ) )
194               {
195                 return serveRequestLogin ( userLocal );
196               }
197    
198               if ( requestType.equals ( TYPE_LOGOUT ) )
199               {
200                 return serveRequestLogout ( username );
201               }
202    
203               if ( requestType.equals ( TYPE_STATE ) )
204               {
205                 return serveRequestState ( userLocal );
206               }
207    
208               if ( requestType.equals ( TYPE_TOWN ) )
209               {
210                 return serveRequestTown ( userLocal );
211               }
212             }
213             catch ( IllegalStateException  ex )
214             {
215               ResponseState  responseState = serveRequestState ( userLocal );
216    
217               responseState.setMessage (
218                 "Your request is not allowed from here." );
219    
220               return responseState;
221             }
222    
223             return createResponse (
224               requestType,
225               false,
226               "unknown request type:  " + requestType,
227               username );
228           }
229           catch ( Exception  ex )
230           {
231             // Throwing EJBException will cause the transaction to be
232             // rolled back automatically.
233             // See p433, Monson-Haefel, "Enterprise Java Beans", 3rd Ed., 2001
234    
235             throw new EJBException ( ex );
236           }
237         }
238    
239         //////////////////////////////////////////////////////////////////////
240         //////////////////////////////////////////////////////////////////////
241    
242         private Object  serveRequestAccount ( UserLocal  userLocal )
243           throws Exception
244         //////////////////////////////////////////////////////////////////////
245         {
246           ResponseAccount  responseAccount
247             = ObjectFactory.createResponseAccount ( );
248    
249           responseAccount.setUsername   ( userLocal.getUsername   ( ) );
250    
251           responseAccount.setFirstName  ( userLocal.getFirstName  ( ) );
252    
253           responseAccount.setMiddleName ( userLocal.getMiddleName ( ) );
254    
255           responseAccount.setLastName   ( userLocal.getLastName   ( ) );
256    
257           responseAccount.setCredits    ( userLocal.getCredits    ( ) );
258    
259           return responseAccount;
260         }
261    
262         private Object  serveRequestCreateUser (
263           String  username,
264           String  password )
265           throws Exception
266         //////////////////////////////////////////////////////////////////////
267         {
268           if ( username == null )
269           {
270             return createResponse (
271               TYPE_CREATE_USER,
272               false,
273               null,
274               null );
275           }
276    
277           boolean  granted
278             = ( password != null )
279             && !"".equals ( username.trim ( ) )
280             && !"".equals ( password.trim ( ) )
281             && username.equals ( username.toLowerCase ( ) )
282             && username.equals ( username.trim ( ) );
283    
284    // TODO:  Need to also check that username just letters, numbers,
285    // and underscore with no white space as well.
286    
287           if ( !granted )
288           {
289             return createResponse (
290               TYPE_CREATE_USER,
291               false,
292               "Bad username or password.",
293               username );
294           }
295    
296           Context  context = new InitialContext ( );
297    
298           Object  obj = context.lookup ( JNDI_USER_LOCAL_HOME );
299    
300           UserLocalHome  userLocalHome = ( UserLocalHome )
301             PortableRemoteObject.narrow ( obj, UserLocalHome.class );
302    
303           UserLocal  userLocal = null;
304    
305           try
306           {
307             userLocal = userLocalHome.findByUsername ( username );
308    
309             return createResponse (
310               TYPE_CREATE_USER,
311               false,
312               "Username already in use.",
313               username );
314           }
315           catch ( ObjectNotFoundException  ex )
316           {
317           }       
318    
319           userLocal = userLocalHome.create ( username );
320    
321           userLocal.setPassword ( password );
322    
323           userLocal.setCredits ( INIT_USER_CREDITS );
324    
325           createPcLocal ( userLocal );
326    
327           return serveRequestState ( userLocal );
328         }
329    
330         private Object  serveRequestDestroyUser ( UserLocal  userLocal )
331           throws Exception
332         //////////////////////////////////////////////////////////////////////
333         {
334           PcLocal  pcLocal = userLocal.getPcLocal ( );
335    
336           // This prevents a database persistent memory leak.
337    
338           if ( pcLocal != null )
339           {
340             pcLocal.remove ( );
341           }
342    
343           String  username = userLocal.getUsername ( );
344    
345           userLocal.remove ( );
346    
347           return createResponse (
348             TYPE_DESTROY_USER,
349             true,
350             "User " + username + " destroyed.",
351             username );
352         }
353    
354         private Object  serveRequestDungeon ( UserLocal  userLocal )
355           throws Exception
356         //////////////////////////////////////////////////////////////////////
357         {
358           PcLocal  pcLocal = getPcLocal ( userLocal );
359    
360           checkState ( pcLocal, STATE_TOWN );
361    
362           pcLocal.setState ( STATE_DUNGEON );
363    
364           ResponseState  responseState = serveRequestState ( userLocal );
365    
366           responseState.setMessage ( "You have entered the dungeon." );
367    
368           return responseState;
369         }
370    
371         private Object  serveRequestFight ( UserLocal  userLocal )
372           throws Exception
373         //////////////////////////////////////////////////////////////////////
374         {
375           PcLocal  pcLocal = getPcLocal ( userLocal );
376    
377           checkState ( pcLocal, STATE_DUNGEON );
378    
379           boolean  victory = random.nextBoolean ( );
380    
381           String  message = null;
382    
383           if ( victory )
384           {
385             message = "You conquer and find treasure.";
386    
387             pcLocal.setWealth ( pcLocal.getWealth ( ) + 1 );
388    
389             long  experience = pcLocal.getExperience ( ) + 1;
390    
391             pcLocal.setExperience ( experience );
392    
393             long  level = pcLocal.getLevel ( );
394    
395             if ( MathLib.log ( experience, 10 ) >= level + 1 )
396             {
397               pcLocal.setLevel ( ++level );
398             }
399           }
400           else
401           {
402             message = "You have been wounded.";
403    
404             pcLocal.setHealth ( pcLocal.getHealth ( ) - 1 );
405           }
406    
407           ResponseState  responseState = serveRequestState ( userLocal );
408    
409           responseState.setMessage ( message );
410    
411           return responseState;
412         }
413    
414         private Object  serveRequestFlee ( UserLocal  userLocal )
415           throws Exception
416         //////////////////////////////////////////////////////////////////////
417         {
418           PcLocal  pcLocal = getPcLocal ( userLocal );
419    
420           checkState ( pcLocal, STATE_DUNGEON );
421    
422           pcLocal.setState ( STATE_TOWN );
423    
424           pcLocal.setHealth ( pcLocal.getHealth ( ) - 1 );
425    
426           ResponseState  responseState = serveRequestState ( userLocal );
427    
428           responseState.setMessage ( "You are wounded as you turn to flee." );
429    
430           return responseState;
431         }
432    
433         private Object  serveRequestHeal ( UserLocal  userLocal )
434           throws Exception
435         //////////////////////////////////////////////////////////////////////
436         {
437           PcLocal  pcLocal = getPcLocal ( userLocal );
438    
439           checkState ( pcLocal, STATE_HEALER );
440    
441           pcLocal.setWealth ( pcLocal.getWealth ( ) - HEALING_COST );
442    
443           pcLocal.setHealth ( INIT_PC_HEALTH );
444    
445           pcLocal.setState ( STATE_TOWN );
446    
447           ResponseState  responseState = serveRequestState ( userLocal );
448    
449           responseState.setMessage (
450             "You return to the town square after being healed." );
451    
452           return responseState;
453         }
454    
455         private Object  serveRequestHealer ( UserLocal  userLocal )
456           throws Exception
457         //////////////////////////////////////////////////////////////////////
458         {
459           PcLocal  pcLocal = getPcLocal ( userLocal );
460    
461           checkState ( pcLocal, STATE_TOWN );
462    
463           pcLocal.setState ( STATE_HEALER );
464    
465           ResponseState  responseState = serveRequestState ( userLocal );
466    
467           responseState.setMessage ( "You enter the Healer's hut." );
468    
469           return responseState;
470         }
471    
472         private Object  serveRequestLogin ( UserLocal  userLocal )
473           throws Exception
474         //////////////////////////////////////////////////////////////////////
475         {
476           ResponseState  responseState = serveRequestState ( userLocal );
477    
478           responseState.setMessage ( "Welcome to the Wyrm!" );
479    
480           return responseState;
481         }
482    
483         private Object  serveRequestLogout ( String  username )
484           throws Exception
485         //////////////////////////////////////////////////////////////////////
486         {
487           return createResponse (
488             TYPE_LOGOUT,
489             true,
490             "Goodbye.",
491             username );
492         }
493    
494         private Object  serveRequestTown ( UserLocal  userLocal )
495           throws Exception
496         //////////////////////////////////////////////////////////////////////
497         {
498           PcLocal  pcLocal = getPcLocal ( userLocal );
499    
500           checkState ( pcLocal, STATE_HEALER );
501    
502           pcLocal.setState ( STATE_TOWN );
503    
504           ResponseState  responseState = serveRequestState ( userLocal );
505    
506           responseState.setMessage ( "You enter the town square." );
507    
508           return responseState;
509         }
510    
511         //////////////////////////////////////////////////////////////////////
512         //////////////////////////////////////////////////////////////////////
513    
514         private UserLocal  getUserLocal (
515           String  username,
516           String  password )
517           throws Exception
518         //////////////////////////////////////////////////////////////////////
519         {
520           // Can I move some of this code to ejbCreate() so that it is only
521           // executed once?
522    
523           InitialContext  initialContext = new InitialContext ( );
524    
525           Object  obj = initialContext.lookup ( JNDI_USER_LOCAL_HOME );
526    
527           UserLocalHome  userLocalHome = ( UserLocalHome )
528             PortableRemoteObject.narrow ( obj, UserLocalHome.class );
529    
530           UserLocal  userLocal = null;
531    
532           try
533           {
534             userLocal = userLocalHome.findByUsername ( username );
535           }
536           catch ( ObjectNotFoundException  ex )
537           {
538             // Can I use userLocalHome.userExists(username) instead?
539    
540             return null;
541           }
542    
543           if ( !password.equals ( userLocal.getPassword ( ) ) )
544           {
545             return null;
546           }
547    
548           return userLocal;
549         }
550    
551         private ResponseState  serveRequestState ( UserLocal  userLocal )
552           throws Exception
553         //////////////////////////////////////////////////////////////////////
554         {
555           ResponseState  responseState
556             = ObjectFactory.createResponseState ( );
557    
558           responseState.setUsername ( userLocal.getUsername ( ) );
559    
560           responseState.setCredits ( userLocal.getCredits ( ) );
561    
562           PcLocal  pcLocal = getPcLocal ( userLocal );
563    
564           responseState.setState  ( pcLocal.getState  ( ) );
565    
566           responseState.setPcName ( pcLocal.getName   ( ) );
567    
568           responseState.setHealth ( pcLocal.getHealth ( ) );
569    
570           responseState.setWealth ( pcLocal.getWealth ( ) );
571    
572           responseState.setLevel  ( pcLocal.getLevel  ( ) );
573    
574           responseState.setExperience ( pcLocal.getExperience ( ) );
575    
576           responseState.setMessage ( "" );
577    
578           return responseState;
579         }
580    
581         private PcLocal  getPcLocal ( UserLocal  userLocal )
582           throws Exception
583         //////////////////////////////////////////////////////////////////////
584         {
585           PcLocal  pcLocal = userLocal.getPcLocal ( );
586    
587           if ( pcLocal == null )
588           {
589             pcLocal = createPcLocal ( userLocal );
590           }
591    
592           return pcLocal;
593         }
594    
595         private PcLocal  createPcLocal ( UserLocal  userLocal )
596           throws Exception
597         //////////////////////////////////////////////////////////////////////
598         {
599           InitialContext  initialContext = new InitialContext ( );
600    
601           Object  obj = initialContext.lookup ( JNDI_PC_LOCAL_HOME );
602    
603           PcLocalHome  pcLocalHome = ( PcLocalHome )
604             PortableRemoteObject.narrow ( obj, PcLocalHome.class );
605    
606           PcLocal  pcLocal = pcLocalHome.create ( );
607    
608           pcLocal.setName       ( INIT_PC_NAME       );
609    
610           pcLocal.setState      ( INIT_PC_STATE      );
611    
612           pcLocal.setHealth     ( INIT_PC_HEALTH     );
613    
614           pcLocal.setWealth     ( INIT_PC_WEALTH     );
615    
616           pcLocal.setLevel      ( INIT_PC_LEVEL      );
617    
618           pcLocal.setExperience ( INIT_PC_EXPERIENCE );
619    
620           userLocal.setPcLocal ( pcLocal );
621    
622           Long  envInitHealth
623             = ( Long ) initialContext.lookup ( JNDI_INIT_HEALTH );
624    
625           if ( envInitHealth != null )
626           {
627             pcLocal.setHealth ( envInitHealth.longValue ( ) );
628           }
629    
630           return pcLocal;
631         }
632    
633         private void  checkState (
634           PcLocal  pcLocal,
635           String   desiredState )
636           throws Exception
637         //////////////////////////////////////////////////////////////////////
638         {
639           String  state = pcLocal.getState ( );
640    
641           if ( state == null )
642           {
643             state = INIT_PC_STATE;
644           }
645    
646           if ( !state.equals ( desiredState ) )
647           {
648             throw new IllegalStateException ( );
649           }       
650         }
651    
652         private Response  createResponse (
653           String   type,
654           boolean  granted,
655           String   message,
656           String   username )
657           throws Exception
658         //////////////////////////////////////////////////////////////////////
659         {
660           Response  response = ObjectFactory.createResponse ( );
661    
662           response.setType ( type );
663    
664           response.setGranted ( granted );
665    
666           response.setMessage ( message != null ? message : "" );
667    
668           response.setUsername ( username != null ? username : "" );
669    
670           return response;
671         }
672    
673         //////////////////////////////////////////////////////////////////////
674         //////////////////////////////////////////////////////////////////////
675    
676         public void  ejbActivate  ( ) { }
677    
678         public void  ejbCreate    ( ) { }
679    
680         public void  ejbPassivate ( ) { }
681    
682         public void  ejbRemove    ( ) { }
683    
684         public void  setSessionContext ( SessionContext  sessionContext ) { }
685    
686         //////////////////////////////////////////////////////////////////////
687         //////////////////////////////////////////////////////////////////////
688         }