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 }