001package edu.pdx.cs.joy.family;
002
003import org.junit.jupiter.api.AfterEach;
004import org.junit.jupiter.api.Assertions;
005import org.junit.jupiter.api.BeforeEach;
006import org.junit.jupiter.api.io.TempDir;
007
008import java.io.File;
009import java.io.PrintWriter;
010import java.io.StringWriter;
011import java.rmi.RemoteException;
012import java.rmi.registry.LocateRegistry;
013import java.rmi.registry.Registry;
014import java.util.Calendar;
015import java.util.Date;
016
017import static org.junit.jupiter.api.Assertions.assertNotNull;
018
019
020/**
021 * This is the abstract superclass for all of the remote family
022 * tree tests.
023 */
024public abstract class RemoteTestCase {
025
026  /** The port on which the RMI registry runs */
027  private static final int RMI_PORT =
028    Integer.getInteger("RMI_PORT", 1999).intValue();
029
030  /** An RMI Registry that is co-located in the VM in which the test
031   * runs */
032  private static Registry registry;
033
034  /** The name of this test */
035  private String name = "RemoteTestCase" + System.currentTimeMillis();
036
037    /**
038   * Creates an empty <code>RemoteFamilyTree</code> and binds it into
039   * the RMI namespace.
040   */
041  @BeforeEach
042  public void setUp(@TempDir File tempDir) {
043    try {
044      File file = new File(tempDir, "familyTree.xml");
045      file.delete();
046      file.deleteOnExit();
047      RemoteFamilyTree tree = new XmlRemoteFamilyTree(file);
048      this.bind(tree);
049
050    } catch (Exception ex) {
051      fail("While getting creating remote family tree", ex);
052    }
053  }
054
055  /**
056   * Unbinds the remote family tree from the RMI namespace
057   */
058  @AfterEach
059  public void tearDown() {
060    this.unbind();
061  }
062
063  /**
064   * Returns the name that the <code>RemoteFamilyTree</code> is bound
065   * into in the RMI namespace.
066   */
067  protected String getFamilyName() {
068    return "RemoteTestCase";
069  }
070
071  /**
072   * Returns an RMI registry that is co-located in this VM.  If one
073   * doesn't exist, it is started on {@link #RMI_PORT}
074   */
075  private Registry getRegistry() {
076    if (registry != null) {
077      return registry;
078    }
079
080    synchronized (RemoteTestCase.class) {
081      if (registry != null) {
082        return registry;
083      }
084
085      try {
086        registry = LocateRegistry.createRegistry(RMI_PORT);
087
088      } catch (RemoteException ex) {
089        try {
090          registry = LocateRegistry.createRegistry(RMI_PORT);
091
092        } catch (RemoteException ex1) {
093          fail("Couldn't create local registry", ex);
094        }
095      }
096
097      assertNotNull(registry);
098      return registry;
099    }
100  }
101
102  /**
103   * Returns the <code>RemoteFamilyTree</code> used by this test
104   */
105  protected RemoteFamilyTree getTree() {
106//     if (System.getSecurityManager() == null) {
107//       System.setSecurityManager(new RMISecurityManager());
108//     }
109
110    Registry registry = getRegistry();
111    try {
112      return (RemoteFamilyTree) registry.lookup(this.getName());
113
114    } catch (Exception ex) {
115      fail("While getting remote family tree on " + this.getName(), ex);
116      return null;
117    }
118  }
119
120  /**
121   * Convenience method that binds a given
122   * <code>RemoteFamilyTree</code> into the RMI namespace.
123   */
124  protected void bind(RemoteFamilyTree tree) {
125//     if (System.getSecurityManager() == null) {
126//       System.setSecurityManager(new RMISecurityManager());
127//     }
128
129    Registry registry = getRegistry();
130    try {
131      registry.rebind(this.getName(), tree);
132      System.out.println("Successfully bound RemoteFamilyTree");
133
134    } catch (Exception ex) {
135      fail("While getting remote family tree on " + this.getName(), ex);
136    }
137  }
138
139  /**
140   * Convenience method that unbinds and shuts down the remote family
141   * tree from the RMI namespace.
142   */
143  protected void unbind() {
144//     if (System.getSecurityManager() == null) {
145//       System.setSecurityManager(new RMISecurityManager());
146//     }
147
148    Registry registry = getRegistry();
149    try {
150      RemoteFamilyTree tree = 
151        (RemoteFamilyTree) registry.lookup(this.getName());
152      tree.shutdown();
153      registry.unbind(this.getName());
154      System.out.println("Successfully unbound RemoteFamilyTree");
155
156    } catch (Exception ex) {
157      fail("While getting remote family tree on " + this.getName(), ex);
158    }
159  }
160
161  private String getName()
162  {
163    return name;
164  }
165
166    /**
167   * Asserts the equality of two dates.  Only takes the month, day,
168   * and year into account.
169   */
170  protected void assertEquals(Date d1, Date d2) {
171    Calendar cal1 = Calendar.getInstance();
172    cal1.setTime(d1);
173
174    Calendar cal2 = Calendar.getInstance();
175    cal1.setTime(d2);
176
177    Assertions.assertEquals(cal1.get(Calendar.DAY_OF_YEAR),
178                 cal2.get(Calendar.DAY_OF_YEAR));
179    Assertions.assertEquals(cal1.get(Calendar.YEAR), cal2.get(Calendar.YEAR));
180  }
181
182  /**
183   * A JUnit failure that is caused by an exception.  This method
184   * provides us with a nice strack trace for the failure.
185   *
186   * @since Winter 2004
187   */
188  public static void fail(String message, Throwable cause) {
189    StringWriter sw = new StringWriter();
190    sw.write(message);
191    sw.write("\nCaused by: ");
192
193    PrintWriter pw = new PrintWriter(sw, true);
194    cause.printStackTrace(pw);
195    Assertions.fail(sw.toString());
196  }
197
198}