Java程序辅导

C C++ Java Python Processing编程在线培训 程序编写 软件开发 视频讲解

客服在线QQ:2653320439 微信:ittutor Email:itutor@qq.com
wx: cjtutor
QQ: 2653320439
Assignment Two starter code and specs (41d82cf9) · Commits · comp6700 / comp6700-2017 · GitLab Skip to content Projects Groups Snippets Help Loading... Help Support Keyboard shortcuts ? Submit feedback Contribute to GitLab Sign in Toggle navigation C comp6700-2017 Project overview Project overview Details Activity Releases Repository Repository Files Commits Branches Tags Contributors Graph Compare Issues 0 Issues 0 List Boards Labels Milestones Analytics Analytics Repository Value Stream Wiki Wiki Members Members Collapse sidebar Close sidebar Activity Graph Create a new issue Commits Issue Boards Open sidebar comp6700 comp6700-2017 Commits 41d82cf9 Commit 41d82cf9 authored Apr 23, 2017 by Alexei Khorev Browse files Options Browse Files Download Email Patches Plain Diff Assignment Two starter code and specs parent 5684602b Changes 14 Hide whitespace changes Inline Side-by-side Showing 14 changed files with 797 additions and 0 deletions +797 -0 ass2/Makefile ass2/Makefile +34 -0 ass2/README.md ass2/README.md +202 -0 ass2/data_stream.json ass2/data_stream.json +30 -0 ass2/doc_args ass2/doc_args +4 -0 ass2/images/full_app.png ass2/images/full_app.png +0 -0 ass2/images/vanilla_app.png ass2/images/vanilla_app.png +0 -0 ass2/src/Controller.java ass2/src/Controller.java +10 -0 ass2/src/RunningHeadline.java ass2/src/RunningHeadline.java +182 -0 ass2/src/model/Feeder.java ass2/src/model/Feeder.java +112 -0 ass2/src/model/Message.java ass2/src/model/Message.java +66 -0 ass2/src/model/MessageParser.java ass2/src/model/MessageParser.java +91 -0 ass2/src/view/display-1.fxml ass2/src/view/display-1.fxml +52 -0 ass2/src/view/display.fxml ass2/src/view/display.fxml +8 -0 ass2/src/view/styles.css ass2/src/view/styles.css +6 -0 No files found. ass2/Makefile 0 → 100644 View file @ 41d82cf9 SOURCES = $(wildcard src/*.java src/*/*.java) all: compile doc compile: $(SOURCES) pre-build @@javac -d bin -Xlint:unchecked $(SOURCES) @@cp -r src/view bin/ doc: $(SOURCES) @@javadoc @doc_args $(SOURCES) run: compile @@echo "Press 'p' to pause, 'r' to resume, 'cmd-q' to quit" @@java -cp bin RunningHeadline data_stream.json & runcli: compile @@java -cp bin model.Feeder data_stream.json & pre-build: @@mkdir -p bin clean: @@echo "Deleting all generated files" @@rm -rf bin/* @@rm -rf docs/* diag: @@echo $(SOURCES) .PHONY: all compile doc run runcli pre-build clean diag help: @@echo "To run GUI client: make run" @@echo "To run CLI client: make runcli" ass2/README.md View file @ 41d82cf9 COMP6700/COMP2140 Assignment 2: Running Headline News ===================================================== *Due on 18.00 pm AEST Friday, May 24 2017* Academic Honesty and Integrity ------------------------------ Honesty and integrity are of utmost importance. These goals are not at odds with being resourceful and working collaboratively. You *should* be resourceful and you should discuss the assignment and other aspects of the course with others taking the class. However, *you must never misrepresent the work of others as your own*. If you have taken ideas from elsewhere or used code sourced from elsewhere, you must say so with utmost clarity. Please read [the ANU's official position on academic honesty](http://www.anu.edu.au/students/program-administration/assessments-exams/academic-honesty-plagiarism). If you have any questions, please ask the lecturers. Preparation ----------- Before you start working on Assignment Two, change (using the Terminal application on Mac/Linux, or Git-Bash on Windows) into the directory of your local ``comp6700-2017`` (this applies to COMP2140 student as well) GitLab repository and execute the following commands: ``` git fetch git@gitlab.cecs.anu.edu.au:u1234567/comp6700-2017.git master git checkout -b u1234567/comp6700-2017-master FETCH_HEAD ``` Review the changes if required; then merge the branch and fix any conflicts that come up: ``` git checkout master git merge --no-ff u1234567/comp6700-2017-master ``` Proceed as usual to extend the Assignment Two code, commit changes and push to the remote repository for submission (pushing is also recommended when you commit changes in the local repository). To start, use the `Makefile` inside the ``ass2`` directory, to compile and run the original program: ``` make compile make run ``` Import the source files into a new project which you create with an IDE, follow the default option during the set-up dialog. Compile and run the program from within the IDE as usual. Add any new Java source files you create, and any other files that are required to run your project (e.g. `fxml` and `css` files) to your repository. The total size of additional code (excluding comments) should be around 350 LOC, depending on style of your code (high level or not) and choice of standard API. Use of good modularisation will be crucial for success. The time necessary to study the necessary material (JavaFX API, relevant techniques to use containers and streams) is around 15 hours. Problem Description ------------------- In this project, you will complete an application which simulates the running of news messages on a display. A visually relevant example would be a news headline display which can be seen in Canberra City at the crossing of Northbourne Avenue and Alinga Street. Another example is an extension for the Safari browser, which displays running news in the top bar. We will use a simple model in which a news item, described as a Json-string, is read from a file, a fictitious timestamp is generated and included together with the news item into a buffer of the class *Feeder*. The Feeder object represents a news aggregator, and its buffer serves a supplier of news messages which arrived at the time given by the timestamp. We possess all the messages and the time of their "arrival" in advance, but pretend that messages arrive at an asynchronous moments of time, and ordered in the message queue by the time of their "arrival". (Think of this as if Dr. Who has gone into the future, collected all news messages, stored them in the order of their occurrence, and brought this record back.) When you compile and run the original program, it will display the following window with news items sliding one by one, from right to left: ![RunningHeadlines-1](./images/vanilla_app.png "RunningHeadlines Before") The original program does not have necessary features which are expected from a program with graphical user interface (GUI). For starters, it takes the name of the data file (which contains messages as json-strings) as a command-line argument instead of providing a menu to open this file with a file chooser dialog. Also, the application provides only rudimentary control over the application behaviour: by using keys ``P`` and ``R`` (and also ``cmd-Q``), the user can pause the running headlines, resume their motion, and quit the application. You will modify and extend the program to improve the user interface, and provide new features of control. Tasks ----- - Add a menu with following groups and items: - Open, Close, Quit (Close can be an optional feature, since other menu items will provide the relevant control) - Pause, Resume, Faster, Slower, Next, Previous - Add a row of controls (most suitably implemented with ``javafx.scene.control.CheckBox`` class), each allowing to include news items which have a relevant topic. *Topic* is an inner enum class which defines the type of the *Message* class fields; another field, of the type *Status*, will be used to prioritise the news item order of display. Together -- ``Topic``, ``Status`` and ``timestamp`` -- represent news message metadata. - Implement priority ordering based on the `Message.Status` value and the timestamp of a message in the queue. A suitable container type for the Feeder's buffer is ``java.util.PriorityQueue``, which requires a comparator object (or a functional interface), to determine in which order the elements are extracted from the container, and hence the order in which they will processed. Messages should be ordered according to their status, from EMERGENCY (highest priority) to SPECIAL_INTEREST (lowest priority). - Add visual effects: - colourise topics (mark each topic with a different colour) - add a separator between successive messages (in the running news display in Civic, they are separated by the ABC logo; you can use emoji symbols, for example, -- they are Unicode characters, and Java is Unicode friendly) - if the next message has a status of ``EMERGENCY``, make the currently playing message fade away halfway through - add styling to UI using css-styles - If you wish, you may use FXML to define the user interface for your project, but this is not required. If you do use FXML Advice on how to approach the project ------------------------------------- This short video provides an illustration of how your completed application may look like: [![RunningHeadlines-2](./images/full_app.png "RunningHeadlines After")](http://cs.anu.edu.au/courses/comp6700/v_media/ass2.mp4) The code which you will be writing can be placed in the existing classes, or (at least some of the new code) in newly added classes. The design is not a key consideration here, but it makes sense to pay attention to how newly emerging program will be organised. One special note -- the class *Controller* can be either kept or removed; as of now, it does not play any role, it was auto-generated by the IDE as a part of the template JavaFX project. *Controller* can be used if you pursue the creation of layout and control elements using the FXML-based approach (we will discuss it briefly in the lectures), but all the required tasks can be accomplished following the "old-fashioned" approach of creating appropriate statements inside the ordinary Java source files. If you follow the latter, *Controller* can be removed altogether. Marking guide ------------- Marks will be awarded in accordance with the following scheme: - Menu (File and Control) --- **4** points; ``File`` menu items should contain implemented callbacks for the message file opening operation, and for quitting the application; ``Control`` menu items ``Pause``, ``Resume`` and ``Reset`` should also be with implemented callbacks, while ``Faster``, ``Slower``, ``Next`` and ``Previous`` callback implementations will be the next task. - Callback implementation for ``Faster``, ``Slower``, ``Next`` and ``Previous`` --- **4** points. - Topic selection controls (as a row of check boxes, or in a different layout) --- **3** points; the selection controls should allow an arbitrary combination of topics (multiple checked boxes), and also contain an additional control (check box) to allow (de-)selection of all topics. The topic controls should be programmed, not hard-coded (that is, the program should itself determine the number and name of all controls from the *Topic* enum type). - Visual Effects --- **2** points (implement two, either some of those which are mentioned above, or of your own device which can be fun) - Priority queue implementation for the message buffer --- **1** point - The program *style* and quality of *comments* --- **1** point Submission protocol ------------------- Your submission must be pushed to your ``comp6700-2017`` GitLab repository. The necessary instructions are provided in the [Forking your GitLab repository](https://cs.anu.edu.au/courses/comp6700/labs/gitlab/) --- a set of instructions which is a part of Week Four exercises. All the source code for Assignment Two must be inside the directory ``comp6700-2017/ass2`` (of your forked repository). Your main class should be called ``RunningHeadline`` as per the distribution in the repository - do not change the name or move it from the ``ass2/src`` directory. The last commit prior to the submission deadline will be regarded as your submission. We do not prescribe the use of any particular IDE or other tools (*tools agnostic* specifications), but you are free to include a project file which an IDE creates to configure your project. **Do not zip your submission**; it should be committed to GitLab as individual files. In general, it is bad practice to commit compressed files (such as zipped archives) to a Git repository. Please **do not commit Java byte code** i.e. the `.class` files. ass2/data_stream.json 0 → 100644 View file @ 41d82cf9 {"status":"SPECIAL_INTEREST", "topic":"DOMESTIC", "text":"Satirist John Clarke, of Clarke and Dawe fame, dies aged 68"} {"status":"NORMAL", "topic":"INTERNATIONAL", "text":"North Korea says it 'will go to war' if US provokes it"} {"status":"NORMAL", "topic":"INTERNATIONAL", "text":"Assad dismisses Syrian gas attack as '100 per cent fabrication'"} {"status":"SPECIAL_INTEREST", "topic":"INTERNATIONAL", "text":"Iranian President Rouhani to seek second term, faces hardline challenge"} {"status":"NORMAL", "topic":"INTERNATIONAL", "text":"China says North Korea tension has to be stopped from reaching 'irreversible' stage"} {"status":"NORMAL", "topic":"INTERNATIONAL", "text":"Huge US bomb kills dozens of IS militants in Afghanistan"} {"status":"EMERGENCY", "topic":"SCITECH", "text":"Large asteroid to hurtle past Earth on April 19"} {"status":"NORMAL", "topic":"INTERNATIONAL", "text":"N. Korea to strike US bases in Asian Pacific"} {"status":"SPECIAL_INTEREST", "topic":"SCITECH", "text":"Top secret CIA virus control system: WikiLeaks releases Hive"} {"status":"SPECIAL_INTEREST", "topic":"INTERNATIONAL", "text":"Forget the 'Mother of all bombs', meet the Russian-made 'Daddy'"} {"status":"NORMAL", "topic":"INTERNATIONAL", "text":"Bake bread not war: Russian military helps Syrians restore Aleppo bakery"} {"status":"NORMAL", "topic":"INTERNATIONAL", "text":"Tillerson backs down on ultimatum mission to Russia"} {"status":"EMERGENCY", "topic":"MISCELLANEOUS", "text":"Potato chip prices spike in Japan due to panic buying"} {"status":"NORMAL", "topic":"MISCELLANEOUS", "text":"London's police failing to cope with soaring gun & knife violence"} {"status":"BREAKING_NEWS", "topic":"SCITECH", "text":"Space Station expedition 50 crew touches down in Kazakhstan after 170 days in orbit"} {"status":"SPECIAL_INTEREST", "topic":"MISCELLANEOUS", "text":"In pot we trust: International Church of Cannabis to open in Colorado"} {"status":"NORMAL", "topic":"DOMESTIC", "text":"Sydney teen dies after being shot in bedroom"} {"status":"NORMAL", "topic":"MISCELLANEOUS", "text":"Russia boycotts Eurovision after contestant barred from entering Ukraine"} {"status":"NORMAL", "topic":"BUSINESS", "text":"Australia's unemployment rate remains steady at 5.9 per cent in March"} {"status":"NORMAL", "topic":"BUSINESS", "text":"The Reserve Bank expresses concern that a third of Australian borrowers have little to no buffer on their home loan repayments"} {"status":"SPECIAL_INTEREST", "topic":"MISCELLANEOUS", "text":"Christian leaders urge hope amid disaster and conflict"} {"status":"BREAKING_NEWS", "topic":"MISCELLANEOUS", "text":"Searches for 'World War 3' hit their highest level this month since records started in 2004"} {"status":"NORMAL", "topic":"INTERNATIONAL", "text":"N. Korean missile fails, blows up 'almost immediately' after launch - Seoul & US military"} {"status":"NORMAL", "topic":"INTERNATIONAL", "text":"Blast hits bus convoy near Aleppo, women & children among dozens killed. Holland blames Assad"} {"status":"SPECIAL_INTEREST", "topic":"MISCELLANEOUS", "text":"Trump supporters, opponents clash in California park"} {"status":"SPECIAL_INTEREST", "topic":"INTERNATIONAL", "text":"Turks vote in historic referendum on expanding Erdogan's power"} {"status":"NORMAL", "topic":"BUSINESS", "text":"Uber's revenue hits $6.5 billion in 2016, still has large loss"} {"status":"SPECIAL_INTEREST", "topic":"BUSINESS", "text":"Apple receives permit in California to test self-driving cars"} {"status":"SPECIAL_INTEREST", "topic":"MISCELLANEOUS", "text":"Drug-addicted python rehabilitated by Australian prisoners"} {"status":"BREAKING_NEWS", "topic":"MISCELLANEOUS", "text":"DNC Head Tom Perez Speaks While American Flag Falls In Background"} \ No newline at end of file ass2/doc_args 0 → 100644 View file @ 41d82cf9 -d docs/ -author -private -sourcepath src/ ass2/images/full_app.png 0 → 100644 View file @ 41d82cf9 546 KB ass2/images/vanilla_app.png 0 → 100644 View file @ 41d82cf9 38 KB ass2/src/Controller.java 0 → 100644 View file @ 41d82cf9 /** * A generated class (for JavaFX framework) to use if the UI * layout is built with FXML * */ public class Controller { } ass2/src/RunningHeadline.java 0 → 100644 View file @ 41d82cf9 import javafx.animation.*; import javafx.application.Application; import javafx.application.Platform; import javafx.fxml.FXMLLoader; import javafx.geometry.VPos; import javafx.scene.Group; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.input.KeyCode; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.scene.text.Text; import javafx.stage.Stage; import javafx.util.Duration; import model.Feeder; import model.Message; import java.io.File; import java.io.IOException; import java.nio.file.Paths; import java.util.*; import static java.util.Arrays.asList; import static model.Message.Topic; /** * Created with IntelliJ IDEA. * User: abx * Date: 15/4/17 * Time: 1:20 AM * Main class for Ass2 application "Courant-En-Tete" -- * running headlines. JavaFX Application which * should set up a simple scene with a menu bar for file * operations, and some controls to operate the running * messages -- to pause and resume, speed-up and slow-down, * skip to next message, or rewind to previous. Also, a row * of control check boxes can be added to control message * topic selections to be displayed in the running headlines. * One more extension is to implement a priority queue for * the message buffer (@see model.Feeder) */ public class RunningHeadline extends Application { // dimensions of the scene with text private final double displayWidth = 750; private final double displayHeight = 120; private double playSpeed = 0.2; // make larger to play faster private Group group; // container for controls and text private Feeder feeder; // model class which stores and processes messages private List newsPieces; // may be used to operate on the messages private List timelines = new ArrayList<>(); // animated messages private boolean running; /** * removes any messages from the news buffer and fills it * with news one which are read from a file * @param newsFileName the name of file to open */ private void setUpFeed(String newsFileName) throws IOException { feeder.getBuffer().clear(); feeder.fillNewsBuffer(Paths.get(newsFileName)); } /** * given the contents of the message buffer, creates a list * of timeline objects with start and end properties for text * objects set up, the speed at which each message timeline will * be palyed (the same for all -- the messages are like railroad cars * in one train chain) */ private void setUpTimeline() { double offset = displayWidth + 20; // starting x-pos for message stream double playtime = 0; Queue messageBuffer = feeder.getBuffer(); while (!messageBuffer.isEmpty()) { Timeline timeline = new Timeline(); timelines.add(timeline); Message latestMessage; latestMessage = messageBuffer.poll(); String messageBody = latestMessage.text + " "; Text text = new Text(offset, displayHeight - 15, messageBody); // use another font if this one is not available on your system text.setFont(Font.font("Tahoma", FontWeight.BLACK, 80)); text.setTextOrigin(VPos.BASELINE); double mesWidth = text.getLayoutBounds().getWidth(); playtime += mesWidth / playSpeed; setNewsPieceForRun(text, group, timeline, playtime); offset += mesWidth; } } /** * defines parameters of (message) timeline * @param text is a text object which will be animated * @param groups is the parent container to which the text is added as child * @param tl is a timeline for individual animation of this text * @param playtime is the time for tl to be played (no autoreverse, 1 cycle) * * tl is defined to remove itself from the timelines list when it is * finished (this may need to be removed for features like "play previous" * to be implemented); the reason for this removal is to reduce the memory * usage mainly. Also, a diagnostic messages is added to be printed when the * tl timeline complets (can be removed with no harm) */ private void setNewsPieceForRun(Text text, Group group, Timeline tl, double playtime) { group.getChildren().add(text); int mesLength = (int) text.getLayoutBounds().getWidth(); tl.setCycleCount(1); tl.setAutoReverse(false); KeyValue kv = new KeyValue(text.xProperty(), -10 - mesLength, Interpolator.LINEAR); KeyFrame kf = new KeyFrame(Duration.millis(playtime), kv); tl.getKeyFrames().add(kf); tl.setOnFinished(e -> { timelines.remove(tl); // THINK HARD IF YOU NEED TO HAVE HIS! System.out.printf("The end of the message line is at %.2f%n", text.getLayoutBounds().getMaxX()); }); timelines.add(tl); } /** * start (resumes) running all (remianing) timeline messages */ private void runNewsStream() { timelines.forEach(Animation::play); } @Override public void start(Stage primaryStage) throws Exception { Parent root = FXMLLoader.load(getClass().getResource("view/display.fxml")); primaryStage.setTitle("News just in..."); // next two lines are needed if you read a command-line arguments Parameters params = getParameters(); String newsMockFile = params.getRaw().get(0); // messages are provisoned from the data file and placed into buffer feeder = new Feeder(); feeder.fillNewsBuffer(Paths.get(newsMockFile)); // container which will host the texts (also menu and selection // controls) group = new Group(); // the scene itself Scene scene = new Scene(group, displayWidth, displayHeight); scene.getStylesheets().add("view/styles.css"); // examples of call-backs to control the timeline // via key-board; can be removed when menu and proper controls // like check-boxes are added scene.onKeyPressedProperty().set(ke -> { if (ke.isMetaDown() && ke.getCode() == KeyCode.Q) Platform.exit(); else if (ke.getCode() == KeyCode.P) timelines.forEach(tl -> tl.pause()); else if (ke.getCode() == KeyCode.R) timelines.forEach(tl -> tl.play()); }); // initialise all timelines for text messages and run them setUpTimeline(); runNewsStream(); primaryStage.setResizable(false); primaryStage.setScene(scene); primaryStage.show(); primaryStage.setOnCloseRequest(e -> Platform.exit()); } public static void main(String[] args) throws IOException { launch(args); } } ass2/src/model/Feeder.java 0 → 100644 View file @ 41d82cf9 package model; import model.Message.Topic; import java.io.IOException; import java.io.PrintStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import java.util.stream.Collectors; /** * Created with IntelliJ IDEA. * User: abx * Date: 15/4/17 * Time: 1:33 AM * Created for ass2 in package model */ public class Feeder { // private static final String newsFeederMockFile = "data_stream.txt"; // bufferFileName is to be removed in rpoper GUI version private static final String bufferFileName = "message_buffer.txt"; private static final int origin = 2; // shortest time in sec between two feeds private static final int bound = 5; // longest time in sec between two feeds // queue to contain the text messages, later may become PriorityQueue private Queue buffer; public Feeder() { this.buffer = new ArrayDeque<>(); } public Queue getBuffer() { return this.buffer; } /** * reads lines from the data file, parses each line and creats a Message * object with the timestamp generated randomly; the messages are placed * in the buffer in the chronological order. Later changes to implement * priority ordering (based both on the timestamp and the status) may * affect the message order * * @param feedSource is the path to the data source file */ public void fillNewsBuffer(Path feedSource) throws IOException { double tt[] = new double[]{0}; double dt[] = new double[1]; Random random = new Random(); Files.lines(feedSource, StandardCharsets.UTF_8) .map(s -> { dt[0] = (bound - origin) * random.nextDouble() + origin; tt[0] += dt[0]; return MessageParser.getMessage(s, tt[0]); }) .forEach(buffer::add); } /** * filters out the messages from the original buffer to retain * only those whose topics are fount in the topics set * * @param topics the set of topics for all fitlered messages * to belong to */ public Queue filterNewsBuffer(Set topics) { return new ArrayDeque<>(buffer.stream() .filter(m -> topics.contains(m.topic)) .collect(Collectors.toList())); } /** * auxiliary method to "animate" the messages when printed on the * command line (not in the GUI window); just run "make runcli" to * see it in action, no actual use in the GUI version of the programm */ public void printBufferSlowly() { this.buffer.forEach(m -> { try { printSlowly(m.text, System.out); } catch (InterruptedException e) { e.printStackTrace(); } }); } private static void printSlowly(CharSequence text, PrintStream out) throws InterruptedException { System.out.println(); for (int i = 0; i < text.length(); i++) { Thread.sleep(75); out.print(text.charAt(i)); } out.println(); } public static void main(String[] args) throws IOException { Feeder feeder = new Feeder(); feeder.fillNewsBuffer(Paths.get(args[0])); feeder.printBufferSlowly(); // feeder.getBuffer().forEach(System.out::println); } } ass2/src/model/Message.java 0 → 100644 View file @ 41d82cf9 package model; /** * Created with IntelliJ IDEA. * User: abx * Date: 18/4/17 * Time: 12:11 AM * Created for ass2 in package model * * Class to represent a data set (content and metadata) * of a news piece. The timeStamp marks the position of the message * in the running message queue, the topic allows to filter (select) * the messages which are displayed, the status (not yet put to use) * allows to implement a priority ordering in the message queue based * on both the timestamp and the status value (hence we use PriorityQueue * for the message buffer in Feeder. */ public class Message { public final double timeStamp; public final String text; public final Topic topic; public final Status status; public Message(double timeStamp, String text, Topic topic, Status status) { this.timeStamp = timeStamp; this.text = text; this.topic = topic; this.status = status; } @Override public String toString() { return "Message{" + "timeStamp=" + timeStamp + ", text='" + text + '\'' + ", topic=" + topic + ", status=" + status + '}'; } public enum Topic { WEATHER, BUSINESS, INTERNATIONAL, DOMESTIC, SCITECH, SPORT, MISCELLANEOUS,// UNKNOWN } public enum Status { EMERGENCY(10), BREAKING_NEWS(5), NORMAL(3), SPECIAL_INTEREST(1);// ,UNKNOWN(0); private final int value; Status(int i) { value = i; } public int value() { return value; } } } ass2/src/model/MessageParser.java 0 → 100644 View file @ 41d82cf9 package model; import model.Message.Status; import model.Message.Topic; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; /** * Created with IntelliJ IDEA. * User: abx * Date: 17/4/17 * Time: 11:58 PM * Created for ass2 in package model * Simple JSON parser for documents with flat structure * (no json-objects as values); format-stable (ignores any white space) */ public class MessageParser { /** * Gets message from a json-string and marking each with a timestamp * * @param jsonString the json string * @param timeStamp the time stamp * @return the message */ public static Message getMessage(String jsonString, double timeStamp) { Map jsonMap = getJsonMap(jsonString); String text = jsonMap.get("text"); Topic topic = Topic.valueOf(jsonMap.get("topic").toUpperCase()); Status status = Status.valueOf(jsonMap.get("status").toUpperCase()); return new Message(timeStamp, text, topic, status); } private static List jsonChunks(String js) { js = js.trim(); if (js.startsWith("{")) js = js.substring(1); if (js.endsWith("}")) js = js.substring(0,js.length()-1); List res = new ArrayList<>(); int current = 0; for (Integer integer : getSeparatorIndices(js)) { res.add(js.substring(current, integer)); current = integer + 1; } res.add(js.substring(current)); // after the last ',' return res; } private static List getSeparatorIndices(String js) { List res = new ArrayList<>(); short insideBrackets = 0; boolean insideDoubleQuotes = false; char c; for (int i = 0; i < js.length(); i++) { c = js.charAt(i); if (c == '"') insideDoubleQuotes = !insideDoubleQuotes; insideBrackets += changeNestingLevel(c); if (c == ',' && insideBrackets == 0 && !insideDoubleQuotes) res.add(i); } return res; } private static short changeNestingLevel(char c) { if (c == '{' || c == '[') return 1; if (c == '}' || c == ']') return -1; return 0; } private static Map getJsonMap(String js) { List pairs = jsonChunks(js); Map jsonMap = new TreeMap<>(); String key, value; for (String pair: pairs) { key = pair.split(":")[0].trim(); value = pair.split(":",2)[1].trim(); if (key.startsWith("\"")) key = key.substring(1); if (key.endsWith("\"")) key = key.substring(0,key.length()-1);