Download | Plain Text | No Line Numbers


  1. /*
  2.  * Copyright (c) 2010, Manuel Mausz. All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * - Redistributions of source code must retain the above copyright
  9.  * notice, this list of conditions and the following disclaimer.
  10.  *
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  * notice, this list of conditions and the following disclaimer in the
  13.  * documentation and/or other materials provided with the distribution.
  14.  *
  15.  * - The names of the authors may not be used to endorse or promote products
  16.  * derived from this software without specific prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  19.  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  20.  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  21.  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  22.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  23.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  25.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  26.  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  27.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  */
  30.  
  31. import static java.lang.System.err;
  32. import static java.lang.System.out;
  33.  
  34. import java.util.concurrent.ScheduledExecutorService;
  35. import java.util.concurrent.ScheduledFuture;
  36. import java.util.concurrent.Executors;
  37. import java.util.concurrent.TimeUnit;
  38.  
  39. import java.rmi.registry.*;
  40. import java.rmi.server.*;
  41. import java.rmi.*;
  42.  
  43. import java.text.SimpleDateFormat;
  44. import java.lang.StringBuffer;
  45. import java.util.Collections;
  46. import java.util.Comparator;
  47. import java.util.Properties;
  48. import java.util.ArrayList;
  49. import java.util.HashMap;
  50. import java.util.HashSet;
  51. import java.util.Arrays;
  52. import java.util.Date;
  53. import java.util.Set;
  54. import java.util.Map;
  55.  
  56. import java.io.*;
  57.  
  58. /*
  59.  * Server implementation for Lab#2 of DSLab WS10
  60.  * See angabe.pdf for details
  61.  *
  62.  * This code is not documented at all. This is volitional
  63.  *
  64.  * @author Manuel Mausz (0728348)
  65.  */
  66. public class Server
  67. implements Serializable
  68. {
  69. public class ServerRecords
  70. extends HashMap<String, S2SInterface>
  71. {}
  72.  
  73. /*==========================================================================*/
  74.  
  75. public class UserRecord
  76. implements Serializable
  77. {
  78. public final String name;
  79. public final String server;
  80. public String pass = null;
  81. public boolean committed = false;
  82. public S2CInterface s2ciface = null;
  83.  
  84. UserRecord(String name, String server)
  85. {
  86. this.name = name;
  87. this.server = server;
  88. }
  89.  
  90. /*------------------------------------------------------------------------*/
  91.  
  92. public synchronized boolean isCommitted()
  93. {
  94. return committed;
  95. }
  96.  
  97. /*------------------------------------------------------------------------*/
  98.  
  99. public synchronized void commit()
  100. {
  101. committed = true;
  102. }
  103. }
  104.  
  105. /*==========================================================================*/
  106.  
  107. public class UserRecords
  108. extends HashMap<String, UserRecord>
  109. {
  110. public synchronized boolean register(String user, String pass)
  111. {
  112. if (!registerPrepare(user, bindingName))
  113. return false;
  114.  
  115. synchronized(servers)
  116. {
  117. ArrayList<String> rollbacklist = new ArrayList<String>();
  118. boolean ret = true;
  119.  
  120. for(String server : servers.keySet())
  121. {
  122. try
  123. {
  124. ret = servers.get(server).registerPrepare(user, bindingName);
  125. }
  126. catch(RemoteException e)
  127. {
  128. ret = false;
  129. }
  130.  
  131. if (!ret)
  132. break;
  133. rollbacklist.add(server);
  134. }
  135.  
  136. if (!ret)
  137. {
  138. for(String server : rollbacklist)
  139. {
  140. try
  141. {
  142. servers.get(server).registerRollback(user);
  143. }
  144. catch(RemoteException e)
  145. {}
  146. }
  147. registerRollback(user);
  148. return false;
  149. }
  150.  
  151. for(String server : servers.keySet())
  152. {
  153. try
  154. {
  155. servers.get(server).registerCommit(user);
  156. }
  157. catch(RemoteException e)
  158. {}
  159. }
  160.  
  161. registerCommit(user);
  162. get(user).pass = pass;
  163. }
  164.  
  165. return true;
  166. }
  167.  
  168. /*------------------------------------------------------------------------*/
  169.  
  170. public synchronized boolean registerPrepare(String user, String server)
  171. {
  172. if (containsKey(user))
  173. return false;
  174. put(user, new UserRecord(user, server));
  175. return true;
  176. }
  177.  
  178. /*------------------------------------------------------------------------*/
  179.  
  180. public synchronized boolean registerCommit(String user)
  181. {
  182. if (!containsKey(user))
  183. return false;
  184. get(user).commit();
  185. return true;
  186. }
  187.  
  188. /*------------------------------------------------------------------------*/
  189.  
  190. public synchronized boolean registerRollback(String user)
  191. {
  192. out.println("rollback");
  193. if (!containsKey(user))
  194. return true;
  195. if (get(user).isCommitted())
  196. return false;
  197. remove(user);
  198. return true;
  199. }
  200.  
  201. /*------------------------------------------------------------------------*/
  202.  
  203. public synchronized UserRecord login(String user, String pass, S2CInterface s2ciface)
  204. {
  205. UserRecord record = get(user);
  206. if (record == null)
  207. return null;
  208.  
  209. synchronized(record)
  210. {
  211. if (record.pass == null || !record.pass.equals(pass) || !record.isCommitted())
  212. return null;
  213.  
  214. try
  215. {
  216. if (record.s2ciface != null)
  217. {
  218. record.s2ciface.notify("Another user logged in using your credentials. You will get logged out now.");
  219. record.s2ciface.logout();
  220. }
  221. }
  222. catch(RemoteException e)
  223. {}
  224.  
  225. record.s2ciface = s2ciface;
  226. }
  227. return record;
  228. }
  229.  
  230. /*------------------------------------------------------------------------*/
  231.  
  232. public synchronized void logout(UserRecord user)
  233. {
  234. if (user != null)
  235. {
  236. synchronized(user)
  237. {
  238. user.s2ciface = null;
  239. }
  240. }
  241. }
  242.  
  243. /*------------------------------------------------------------------------*/
  244.  
  245. public synchronized void notify(String user, String msg)
  246. throws RemoteException
  247. {
  248. UserRecord record = get(user);
  249. if (record == null)
  250. throw new RemoteException("User doesn't exist.");
  251. synchronized(record)
  252. {
  253. if (!record.isCommitted())
  254. throw new RemoteException("User doesn't exist.");
  255.  
  256. if (!record.server.equals(bindingName))
  257. {
  258. S2SInterface tmp = servers.get(record.server);
  259. if (tmp != null)
  260. {
  261. try
  262. {
  263. tmp.notifyUser(user, msg);
  264. }
  265. catch(RemoteException e)
  266. {}
  267. }
  268. return;
  269. }
  270.  
  271. if (record.s2ciface != null)
  272. record.s2ciface.notify(msg);
  273. }
  274. }
  275. }
  276.  
  277. /*==========================================================================*/
  278.  
  279. public class EventRecord
  280. implements Serializable
  281. {
  282. public final String name;
  283. public String location;
  284. public int duration;
  285. public String author = null;
  286. public final String server;
  287. public boolean committed = false;
  288. public HashMap<Date, Integer> dates;
  289. public Date date = null;
  290. public HashSet<String> invitees;
  291. public HashSet<String> voted;
  292.  
  293. EventRecord(String name, String server)
  294. {
  295. this.name = name;
  296. this.server = server;
  297. dates = new HashMap<Date, Integer>();
  298. invitees = new HashSet<String>();
  299. voted = new HashSet<String>();
  300. }
  301.  
  302. /*------------------------------------------------------------------------*/
  303.  
  304. public synchronized boolean isCommitted()
  305. {
  306. return committed;
  307. }
  308.  
  309. /*------------------------------------------------------------------------*/
  310.  
  311. public synchronized void commit()
  312. {
  313. committed = true;
  314. }
  315. }
  316.  
  317. /*==========================================================================*/
  318.  
  319. public class EventRecords
  320. extends HashMap<String, EventRecord>
  321. {
  322. private SimpleDateFormat datefmt = new SimpleDateFormat("dd.MM.yyyy/HH:mm");
  323.  
  324. public synchronized boolean create(UserRecord user, String event,
  325. String location, int duration)
  326. {
  327. if (!createPrepare(event, bindingName))
  328. return false;
  329.  
  330. synchronized(servers)
  331. {
  332. ArrayList<String> rollbacklist = new ArrayList<String>();
  333. boolean ret = true;
  334.  
  335. for(String server : servers.keySet())
  336. {
  337. try
  338. {
  339. ret = servers.get(server).createPrepare(event, bindingName);
  340. }
  341. catch(RemoteException e)
  342. {
  343. ret = false;
  344. }
  345.  
  346. if (!ret)
  347. break;
  348. rollbacklist.add(server);
  349. }
  350.  
  351. if (!ret)
  352. {
  353. for(String server : rollbacklist)
  354. {
  355. try
  356. {
  357. servers.get(server).createRollback(event);
  358. }
  359. catch(RemoteException e)
  360. {}
  361. }
  362. createRollback(event);
  363. return false;
  364. }
  365.  
  366. for(String server : servers.keySet())
  367. {
  368. try
  369. {
  370. servers.get(server).createCommit(event);
  371. }
  372. catch(RemoteException e)
  373. {}
  374. }
  375.  
  376. createCommit(event);
  377. EventRecord record = get(event);
  378. synchronized(record)
  379. {
  380. record.location = location;
  381. record.duration = duration;
  382. synchronized(user)
  383. {
  384. record.author = user.name;
  385. }
  386. }
  387. }
  388.  
  389. return true;
  390. }
  391.  
  392. /*------------------------------------------------------------------------*/
  393.  
  394. public synchronized boolean createPrepare(String event, String server)
  395. {
  396. if (containsKey(event))
  397. return false;
  398. put(event, new EventRecord(event, server));
  399. return true;
  400. }
  401.  
  402. /*------------------------------------------------------------------------*/
  403.  
  404. public synchronized boolean createCommit(String event)
  405. {
  406. if (!containsKey(event))
  407. return false;
  408. get(event).commit();
  409. return true;
  410. }
  411.  
  412. /*------------------------------------------------------------------------*/
  413.  
  414. public synchronized boolean createRollback(String event)
  415. {
  416. if (!containsKey(event))
  417. return true;
  418. if (get(event).isCommitted())
  419. return false;
  420. remove(event);
  421. return true;
  422. }
  423.  
  424. /*------------------------------------------------------------------------*/
  425.  
  426. public synchronized void addDate(UserRecord user, String event, Date date)
  427. throws RemoteException
  428. {
  429. EventRecord record = get(event);
  430. if (record == null)
  431. throw new RemoteException("Event doesn't exist.");
  432. synchronized(record)
  433. {
  434. if (!record.isCommitted())
  435. throw new RemoteException("Event doesn't exist.");
  436. synchronized(user)
  437. {
  438. if (record.author == null || !record.author.equals(user.name))
  439. throw new RemoteException("You're not the author of that event.");
  440. }
  441. if (record.date != null)
  442. throw new RemoteException("Event already have been finalized.");
  443. if (record.dates.containsKey(date))
  444. throw new RemoteException("Date already exists.");
  445. record.dates.put(date, 0);
  446. }
  447. }
  448.  
  449. /*------------------------------------------------------------------------*/
  450.  
  451. public synchronized void invite(UserRecord user, String event, String invitee)
  452. throws RemoteException
  453. {
  454. EventRecord record = get(event);
  455. if (record == null)
  456. throw new RemoteException("Event doesn't exist.");
  457. synchronized(record)
  458. {
  459. if (!record.isCommitted())
  460. throw new RemoteException("Event doesn't exist.");
  461. synchronized(user)
  462. {
  463. if (record.author == null || !record.author.equals(user.name))
  464. throw new RemoteException("You're not the author of that event.");
  465. }
  466. if (record.author.equals(invitee))
  467. throw new RemoteException("You can't invite yourself.");
  468. if (record.date != null)
  469. throw new RemoteException("Event already have been finalized.");
  470. if (record.invitees.contains(invitee))
  471. throw new RemoteException("User already invited.");
  472.  
  473. users.notify(invitee, "You have been invited to event \"" + event + "\"");
  474. record.invitees.add(invitee);
  475. }
  476. }
  477.  
  478. /*------------------------------------------------------------------------*/
  479.  
  480. public synchronized String toString(String event)
  481. throws RemoteException
  482. {
  483. EventRecord record = get(event);
  484. if (record == null)
  485. throw new RemoteException("Event doesn't exist.");
  486.  
  487. synchronized(record)
  488. {
  489. if (!record.isCommitted())
  490. throw new RemoteException("Event doesn't exist.");
  491. if (!record.server.equals(bindingName))
  492. {
  493. S2SInterface tmp = servers.get(record.server);
  494. if (tmp == null)
  495. throw new RemoteException("Internal Error: Remote server doesn't exist anymore.");
  496. return tmp.eventToString(event);
  497. }
  498.  
  499. StringBuffer sb = new StringBuffer(100);
  500. sb.append("Event: ").append(record.name).append("\n");
  501. sb.append("Location: ").append(record.location).append("\n");
  502. sb.append("Duration: ").append(record.duration).append(" min.\n");
  503. sb.append("Author: ").append(record.author).append("\n");
  504.  
  505. if (record.date != null)
  506. sb.append("Date: ").append(datefmt.format(record.date)).append("\n");
  507. else
  508. {
  509. if (record.dates.size() == 0)
  510. sb.append("Options: None set\n");
  511. else
  512. {
  513. sb.append("Options:\n");
  514. for(Date date : record.dates.keySet())
  515. sb.append(" * ").append(datefmt.format(date)).append(" ... ")
  516. .append(record.dates.get(date)).append(" votes\n");
  517. }
  518. }
  519.  
  520. if (record.invitees.size() == 0)
  521. sb.append("Invitees: None set\n");
  522. else
  523. sb.append("Invitees: ").append(Utils.join(record.invitees, ", ")).append("\n");
  524.  
  525. return sb.toString();
  526. }
  527. }
  528.  
  529. /*------------------------------------------------------------------------*/
  530.  
  531. public synchronized void vote(String event, String user, Date[] dates)
  532. throws RemoteException
  533. {
  534. EventRecord record = get(event);
  535. if (record == null)
  536. throw new RemoteException("Event doesn't exist.");
  537.  
  538. synchronized(record)
  539. {
  540. if (!record.isCommitted())
  541. throw new RemoteException("Event doesn't exist.");
  542. if (!record.server.equals(bindingName))
  543. {
  544. S2SInterface tmp = servers.get(record.server);
  545. if (tmp == null)
  546. throw new RemoteException("Internal Error: Remote server doesn't exist anymore.");
  547. try
  548. {
  549. tmp.vote(event, user, dates);
  550. }
  551. catch(RemoteException e)
  552. {
  553. throw new RemoteException(e.getCause().getMessage());
  554. }
  555. return;
  556. }
  557.  
  558. if (record.date != null)
  559. throw new RemoteException("Event already have been finalized.");
  560. if (record.voted.contains(user))
  561. throw new RemoteException("You have already voted.");
  562. if ((record.author == null || !record.author.equals(user))
  563. && !record.invitees.contains(user))
  564. throw new RemoteException("You're not allowed to vote for that event.");
  565.  
  566. Set recorddates = record.dates.keySet();
  567. for(Date date : dates)
  568. {
  569. if (!recorddates.contains(date))
  570. throw new RemoteException("Date \"" + datefmt.format(date) + "\" is not a valid option.");
  571. }
  572.  
  573. for(Date date : dates)
  574. record.dates.put(date, record.dates.get(date) + 1);
  575. record.voted.add(user);
  576. }
  577. }
  578.  
  579. /*------------------------------------------------------------------------*/
  580.  
  581. public synchronized void finalize(UserRecord user, String event)
  582. throws RemoteException
  583. {
  584. EventRecord record = get(event);
  585. if (record == null)
  586. throw new RemoteException("Event doesn't exist.");
  587. synchronized(record)
  588. {
  589. synchronized(user)
  590. {
  591. if (!record.isCommitted())
  592. throw new RemoteException("Event doesn't exist.");
  593. if (record.author == null || !record.author.equals(user.name))
  594. throw new RemoteException("You're not the author of that event.");
  595. if (record.date != null)
  596. throw new RemoteException("Event has already been finalized.");
  597.  
  598. record.date = Collections.max(record.dates.entrySet(),
  599. new Comparator<Map.Entry<Date, Integer>>() {
  600. public int compare(Map.Entry<Date, Integer> o1, Map.Entry<Date, Integer> o2)
  601. {
  602. return o1.getValue().compareTo(o2.getValue());
  603. }
  604. }).getKey();
  605.  
  606. String text = "Event \"" + event + "\" has been scheduled on "
  607. + datefmt.format(record.date) + ".";
  608. users.notify(user.name, text);
  609. for(String invitee : record.invitees)
  610. users.notify(invitee, text);
  611. }
  612. }
  613. }
  614. }
  615.  
  616. /*==========================================================================*/
  617.  
  618. public class WaitForServers
  619. implements Runnable
  620. {
  621. private ArrayList<String> serverlist;
  622. WaitForServers()
  623. {
  624. serverlist = new ArrayList<String>();
  625. serverlist.addAll(Arrays.asList(serverNames));
  626. serverlist.add(bindingName);
  627. Collections.sort(serverlist);
  628. }
  629.  
  630. /*------------------------------------------------------------------------*/
  631.  
  632. public void shutdown()
  633. {
  634. scheduler.shutdown();
  635. synchronized(mainLock)
  636. {
  637. mainLock.notify();
  638. }
  639. }
  640.  
  641. /*------------------------------------------------------------------------*/
  642.  
  643. public void run()
  644. {
  645. synchronized(registry)
  646. {
  647. try
  648. {
  649. String[] tmp = registry.list();
  650. Collections.sort(Arrays.asList(tmp));
  651. if (serverlist.equals(Arrays.asList(tmp)))
  652. {
  653. synchronized(servers)
  654. {
  655. for(String server : tmp)
  656. {
  657. if (server.equals(bindingName))
  658. continue;
  659. servers.put(server, ((RemoteInterface)registry.lookup(server)).s2sInterfaceFactory());
  660. }
  661. }
  662. shutdown();
  663. }
  664. }
  665. catch(NotBoundException e)
  666. {
  667. err.println("Error: " + e.getMessage()); /* this shouldn't happen */
  668. shutdown();
  669. }
  670. catch(RemoteException e)
  671. {
  672. err.println("Unable to lookup servers: " + e.getMessage());
  673. shutdown();
  674. }
  675. }
  676. }
  677. }
  678.  
  679. /*==========================================================================*/
  680.  
  681. public class Interactive
  682. extends CommandInteractive
  683. implements Runnable
  684. {
  685. private final InputStream sin;
  686. private final Object mainLock;
  687.  
  688. Interactive(InputStream sin, Object mainLock)
  689. throws NoSuchMethodException, IOException
  690. {
  691. this.sin = sin;
  692. this.mainLock = mainLock;
  693.  
  694. setIgnoreEmptyMode(false);
  695. cmdHandler.register("unknown", this, "cmdUnknown");
  696. }
  697.  
  698. /*------------------------------------------------------------------------*/
  699.  
  700. public void cmdUnknown(String cmd, String[] args)
  701. throws IOException
  702. {
  703. stop();
  704. }
  705.  
  706. /*------------------------------------------------------------------------*/
  707.  
  708. public void shutdown()
  709. {}
  710.  
  711. /*------------------------------------------------------------------------*/
  712.  
  713. public void run()
  714. {
  715. try
  716. {
  717. run(sin);
  718. }
  719. catch(CommandHandler.Exception e)
  720. {
  721. err.println("Internal Error: " + e.getMessage());
  722. }
  723. catch(IOException e)
  724. {
  725. /* ignore that exception
  726.   * thread will shutdown and unlock the main thread
  727.   * which will shutdown the application
  728.   */
  729. }
  730.  
  731. shutdown();
  732. synchronized(mainLock)
  733. {
  734. mainLock.notify();
  735. }
  736. }
  737. }
  738.  
  739. /*==========================================================================*/
  740.  
  741. private static String bindingName;
  742. private static boolean initRegistry;
  743. private static String[] serverNames;
  744. private static InputStream stdin = null;
  745. private static Thread tInteractive = null;
  746. private static ScheduledExecutorService scheduler = null;
  747. private static Registry registry = null;
  748. private static RemoteInterface riface = null;
  749. private static ServerRecords servers;
  750. public UserRecords users;
  751. public EventRecords events;
  752. public volatile boolean ready = false;
  753. private static final Object mainLock = new Object();
  754.  
  755. /*--------------------------------------------------------------------------*/
  756.  
  757. Server()
  758. {
  759. servers = new ServerRecords();
  760. users = new UserRecords();
  761. events = new EventRecords();
  762. }
  763.  
  764. /*--------------------------------------------------------------------------*/
  765.  
  766. public static void usage()
  767. throws Utils.Shutdown
  768. {
  769. out.println("Usage: Server bindingName initRegistry serverNames\n");
  770. out.println("bindingName\t...the name this server shall use to bind its remote");
  771. out.println("\t\t reference in the RMI registry");
  772. out.println("initRegistry\t...a boolean value, i.e. either true or false,");
  773. out.println("\t\t indicating whether this server is responsible for");
  774. out.println("\t\t creating the RMI registry or not");
  775. out.println("serverNames\t...a list of names, separated by space characters,");
  776. out.println("\t\t indicating the name of the other servers' remote references");
  777.  
  778. // Java is some piece of crap which doesn't allow me to set exitcode w/o
  779. // using System.exit. Maybe someday Java will be a fully functional
  780. // programming language, but I wouldn't bet my money
  781. //System.exit(1);
  782. throw new Utils.Shutdown("FUCK YOU JAVA");
  783. }
  784.  
  785. /*--------------------------------------------------------------------------*/
  786.  
  787. public void bailout(String error)
  788. throws Utils.Shutdown
  789. {
  790. if (error != null)
  791. err.println("Error: " + error);
  792. shutdown();
  793.  
  794. // Java is some piece of crap which doesn't allow me to set exitcode w/o
  795. // using System.exit. Maybe someday Java will be a fully functional
  796. // programming language, but I wouldn't bet my money
  797. //System.exit(2);
  798. throw new Utils.Shutdown("FUCK YOU JAVA");
  799. }
  800.  
  801. /*--------------------------------------------------------------------------*/
  802.  
  803. public void parseArgs(String[] args)
  804. {
  805. if (args.length != 3)
  806. usage();
  807.  
  808. bindingName = args[0];
  809. if (bindingName.length() == 0)
  810. bailout("bindingName is empty");
  811.  
  812. initRegistry = false;
  813. if (args[1].equals("true"))
  814. initRegistry = true;
  815. else if (args[1].equals("false"))
  816. initRegistry = false;
  817. else
  818. bailout("initRegistry must be either \"true\" or \"false\"");
  819.  
  820. serverNames = args[2].split(" ");
  821. if (Arrays.asList(serverNames).contains(bindingName))
  822. bailout("bindingName found in serverNames. You shouldn't do that!");
  823. }
  824.  
  825. /*--------------------------------------------------------------------------*/
  826.  
  827. public void createInterface()
  828. {
  829. String regHost = null;
  830. int regPort = 0;
  831.  
  832. try
  833. {
  834. InputStream in = ClassLoader.getSystemResourceAsStream("registry.properties");
  835. if (in == null)
  836. bailout("Properties file doesn't exist or isn't readable");
  837. Properties props = new Properties();
  838. props.load(in);
  839. for(String prop : props.stringPropertyNames())
  840. {
  841. if (prop.equals("registry.host"))
  842. regHost = props.getProperty(prop);
  843. else if (prop.equals("registry.port"))
  844. {
  845. try
  846. {
  847. regPort = Integer.parseInt(props.getProperty(prop));
  848. if (regPort <= 0 || regPort > 65536)
  849. {
  850. err.println("Property " + prop + " must be a valid port number (1 - 65535). Skipping...");
  851. regPort = 0;
  852. }
  853. }
  854. catch(NumberFormatException e)
  855. {
  856. err.println("Property " + prop + " must be numeric. Skipping...");
  857. }
  858. }
  859. else
  860. err.println("Property " + prop + " is unknown. Skipping...");
  861. }
  862. in.close();
  863. }
  864. catch(IOException e)
  865. {
  866. bailout("Unable to read from properties file: " + e.getMessage());
  867. }
  868.  
  869. if (!initRegistry && (regHost == null || regHost.length() <= 0))
  870. bailout("Registry host is not set");
  871. if (regPort == 0)
  872. bailout("Registry port is not set");
  873.  
  874. try
  875. {
  876. if (initRegistry)
  877. registry = LocateRegistry.createRegistry(regPort);
  878. else
  879. registry = LocateRegistry.getRegistry(regHost, regPort);
  880.  
  881. riface = new RemoteInterfaceImpl(this);
  882. //DEBUG RemoteServer.setLog(System.out);
  883. registry.bind(bindingName, riface);
  884. }
  885. catch(RemoteException e)
  886. {
  887. bailout("Unable to get/create registry: " + e.getMessage());
  888. }
  889. catch(AlreadyBoundException e)
  890. {
  891. registry = null;
  892. bailout("Unable to bind remote interface. Already bound: " + e.getMessage());
  893. }
  894.  
  895. out.println("Remote interface successfully exported!");
  896. }
  897.  
  898. /*--------------------------------------------------------------------------*/
  899.  
  900. public void writeData(String file)
  901. {
  902. if (file == null)
  903. return;
  904.  
  905. try
  906. {
  907. ObjectOutputStream sout = new ObjectOutputStream(new FileOutputStream(file));
  908. sout.writeObject(users);
  909. sout.writeObject(events);
  910. sout.close();
  911. }
  912. catch(FileNotFoundException e)
  913. {}
  914. catch(IOException e)
  915. {}
  916. }
  917.  
  918. /*--------------------------------------------------------------------------*/
  919.  
  920. public void readData(String file)
  921. {
  922. if (file == null)
  923. return;
  924.  
  925. try
  926. {
  927. ObjectInputStream sin = new ObjectInputStream(new FileInputStream(file));
  928. users = (UserRecords)sin.readObject();
  929. events = (EventRecords)sin.readObject();
  930. sin.close();
  931. }
  932. catch(ClassNotFoundException e)
  933. {}
  934. catch(FileNotFoundException e)
  935. {}
  936. catch(IOException e)
  937. {}
  938. }
  939.  
  940. /*--------------------------------------------------------------------------*/
  941.  
  942. public void shutdown()
  943. {
  944. for(String user : users.keySet())
  945. {
  946. UserRecord record = users.get(user);
  947. synchronized(record)
  948. {
  949. record.s2ciface = null;
  950. }
  951. }
  952.  
  953. try
  954. {
  955. if (scheduler != null)
  956. {
  957. scheduler.shutdownNow();
  958. scheduler.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
  959. }
  960. }
  961. catch(InterruptedException e)
  962. {}
  963.  
  964. try
  965. {
  966. if (riface != null)
  967. riface.unexportAll();
  968. }
  969. catch(RemoteException e)
  970. {}
  971.  
  972. try
  973. {
  974. if (registry != null)
  975. registry.unbind(bindingName);
  976. }
  977. catch(NotBoundException e)
  978. {}
  979. catch(RemoteException e)
  980. {}
  981.  
  982. try
  983. {
  984. if (tInteractive != null)
  985. {
  986. tInteractive.interrupt();
  987. tInteractive.join();
  988. }
  989. }
  990. catch(InterruptedException e)
  991. {}
  992.  
  993. try
  994. {
  995. if (stdin != null)
  996. stdin.close();
  997. }
  998. catch(IOException e)
  999. {}
  1000.  
  1001. //PERSISTENT writeData(bindingName + ".data");
  1002. }
  1003.  
  1004. /*--------------------------------------------------------------------------*/
  1005.  
  1006. public void run(String[] args)
  1007. {
  1008. boolean shutdown = false;
  1009.  
  1010. parseArgs(args);
  1011. //PERSISTENT readData(bindingName + ".data");
  1012.  
  1013. synchronized(mainLock)
  1014. {
  1015. createInterface();
  1016.  
  1017. try
  1018. {
  1019. InputStream stdin = java.nio.channels.Channels.newInputStream(
  1020. new FileInputStream(FileDescriptor.in).getChannel());
  1021. tInteractive = new Thread(new Interactive(stdin, mainLock));
  1022. tInteractive.start();
  1023. }
  1024. catch(NoSuchMethodException e)
  1025. {
  1026. bailout("Unable to setup interactive command handler");
  1027. }
  1028. catch(IOException e)
  1029. {
  1030. bailout("Unable to create object output stream: " + e.getMessage());
  1031. }
  1032.  
  1033. try
  1034. {
  1035. out.println("Waiting for the other servers to come online...");
  1036. scheduler = Executors.newScheduledThreadPool(1);
  1037. ScheduledFuture<?> waitServerTimer = scheduler.scheduleAtFixedRate(
  1038. new WaitForServers(), 0, 500, TimeUnit.MILLISECONDS);
  1039. mainLock.wait();
  1040. synchronized(servers)
  1041. {
  1042. if (!scheduler.isShutdown() || servers.size() != serverNames.length)
  1043. shutdown = true;
  1044. }
  1045. }
  1046. catch(InterruptedException e)
  1047. {
  1048. /* if we get interrupted -> ignore */
  1049. }
  1050.  
  1051. if (!shutdown)
  1052. {
  1053. ready = true;
  1054. out.println("Server startup successful!");
  1055. try
  1056. {
  1057. mainLock.wait();
  1058. }
  1059. catch(InterruptedException e)
  1060. {
  1061. /* if we get interrupted -> ignore */
  1062. }
  1063. }
  1064. }
  1065.  
  1066. out.println("Shutting down...");
  1067. shutdown();
  1068. }
  1069.  
  1070. /*--------------------------------------------------------------------------*/
  1071.  
  1072. public static void main(String[] args)
  1073. {
  1074. try
  1075. {
  1076. Server srv = new Server();
  1077. srv.run(args);
  1078. }
  1079. catch(Utils.Shutdown e)
  1080. {}
  1081. }
  1082. }
  1083.