第一部分:项目描述文档
Collaborative real-time editors, like and , allow multiple users to edit a file simultaneously. These applications are usually web-based and allow different users on different computers to easily login and edit the same file at the same time.
Such editors can be divided into two main components: the clients and the server. Each user is associated with one client program that accepts their operations. Client programs then pass the operations to the server, which continuously receives and processes the operations from all the users in time order to keep the document updated. Operations include undo and redo for each user.
In this program, your task is to simulate the server of a simplified collaborative spreadsheet. Each document is a fixed-size spreadsheet table where each cell (i.e., element) is an integer. In this program specification, we'll use the term "document" and "table" interchangeably. The simulation works as follows:
- The program opens and reads the input file containing a list of document descriptions followed by a time-ordered list of operations done by the users.
- The program uses the list of document descriptions to initialize the database of documents that's initially empty.
- The program then reads each operation, modifies the database of documents accordingly, and outputs the result of the operation to an output file.
第二部分:sampleInput.txt
3
doc1,5,5,user1,user2doc2,3,5,user3,user2doc3,3,4,user4,user5,user112345,user1,doc1,set,1,3,212360,user2,doc1,set,1,4,312365,user1,doc1,clear,1,312370,user2,doc1,undo12371,user2,doc1,redo12373,user1,doc1,undo14310,user3,doc2,set,1,1,314321,user2,doc2,add,1,1,414330,user3,doc2,undo14333,user3,doc2,redo14334,user2,doc2,undo第三部分:sampleOutput.txt
----------Update Database----------
12345 doc1 user1 set [1,3] 2Document Name: doc1 Size: [5,5]
Table: 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0----------Update Database----------
12360 doc1 user2 set [1,4] 3Document Name: doc1 Size: [5,5]
Table: 0 0 0 0 0 0 0 0 2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0----------Update Database----------
12365 doc1 user1 clear [1,3]Document Name: doc1 Size: [5,5]
Table: 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0----------Update Database----------
12370 doc1 user2 undoDocument Name: doc1 Size: [5,5]
Table: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0----------Update Database----------
12371 doc1 user2 redoDocument Name: doc1 Size: [5,5]
Table: 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0----------Update Database----------
12373 doc1 user1 undoDocument Name: doc1 Size: [5,5]
Table: 0 0 0 0 0 0 0 0 2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0----------Update Database----------
14310 doc2 user3 set [1,1] 3Document Name: doc2 Size: [3,5]
Table: 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0----------Update Database----------
14321 doc2 user2 add [1,1] 4Document Name: doc2 Size: [3,5]
Table: 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0----------Update Database----------
14330 doc2 user3 undoDocument Name: doc2 Size: [3,5]
Table: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0----------Update Database----------
14333 doc2 user3 redoDocument Name: doc2 Size: [3,5]
Table: 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0----------Update Database----------
14334 doc2 user2 undoDocument Name: doc2 Size: [3,5]
Table: 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0附录1 项目描述:
Overview
Goals
The goals of this program are to:
- Understand the Stack and Queue ADTs.
- Implement the Stack ADT.
- Implement the Queue ADT.
- Gain more experience writing generic classes that implement Java interfaces.
- Complete an application that uses stacks and queues.
Description
Collaborative real-time editors, like and , allow multiple users to edit a file simultaneously. These applications are usually web-based and allow different users on different computers to easily login and edit the same file at the same time.
Such editors can be divided into two main components: the clients and the server. Each user is associated with one client program that accepts their operations. Client programs then pass the operations to the server, which continuously receives and processes the operations from all the users in time order to keep the document updated. Operations include undo and redo for each user.
In this program, your task is to simulate the server of a simplified collaborative spreadsheet. Each document is a fixed-size spreadsheet table where each cell (i.e., element) is an integer. In this program specification, we'll use the term "document" and "table" interchangeably. The simulation works as follows:
- The program opens and reads the input file containing a list of document descriptions followed by a time-ordered list of operations done by the users.
- The program uses the list of document descriptions to initialize the database of documents that's initially empty.
- The program then reads each operation, modifies the database of documents accordingly, and outputs the result of the operation to an output file.
Specifications
Program Flow
The main method of the program is in the Server class. At the start of the Server main program, a Database object is constructed, which stores the server's collection of documents. Next, the server opens an input file containing document descriptions and operations (see below). The server reads the number of document descriptions, makes a Document object for each document description, and adds each Document object to the database. When a document is constructed, you must also create a User object for every user that is listed for that document. User objects track a user's operations on that document. A new User object must be constructed for each user for each document.
After the Document objects and associated User objects have been processed, then the server creates a Queue object to store the operations listed on the subsequent lines of the input file. Each operation is read and added to the queue as an Operation object. Note that in real life, users may continuously enqueue operations as the server dequeues operations at the same time. In this program, for simplicity, we assume all the operations are received at the beginning.
After the input file is processed by the program, the server applies each operation in he queue to the appropriate document in the database. The server dequeues an operation, calls the update method on the database passing the operation. The database applies the changes to the document (i.e., the table), and also modifies the users involved to track their operations on undo and redo stacks (see below). These stacks are used by the undo and redo operations. After the server applies an operation to update the database, it then writes to the output file the updated table by getting the document from the database and using document's toString method. The output file's format is described below (see below). The output file will be used to determine if your program performed the right changes for each operation. Your program opens the output file at the beginning of main and closes it once you are done applying all the operations in the queue.
Input File
is a sample input file.
The name of the input file processed by your program is provided as a command-line argument. You may assume the format of input files will be valid. The first line has only one integer corresponding to the number of document descriptions. Each of the following lines are document descriptions and you may assume that the number of document description lines is the same as the integer on the first line. Each document description line provides the document name, its table size and which users have the access. The format used is:
<document name>,<number of rows>,<number of columns>,<list of participating users separated by commas>
as in this example:
doc3,3,4,user4,user5,user1
Note: Documents are of fixed size. Users cannot expand the spreadsheet table or write in a cell outside of the table boundaries. Also, when the table is created, all the cells should be initialized to 0.
After the document descriptions is a list of operations in this format:
<timestamp>,<user responsible for operation>,<document name>,<operation>,<any required input separated by commas>
The timestamp is the time when this operation is received, which is a long integer that is number of seconds that have elapsed since January 1, 1970. Operations are described in the next section.
Operations
The supported operations (specified in the Operation class below) have the following formats.(timestamp, user, and document name are not shown here) Note 0-based indexing is used for row and col indexes.
- Setting the value of a cell at [row, col].
- set,<row>,<col>,<new value>
- clear,<row>,<col>
- add,<row>,<col>,<number to add to specified cell value>
- sub,<row>,<col>,<number to subtract from specified cell value>
- mul,<row>,<col>,<number to multiply with specified cell value>
- div,<row>,<col>,<number to divide current specified cell value by>
- undo
- redo
More about Undo and Redo
The behaviors of undo and redo are more complicated when there are multiple users. We'll implement an approach, like done in Google Spreadsheets, where a user can only undo or redo their own operations. For example (in time order):
- initially table[1,1] = 0.
- user1 set table[1,1] = 2;
- user2 set table[1,1] = 3;
- user1 undo -> table[1,1] = 0 (the value before user1’s operation)
- user2 undo -> table[1,1] = 2 (the value before user2’s operation)
- user1 redo -> table[1,1] = 3 (the value before user1 undo. Note that the value is not 2. Redo will change the cell back to its value before his/her last undo.)
Whenever a new action is taken, the user cannot redo any operation. For example,
- initially table[1,1] = 0.
- user1 set table[1,1] = 2;
- user1 undo -> table[1,1] = 0 (the value before user1's operation)
- user1 set table[4,3] = 5;
- user1 should not be able to redo anything after the previous operation, since the user set the value of [4,3] to 5. (Note that this is somewhat different from what Google Spreadsheet does. In Google spreadsheet, after you set table[4,3] = 5, then move to table[2,3] and click redo, you will set table[2,3] = 5. As no cell is specified for undo and redo operation in this program, we don’t support this behavior.)
Try using Google Spreadsheet if you'd like to familiarize yourself with this approach.
In order to implement undo and redo, a WAL class (specified below) is used. For each operation, you'll create one WAL object, which stores which cell is changed and what the old value of that cell is. For each user, you should have one WAL stack for undo and one WAL stack for redo (remember each user can only redo and undo their own operation). For all operations except undo, you should create the corresponding WAL object and push it into the undo stack. For undo operation, you should pop the top WAL object from the undo stack, reset the cell value, create a new WAL for this change and push it into the redo stack. For redo operation, you should pop the top WAL object from the redo stack, reset the cell value, create a new WAL and push it into the undo stack.
Output File
is a sample output file.
The name of the output file produced by your program is provided as a command-line argument. It will contain the content of each document after each operation is applied. Write the updated document to the output file after each operation. For each operation, the output should contains three parts: Header, Operation Description, Document Content as specified below.
Header: First line with 10 ‘-’ before and after the text:
----------Update Database----------
Operation Description: Depends of the kind of operations. This should be the return string of toString() method in Operation class. (note “\t” is a tab):
For ADD,SUB,MUL,DIV,SET:
<timestamp>\t<document name>\t<user>\t<op>\t[<Row Index>,<Col Index>]\t<Constant>
For CLEAR:
<timestamp>\t<document name>\t<user>\t<op>\t[<Row Index>,<Col Index>]
For UNDO,REDO:
<timestamp>\t<document name>\t<user>\t<op>
Document Content: This should be the return string of toString() method in Document class. Itis specified as:
Document Name: <document name>\tSize: [<Row Size>,<Col Size>]
Table:
<cell>\t<cell>\t…<cell>
<cell>\t<cell>\t…<cell>
…
<cell>\t<cell>\t…<cell>
Classes and Interfaces
You can only assume the input file is in a valid format, but you should handle all the other input validation, e.g. bound checking, access validation and so on.
The StackADT<E> Interface
A StackADT<E> interface provided to you (see ), is a generic interface that you will implement in your SimpleStack class. The interface specifies the following methods:
Method | Description |
void push(E item) | Adds item to the top of the Stack. If item is null, an IllegalArgumentExceptionis thrown. |
E pop() | Removes the item on the top of the Stack and returns it. If the Stack is empty, an EmptyStackException is thrown. |
E peek() | Returns the item on top of the Stack without removing it. If the Stack is empty, an EmptyStackException is thrown. |
boolean isEmpty() | Returns true iff the Stack is empty. |
void clear() | Removes all items in the stack leaving an empty Stack. |
int size() | Returns the number of items in the Stack. |
Do not modify the StackADT interface in any way.
The SimpleStack<E> Class
A SimpleStack<E> implements StackADT<E> interface (see . You must use this class for your implementation of undo and redo operations.
The data structure used by your stack implementation may be an expandable array or a chain of listnodes. You may NOT use Java's predefined classes such as ArrayList or LinkedList.
Do not add any public methods or public fields to your SimpleStack class other than those already provided.
The QueueADT<E> Interface
A QueueADT<E> interface provided to you (see ), is a generic interface that you will implement in your SimpleQueue class. The interface specifies the following methods:
Method | Description |
void enqueue(E item) | Adds item to the rear of the Queue. If item is null, an IllegalArgumentException is thrown. |
E dequeue() | Removes an item from the front of the Queue and returns it. If the Queue is empty, an EmptyQueueException is thrown. |
E peek() | Returns the item at front of the Queue without removing it. If the Queue is empty, an EmptyQueueException is thrown. |
boolean isEmpty() | Returns true iff the Queue is empty. |
void clear() | Removes all items in the queue leaving an empty queue. |
int size() | Returns the number of items in the Queue. |
Do not modify the QueueADT interface in any way.
The SimpleQueue<E> Class
The SimpleQueue<E> implements Queue<E> interface (see . You must use this class for your implementation of the Server class to store the queue of operations read from the input file.
The data structure used by your queue implementation may be an expandable circular array or a chain of listnodes. You may NOT use Java's predefined classes such as ArrayList or LinkedList.
Do not add any public methods or public fields to your SimpleQueue class other than those already provided.
The EmptyStackException and EmptyQueueException classes
The EmptyStackExcpetion and the EmptyQueueExcpetion classes are provided for you (see , ) as unchecked exceptions, which you'll use for your SimpleStack and SimpleQueue classes.
Do not modify the EmptyStackException or the EmptyQueueException classes in any way.
The Operation Class
A Operation class is provided to you (see ); you are expected to complete those sections of it marked as "//TODO". The Operation class represents a single change in the database. A change might include creating a table, undo, addition, etc. There is an enum OP defined in this file, which represents all the possible operations that can be done. The Operation class has the constructor(s) and methods below.
Do not add any other public methods or constructors than those listed below.
Constructor | Description |
Operation(String docName,String userId, OP op, int rowIndex, int colIndex, int constant, long timestamp) | This constructor is for operations that involve only one cell (i.e. incrementing cell[rowIndex, colIndex] by a constant). Throws IllegealArgumentException if op is not supported, or arguments are not valid. |
Operation(String docName,String userId, OP op, int rowIndex, int colIndex, long timestamp) | This constructor is for operations without constant(i.e. clear).Throws IllegealArgumentException if op is not supported, or arguments are not valid. |
Operation(String docName,String userId, OP op, long timestamp) | This constructor is for operations that involve a document as a whole (i.e. undo previous action).Throws IllegealArgumentException if op is not supported, or arguments are not valid. |
Method | Description |
String getUserID() | Returns the user ID. |
OP getOp() | Returns the operator of this operation. |
String getDocName() | Returns the document Name. |
int getRowIndex() | Returns the row that is involved. Returns -1 if this operation does not involve a cell. |
int getColIndex() | Returns the column that is involved. Returns -1 if this operation does not involve a cell. |
int getConstant() | Returns the constant that is involved. Returns -1 if this operation does not involve a cell. |
long getTimestamp() | Returns the timestamp of this operation. |
String toString() | Returns the string representation of this operation. This method should be called forOperation Description part in output. |
The WAL Class
A WAL() class is provided to you(see ); you are expected to complete those sections of it marked as "//TODO". The WAL class represents the state before any operation performed. This is used to undo and redo any operation. For example, user1 changes the value of table[i][j] from a to b, then we need to create a WAL object to record which cell is changed, i.e. row index is i and col index is j, and what the previous value is, i.e. a. Later on, if the user undoes this operation, we can restore this cell based on this WAL object.
Do not add any other public methods or constructors than those listed below.
Constructor | Description |
WAL(int rowIndex, int colIndex, int oldValue) | Creates a WAL, which records what the old value is before an operation. Throws IllegalArgumentException if any argument is invalid. |
Method | Description |
int getOldValue() | Returns the old value. |
int getRowIndex() | Returns the row index. |
int getColIndex() | Returns the col index. |
The Document Class
A Document class is provided to you (see ); you are expected to complete those sections of it marked as "//TODO". The Document class represents a single document, i.e. a 2-d numeric table, in the database. It stores all the users involved in this document and keeps track of the actual data in a two-dimensional array. The Document class has the constructor(s) and methods below.
Do not add any other public methods or constructors than those listed below.
Constructor | Description |
Document(String docName, int rowSize, int colSize, List<User> users) | Creates a document with rowSize * colSize table and a list of users. Throws IllegalArgumentException if any argument is invalid. |
Method | Description |
List<String> getAllUserIds() | Returns the user IDs for this document. You may or may not use this method in your program. |
String getDocName() | Returns the document Name. |
void update(Operation operation) | Applies the input operation to the document. Throws a IllegalArgumentException if the operation is not valid. |
User getUserByUserId() | Returns the user of this document by user id. Returns null if there is no such user for this document. |
int getCellValue(int rowIndex, int colIndex) | Returns the value of the cell specified by the given row index and col index. Throws IllegalArgumentException if the index is out of bound. You may or may not use this method in your program. |
String toString() | Returns the string representation of this document. This method should be called forDocument Content part in output. |
The User Class
A user class is provided to you(see ). you are expected to complete those sections of it marked as "//TODO". The User class represents the user state for a specific document.
Do not add any other public methods or constructors than those listed below.
Constructor | Description |
User(String userId) | Creates a User. Throws IllegalArgumentException is userId is invalid. |
Method | Description |
WAL popWALForUndo() | Returns the top WAL for undo. If there is no such WAL, returns null. |
WAL popWALForRedo() | Returns the top WAL for redo. If there is no such WAL, returns null. |
void pushWALForUndo(WAL wal) | Pushes the WAL into undo stack. Throws IllegalArgumentException if wal is null. |
void pushWALForRedo(WAL wal) | Pushes the WAL into redo stack. Throws IllegalArgumentException if wal is null. |
void clearAllRedoWAL() | Clear all redo WALs. |
void clearAllUndoWAL() | Clear all undo WALs. |
String getUserId() | Returns the user id. |
The Database Class
A Database class is provided to you (see ); you are expected to complete those sections of it marked as "//TODO". The Database class represents a single database on the server. For the purposes of this project, there is only one database object. It keeps track of all the documents on the server, and it is responsible for propagating updates to individual documents. The Database class has the constructor(s) and methods below.
Do not add any other public methods or constructors than those listed below.
Constructor | Description |
Database() | Creates an empty database. |
Method | Description |
void addDocument(Document doc) | Adds one document to database. Throws IllegalArgumentException if doc is invalid. |
List<Document> getDocumentList() | Returns the list of documents in the database. |
String update(Operation operation) | Applies the given operation to the database. Returns the formatted string representation of the updated document content. Throw IllegalArgumentException if the operation is invalid, e.g. the document is not in the database. |
Document getDocumentByDocumentName(String docName) | Returns one document based on document id. Returns nullif there is no such document in the database. |
The Server Main Class
A Server class is provided to you (see ); you are expected to complete those sections of it marked as “//TODO”. The Server class represents the high level server. It opens the input file and parses it. As it is parsing each line, it creates a Operation object and inserts the Operation into a queue. Once the entire file is parsed, the server takes Operations out of the queue one at a time and applies them to the database.This class contains the main method, you should run your program from here.
Do not add any other public methods or constructors than those listed below.
Constructor | Description |
Server(String inputFileName, String outputFileName) | Creates a new server with the given input file name and output file name |
Method | Description |
void run() | Run the server. This method will call initialize and process method sequently. |
void initialize() | Initializes the server based on the information from the input file. This is where you create document objects and queue all operations in the input file |
void process() | Processes each operation. Once you have queued all operations, you begin extracting one operation from the operation queue one at a time, updating the database and logging everything to the output file. |