Exam Rules

  1. [8 points] Draw a class diagram from your project that contains at least four classes not contained in the standard Violet distribution (and up to four classes from the standard Violet distribution if desired) and that truthfully demonstrates inheritance, interface inheritance, aggregation, and dependency. Submit a file problem1.violet.
  2. [12 points] Consider the UndoViolet and CollabViolet teams. Each of them benefited by having a Command interface to represent commands in Violet such as adding a node, joining nodes by an edge, removing a node, removing an edge, changing the position of a node, or changing a property of a node or edge. In the case of CollabViolet, these commands would be replayed on another machine. That is, a Command would have a method void do() to execute the command. In the case of UndoViolet, there would also be a method void undo() to undo the command. For example, the undo of adding a node is removing the node, and the undo of changing a node property is to set it back to its original value. Place your answer to this question in a file problem2.txt.
    1. Explain why this is or is not an example of the Strategy design pattern.
    2. Sometimes, it is beneficial to combine a sequence of several commands into one. For example, consider what happens when one draws an arrow in a sequence diagram from an activation bar to an implicit parameter node. At the destination, a new activation bar node is inserted. (Try it out in Violet if you are unsure about this phenomenon.) This command is best represented as the sequence of two commands: Insert the activation bar node, and join the two activation bar nodes with a call edge. Of course, the do method of a CommandSequence invokes the do methods of each of the commands in the seqence. The undo method of a CommandSequence invokes the undo methods of each of the commands in the seqence in reverse order. Explain why this is or is not an example of the Composite design pattern.
  3. [8 points] Copy/paste the following questions into a file problem3.txt. Mark each of the following by placing an X inside the [] following True or False
    1. Both VioletDroid teams demonstrated their app on an Android tablet. True [ ] / False [ ]
    2. Both CollabDroid teams demonstrated sharing of class and sequence diagrams. True [ ] / False [ ]
    3. Both the RoundTripViolet and VioletFX teams achieved most of their project goals. True [ ] / False [ ]
    4. Both the UndoViolet and ASCIIViolet teams used the Violet code for drawing shapes. True [ ] / False [ ]
  4. [20 points] Consider the BoxedShapeIterator class from Homework 6. Suppose we make a shape
    Shape s = new BoxedShape(new Ellipse2D.Double(105, 110, 20, 30), 10);
    Assume that in the call
    g2.draw(s);
    the following code will be executed:
    PathIterator iter = s.getPathIterator(transform);
    while (!iter.isDone())
    {
       double[] coords = new double[6];
       int type = iter.currentSegment(coords);
       // Draw the segment with the given type and coordinates
       iter.next();
    }
    
    Draw a sequence diagram of this scenario that shows how iteration over a boxed shape works. Be sure to show how the path iterator of the ellipse is accessed. Submit a file problem4.violet.

    Note that there are five objects: g2, s, iter, iter.shape, and iter.iter. Indicate their exact type if you (should) know it and leave it blank if the exact type is indeed unknown.

    In UML, there is no great way of indicating the work that goes on during object construction. First make a “create” arrow to make the iterator object that will be assigned to iter.iter, then make a second arrow for the work in the constructor.

    iter yields five segments for the box, and then five segments for the ellipse. Use a note to indicate the repetition.

    Note that this question has a lot of points, but only for the right steps. Make sure you show me not just the calls to the highlighted methods, but also what methods they call.

  5. [8 points] Make the BoxedShape cloneable and serializable. Your clone method should have return type BoxedShape. Note that most classes implementing Shape are both cloneable and serializable, but some are not (for example, Polygon, Path2D). If the underlying Shape is not cloneable, the clone method should throw a CloneNotSupportedException. If the underlying shape is not serializable, the ObjectOutputStream.writeObject method should throw an IOException. Add the file BoxedShape.java to your final directory.
  6. [14 points] Make a copy of the ch08/graphed2 directory in the book code into a directory problem6. Add a DiamondNode class, and update the SimpleGraph class so that the SimpleGraphEditor can edit graphs consisting of black and white circles and diamonds with a black outline and and blank interiors. (Diamonds don't have a color.) In the draw method, generate four Line2D.Double objects and draw them. In the Node class, make contains into a default method so that a node contains a point if its bounds do. Edges should attach at one of the four corner points of a diamond. Hint: Compute dx and dy as with the circle node, and note that the lines dx = dy and dx = -dy bisect the plane into four areas that tell you which connection point to use.

    Don't sweat the details too much if you are short on time. There are a lot of points to be had in the next question.
  7. [17 points] Suppose you want to find palindromic squares; that is numbers that are squares and whose digits (in base 10) are the same as their reverse. An example is 2642 = 69696. We will split an interval of numbers to be squared into n parts, to be processed concurrently. For each of the following strategies, state whether it works correctly or not, and if it doesn't, explain why. Assume all code compiles. Note that we use Callable<Void> instead of Runnable so we don't have to catch any InterruptedException in the body of the lambda. Put your response in a file problem7.txt.
    1. List<BigInteger> r = new ArrayList<>();
      BigInteger start = ...;
      long length = ...;
      int n = ...;
      ExecutorService service = ...;
      for (int i = 0; i < n; i++)
      {
         long from = i * length / n; 
         long to = (i + 1) * length / n;
      
         Callable<Void> task = () ->
            {
               for (long j = from; j < to; j++)
               {
                  BigInteger a = start.add(BigInteger.valueOf(j)).pow(2);
                  if (isPalindrome(a)) r.add(a);
               }
               return null;
            };
         service.submit(task);
      }
      // Wait until all tasks have finished
      // All results are now in r
      
    2. List<BigInteger> r = new LinkedList<>();
      Lock lock = new ReentrantLock();
      BigInteger start = ...;
      long length = ...;
      int n = ...;
      ExecutorService service = ...;
      for (int i = 0; i < n; i++)
      {
         long from = i * length / n; 
         long to = (i + 1) * length / n;
      
         Callable<Void> task = () ->
            {
               for (long j = from; j < to; j++)
               {
                  BigInteger a = start.add(BigInteger.valueOf(j)).pow(2);
                  if (isPalindrome(a))
                  {
                     lock.lock();
                     r.add(a);
                     lock.unlock();
                  }
               }
               return null;
            };
         service.submit(task);
      }
      // Wait until all tasks have finished
      // All results are now in r
      
    3. List<BigInteger> r = new LinkedList<>();
      BigInteger start = ...;
      long length = ...;
      int n = ...;
      ExecutorService service = ...;
      for (int i = 0; i < n; i++)
      {
         long from = i * length / n; 
         long to = (i + 1) * length / n;
      
         Callable<Void> task = () ->
            {
               Lock lock = new ReentrantLock();
               for (long j = from; j < to; j++)
               {
                  BigInteger a = start.add(BigInteger.valueOf(j)).pow(2);
                  if (isPalindrome(a))
                  {
                     lock.lock();
                     r.add(a);
                     lock.unlock();
                  }
               }
               return null;
            };
         service.submit(task);
      }
      // Wait until all tasks have finished
      // All results are now in r
      
    4. BlockingQueue<BigInteger> r = new LinkedBlockingQueue<>();
      BigInteger start = ...;
      long length = ...;
      int n = ...;
      ExecutorService service = ...;
      for (int i = 0; i < n; i++)
      {
         long from = i * length / n; 
         long to = (i + 1) * length / n;
      
         Callable<Void> task = () ->
            {
               for (long j = from; j < to; j++)
               {
                  BigInteger a = start.add(BigInteger.valueOf(j)).pow(2);
                  if (isPalindrome(a))
                  {
                     r.put(a);
                  }
               }
               return null;
            };
         service.submit(task);
      }
      // Wait until all tasks have finished
      // All results are now in r
      
    5. Map<Long, BigInteger> r = new HashMap<>();
      BigInteger start = ...;
      long length = ...;
      int n = ...;
      ExecutorService service = ...;
      for (int i = 0; i < n; i++)
      {
         long from = i * length / n; 
         long to = (i + 1) * length / n;
      
         Callable<Void> task = () ->
            {
               for (long j = from; j < to; j++)
               {
                  BigInteger a = start.add(BigInteger.valueOf(j)).pow(2);
                  if (isPalindrome(a))
                  {
                     r.put(j, a);
                  }
               }
               return null;
            };
         service.submit(task);
      }
      // Wait until all tasks have finished
      // All results are now in r.values()
      
    6. Map<Long, BigInteger> r = new ConcurrentHashMap<>();
      BigInteger start = ...;
      long length = ...;
      int n = ...;
      ExecutorService service = ...;
      for (int i = 0; i < n; i++)
      {
         long from = i * length / n; 
         long to = (i + 1) * length / n;
      
         Callable<Void> task = () ->
            {
               for (long j = from; j < to; j++)
               {
                  BigInteger a = start.add(BigInteger.valueOf(j)).pow(2);
                  if (isPalindrome(a))
                  {
                     r.putIfAbsent(j, a);
                  }
               }
               return null;
            };
         service.submit(task);
      }
      // Wait until all tasks have finished
      // All results are now in r.values()
      
    7. List<BigInteger> r = new ArrayList<>();
      BigInteger start = ...;
      long length = ...;
      int n = ...;
      ExecutorService service = ...;
      List<Future<List<BigInteger>>> futures = new ArrayList<>();
      for (int i = 0; i < n; i++)
      {
         long from = i * length / n; 
         long to = (i + 1) * length / n;
      
         Callable<List<BigInteger>> task = () ->
            {
               List<BigInteger> rtask = new ArrayList<>();
               for (long j = from; j < to; j++)
               {
                  BigInteger a = start.add(BigInteger.valueOf(j)).pow(2);
                  if (isPalindrome(a)) rtask.add(a);
               }
               return rtask;
            };
         futures.add(service.submit(task));
      }
      for (Future<List<BigInteger>> f : futures)
         r.addAll(f.get());
      // All results are now in r