**New edit info at bottom**
I have created a Tech support program that simulates an electronic tech support system. It is supposed to have a client request support through a ticket and assign it to the appropriate agent. It has four classes (client, agent, ticket, and the actual tech support system).
Ticket class:
/**
* Ticket.java
*
* This class is part of Programming
* Assignment 6 - Tech Support System
* for CS1440 Summer 2014.
*
* #author Brandon C. Eason
* #author
* #version
*/
/**
* This class represents a support ticket
* in the tech support ticket.
*/
public class Ticket
{
//the number of minutes for resolving a premium ticket
private static final int PREMIUM = 30;
//the number of minutes for resolving a basic ticket
private static final int BASIC = 60;
//the number of tickets generated
private static int ticketNumber;
//the ticket id, built from the current date and ticket number
private String id;
//the problem description
private String description;
//the number of minutes since the ticket was entered
private int minutes;
//the client that requested this ticket
private Client requester;
//the agent assigned to this ticket
private Agent solver;
/**
* Fully parameterized constructor for Ticket.
*
* #param date - the date this ticket was created
* #param description - this ticket's problem description
* #param minutes - the number of minutes since this ticket was entered
* #param requester - the client that requested this ticket
*/
public Ticket(String date, String description, int minutes,
Client requester)
{
ticketNumber++;
id = date + "-" + ticketNumber;
this.description = description;
this.minutes = minutes;
this.requester = new Client(requester);
}
/**
* Accessor for ticket number.
*
* #return the number of tickets generated
*/
public static int getNumTickets()
{
return ticketNumber;
}
/**
* Accessor for id.
*
* #return this ticket's id
*/
public String getID()
{
return id;
}
/**
* Accessor for description.
*
* #return this ticket's description
*/
public String getDescription()
{
return description;
}
/**
* Accessor for minutes.
*
* #return the number of minutes since this ticket was entered
*/
public int getMinutes()
{
return minutes;
}
/**
* Accessor for the Client requesting the ticket.
*
* #return a copy of the Client requesting this ticket
*/
public Client getClient()
{
return requester;
}
/**
* Assign this ticket to an agent. The method makes a copy of the
* Agent parameter and sets the solver field to that copy.
*
* #param solver - the agent this ticket is assigned to
*/
public void setAgent(Agent solver)
{
String name = solver.getName();
String id = solver.getID();
String specialty = solver.getSpecialty();
int time = solver.getTime();
solver = new Agent(name, id, specialty, time);
}
/**
* Determine the minutes this ticket is overdue.
* Basic service level clients should have their
* tickets resolved within 60 minutes. Premium
* service level clients should have their tickets
* resolved within 30 minutes.
*
* #return the number of minutes the ticket is overdue
*/
public int timeOverdue()
{
int timeOverdue;
if(requester.hasPremium())
{
timeOverdue = (PREMIUM - this.minutes);
}
else
{
timeOverdue = (BASIC - this.minutes);
}
return timeOverdue;
}
/**
* Return a string predicting the resolution time of the ticket.
*
* #return a prediction of the resolution time
*/
public String prediction()
{
String predict = "Resolution Time: ";
int minutes = timeOverdue() + solver.getTime();
if (minutes > 0)
{
predict += minutes + " minutes behind schedule";
}
else if (minutes < 0)
{
predict += Math.abs(minutes) + " minutes ahead of schedule";
}
else
{
predict += "On time";
}
return predict;
}
/**
* Determine whether this ticket is overdue.
*
* #return true if this ticket is overdue
*/
public boolean isOverdue()
{
return timeOverdue() > 0;
}
/**
* Build a string representation of this ticket.
*
* #return this ticket's data
*/
public String toString()
{
//begin with id and description
String data = "ID#: " + getID();
data += "\r\nProblem: " + getDescription();
//add time overdue, if any
if (isOverdue())
{
data += "\r\nOverdue: " + timeOverdue() + " minutes";
}
//add client data
data += "\r\n------------";
data += "\r\nRequested by\r\n";
data += "------------\r\n";
data += requester;
//add agent data
data += "\r\n-----------";
data += "\r\nAssigned to\r\n";
data += "-----------\r\n";
data += solver;
//add projected resolution time
data += "\r\n" + prediction();
return data;
}
/**
* Determine if this ticket is a duplicate of another.
* Tickets are duplicates if they have the same description
* and Client.
*
* #param other - the other Ticket
* #return true if this ticket is a duplicate of the other
*/
public boolean equals(Ticket other)
{
if(description.equals(other.description) && requester.equals(other.requester))
{
return true;
}
else
{
return false;
}
}
}
Agent class:
/**
* Agent.java
*
* This class is part of Programming
* Assignment 6 - Tech Support System
* for CS1440 Summer 2014.
*
* #author Brandon C. Eason
* #author
* #version
*/
/**
* This clas represents an agent profile
* in the tech support system.
*/
public class Agent
{
//the agent's name
private String name;
//the agent's id number
private String id;
//the agent's support specialty
private String specialty;
//the agent's average turnaround time in whole minutes
private int time;
/**
* Fully parameterized constructor for Agent.
*
* #param name - this agent's name
* #param id - this agent's id number
* #param specialty - this agent's support specialty
* #param time - this agent's average turnaround time in minutes
*/
public Agent(String name, String id, String specialty, int time)
{
this.name = name;
this.id = id;
this.specialty = specialty;
this.time = time;
}
/**
* Create a copy of this Agent.
*
* #return a new Agent that is a copy of this one
*/
public Agent copy()
{
Agent copyAgent = new Agent(name, id, specialty, time);
return copyAgent;
}
/**
* Accessor for name.
*
* #return this agent's name
*/
public String getName()
{
return name;
}
/**
* Accessor for id number.
*
* #return this agent's id number
*/
public String getID()
{
return id;
}
/**
* Accessor for specialty.
*
* #return this agent's support specialty
*/
public String getSpecialty()
{
return specialty;
}
/**
* Accessor for average turnaround time.
*
* #return this agent's average turnaround time
*/
public int getTime()
{
return time;
}
/**
* Builds a string representation of this agent's data.
*
* #return this agent's data
*/
public String toString()
{
String str = "Agents's name: " + this.name
+ "/nAgent's ID: " + this.id
+ "/nSupport specialty: " + this.specialty
+ "/nAverage service time:" + this.time;
return str;
}
}
Client class:
/**
* Client.java
*
* This class is part of Programming
* Assignment 6 - Tech Support System
* for CS1440 Summer 2014.
*
* #author Brandon C. Eason
* #author
* #version
*/
/**
* This class represents a client profile in
* the tech support system with information
* about the client and the client's
* computer system.
*/
public class Client
{
//the client's full name
private String name;
//the client's phone number
private String phone;
//the client's computer type
private String computer;
//true if a premium client
private boolean premium;
/**
* Fully parameterized constructor for
* Client.
*
* #param name - this client's name
* #param phone - this client's phone number
* #param computer - this client's computer type
* #param premium - whether client has premium service
*/
public Client(String name, String phone, String computer, boolean premium)
{
this.name = name;
this.phone = phone;
this.computer = computer;
this.premium = premium;
}
/**
* Constructor for when computer type is not specified.
*
* #param name - this client's name
* #param phone - this client's phone
* #param premium - whether client has premium service
*/
public Client(String name, String phone, boolean premium)
{
this(name, phone, "Unspecified", premium);
}
/**
* Constructor that creates a copy of the Client passed in.
*
* #param object - the client to be copied
*/
public Client(Client object)
{
name = object.name;
computer = object.computer;
phone = object.phone;
premium = object.premium;
}
/**
* Accessor for name.
*
* #return this client's name
*/
public String getName()
{
return name;
}
/**
* Accessor for phone.
*
* #return this client's phone number
*/
public String getPhone()
{
return phone;
}
/**
* Accessor for computer type.
*
* #return this client's computer type
*/
public String getComputer()
{
return computer;
}
/**
* Determine if this client receives
* premium service.
*
* #return true if this client receives premium service.
*/
public boolean hasPremium()
{
return premium;
}
/**
* Builds a printable String representation of
* this client's data.
*
* #return this client's data
*/
public String toString()
{
String service;
if(this.premium)
{
service = "Premium";
}
else
{
service = "Basic";
}
String str = "Client's name: " + this.name
+ "/nClient's phone: " + this.phone
+ "/nCSystem type: " + this.computer
+ "/nService:" + service;
return str;
}
/**
* Determine if this Client is the same as another.
* Client's are equal if they have the same name,
* phone number, computer type, and service level.
*
* #param other - the other Client
* #return true if this client equals the other
*/
public boolean equals(Client other)
{
if(name.equals(other.name) && phone.equals(other.phone)
&& computer.equals(other.computer) && premium == (other.premium))
{
return true;
}
else
{
return false;
}
}
}
This class processes the tickets by reading request from a file, assigning them to agents, and writing them to a report that beings with the date. There is always agents on duty for each specialization(Mac, Windows PC, or any system).
TicketSupportSystem class:
/**
* TechSupportSystem.java
*
* This class is part of Programming
* Assignment 6 - Tech Support System
* for CS1440 Summer 2013.
*
* #author Brandon C. Eason
* #author
* #version
*/
import java.util.Scanner;
import java.io.PrintWriter;
import java.io.FileWriter;
import java.io.File;
import java.io.IOException;
/**
* This class runs a tech support system
* which reads in tickets entered by clients,
* assigns them to an agent to be resolved,
* and writes them to a report.
*/
public class TechSupportSystem
{
//for keyboard input
private Scanner keyboard;
//for file input
private Scanner input;
//for writing to a file
private PrintWriter output;
//for appending to a file
private FileWriter append;
//for opening files
private File inputFile;
//today's date
private String date;
//first agent
private Agent agentOne;
//second agent
private Agent agentTwo;
//third agent
private Agent agentThree;
//the number of tickets assigned
private int numTickets;
/**
* Constructor for TechSupportSystem.
*
* #throws IOException - file not found
*/
public TechSupportSystem() throws IOException
{
System.out.println("------------------------------\n");
System.out.println("Welcome to Ticket Manager Lite\n");
System.out.println("------------------------------\n");
keyboard = new Scanner(System.in);
getDate();
getAgents();
enableWriting();
processTickets();
output.close();
System.out.println("\nTotal tickets processed: "
+ Ticket.getNumTickets());
System.out.println("\nTotal tickets assigned: " + numTickets);
}
/**
* Get today's date from the dispatcher (the user of this system).
*/
private void getDate()
{
date = "";
while (date.length() != 8)
{
System.out.print("Enter today's date(MMDDYYYY format): ");
date = keyboard.nextLine();
}
}
/**
* Verify file for opening and open it.
*
* #param fileName - the file to be opened
* #return true if valid file
*/
private boolean openFile(String fileName)
{
inputFile = new File(fileName);
return inputFile.exists();
}
/**
* Prepare file writing.
*
* #throws IOException - file not found
*/
private void enableWriting() throws IOException
{
append = new FileWriter("report.txt", true);
output = new PrintWriter(append);
output.println("--------------------------");
output.println("Ticket Report for " + date);
output.println("--------------------------\r\n");
}
/**
* Read in agents on duty.
*
* #throws IOException - file not found
*/
private void getAgents() throws IOException
{
String fileName;
do
{
System.out.print("Enter the name of the agent duty file: ");
fileName = keyboard.nextLine();
} while (!openFile(fileName));
input = new Scanner(inputFile);
agentOne = readAgent();
agentTwo = readAgent();
agentThree = readAgent();
input.close();
}
/**
* Read a single agent.
*
* #return the agent that was read
*/
private Agent readAgent()
{
String name = input.nextLine();
String id = input.nextLine();
String specialty = input.nextLine();
int time = input.nextInt();
input.nextLine();
return new Agent(name, id, specialty, time);
}
/**
* Read in the day's tickets from a file, two
* at a time, check for duplicates, assign the
* tickets to an agent, and write them to a report.
*
* #throws IOException - file not found
*/
private void processTickets() throws IOException
{
String fileName;
Ticket currentTicket;
Ticket lastTicket = null;
do
{
System.out.print("Enter the name of the ticket file: ");
fileName = keyboard.nextLine();
} while (!openFile(fileName));
System.out.println();
input = new Scanner(inputFile);
while (input.hasNext())
{
currentTicket = readTicket();
if (lastTicket == null || !currentTicket.equals(lastTicket))
{
assign(currentTicket);
output.println(currentTicket + "\r\n");
}
lastTicket = currentTicket;
}
input.close();
}
/**
* Read in a single ticket.
*
* #return the ticket that was read in
*/
private Ticket readTicket()
{
Client requester;
String description;
int minutes;
requester = readClient();
description = input.nextLine();
minutes = input.nextInt();
input.nextLine();
return new Ticket(date, description, minutes, requester);
}
/**
* Read in a single client.
*
* #return the client that was read in
*/
private Client readClient()
{
String name;
String phone;
String computer;
String premium;
boolean hasPremium = false;
name = input.nextLine();
phone = input.nextLine();
computer = input.nextLine();
premium = input.nextLine();
if (premium.equals("Premium"))
{
hasPremium = true;
}
if (computer.length() == 0)
{
return new Client(name, phone, hasPremium);
}
else
{
return new Client(name, phone, computer, hasPremium);
}
}
/**
* Assign a ticket to an agent.
*
* #param ticket - the ticket to be assigned
*/
private void assign(Ticket ticket)
{
Client requester = ticket.getClient();
String computer = requester.getComputer();
Agent solver;
if (agentOne.getSpecialty().equals(computer))
{
solver = agentOne;
}
else if (agentTwo.getSpecialty().equals(computer))
{
solver = agentTwo;
}
else
{
solver = agentThree;
}
ticket.setAgent(solver);
System.out.println("Ticket assigned to " + solver.getName() + ".");
numTickets++;
}
/**
* Starts the tech support system.
*
* #param args - not used
* #throws IOException - file not found
*/
public static void main(String[] args) throws IOException
{
new TechSupportSystem();
}
}
Everything compiles right but when I run it, it has an error after I tell it the files and it reads them. The error it gives is:
------------------------------
Welcome to Ticket Manager Lite
------------------------------
Enter today's date(MMDDYYYY format): 12121221
Enter the name of the agent duty file: agents.txt
Enter the name of the ticket file: tickets.txt
Ticket assigned to Dee.
Exception in thread "main" java.lang.NullPointerException
at Ticket.prediction(Ticket.java:153)
at Ticket.toString(Ticket.java:210)
at java.lang.String.valueOf(String.java:2979)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at TechSupportSystem.processTickets(TechSupportSystem.java:178)
at TechSupportSystem.<init>(TechSupportSystem.java:62)
at TechSupportSystem.main(TechSupportSystem.java:275)
Press any key to continue . . .
So I know it has something to do with the null value assigned to lastTicket in the TechSupportSystem class and somethings skewed in the prediction. I just dont know what to change that would make it work with the whole processTickets and prediction methods. Ive been staring at this code for hours and just keep brain-farting on what the actual issue is. Could someone atleast point me in the right direction?
Thanks for your time on this long post.
**Edit***
I fixed the nullexception error. When I run it everything works fine it seems. It reports the correct info to the report.txt but the thing that is messing up is it isnt assigning a solver. The solver is null for every ticket.
I assume its something wrong with my
/**
* Assign this ticket to an agent. The method makes a copy of the
* Agent parameter and sets the solver field to that copy.
*
* #param solver - the agent this ticket is assigned to
*/
public void setAgent(Agent solver)
{
String name = solver.getName();
String id = solver.getID();
String specialty = solver.getSpecialty();
int time = solver.getTime();
solver = new Agent(name, id, specialty, time);
}
just cant figure out what.
Most likely you are trying to print a Ticket without a solver. i.e. the solver is null
public String prediction() {
if(solver == null) return "no solver";
BTW if you use a debugger, you should be able to see what the problem is in a few minutes. I suggest you learn how to use it as it will save you hours of frustration.
The simplest workaround is to trap the exception until you can fix it.
String predict;
try {
predict = prediction();
} catch (Exception e) {
predict = e.toString();
}
data += "\r\n" + predict;
Related
Either my understanding of how Priority Queue works is incorrect or I have a logical error in my compareTo method which overrides the Comparable interface. I am trying to assign runways with the highest priority to airplanes that are landing or taking off. In the following scenario, there are four flights and four runways are available. So, each flight lands or departs at its scheduled time.
The format is:
scheduledTime|eventType|flightIdentifier|runwayUsed
00:01|ARRIVAL|A001|null
00:00|DEPARTURE|D001|null
00:01|DEPARTURE|D002|null
00:00|DEPARTURE|D003|null
After assigning flights to priority runways('polling' priority runways from priority queue of runway objects), the result is
00:01|ARRIVAL|A001| 1
00:00|DEPARTURE|D001| 4
00:01|DEPARTURE|D002| 2
00:00|DEPARTURE|D003| 3
However, assuming I don't have a logical error in my compareTo method, the output should be:
00:01|ARRIVAL|A001| 1
00:00|DEPARTURE|D001| 2
00:01|DEPARTURE|D002| 3
00:00|DEPARTURE|D003| 4
Here is the Runway class which contains the compareTo method:
public class Runway implements Comparable<Runway>{
//instance or class variables
private LocalTime whenAvailable; //when the runway is available
private LocalTime actualTime; //actual time the plane arrived or departed
private List<Flight> flights; //the flights that have been assigned to the runway
private Integer runwayNumber; // the number of the runway. for ex., 1 = Runway 1.
private LocalTime previousSchedTime; //the most recent previous time that the runway was scheduled for arrival or departure. This is just used
// for testing purposes.
/**
* Constructor
*/
protected Runway() {
whenAvailable = null;
flights = new ArrayList<Flight>();
}
/**
* Determine if the runway is available
* #param currentTime The scheduled time of the flight
* #return true if the runway is available or false if it is not
*/
protected boolean isAvailable(LocalTime currentTime) {
if(currentTime == null) {
throw new IllegalArgumentException();
}
return whenAvailable == null || !currentTime.isBefore(whenAvailable); // currentTime >= whenAvailable
}
/**
* Assign flight to the runway, i.e., set the actual time a flight uses the runway and the time ruwnay will be available again
* #param flight The flight being assigned to the runway
* #param scheduledTime The scheduled time of the flight
* #param reserveTime The arrival or departure reserve times of the flight
*/
protected void assignFlight(Flight flight, LocalTime scheduledTime, int reserveTime) {
//if the runway is available
if(isAvailable(scheduledTime)) {
//Set the actual time of the flight and when the runway will be available again
//if the runway is null and available
if(whenAvailable == null) {
actualTime = scheduledTime;
whenAvailable = scheduledTime.plusMinutes(reserveTime);
}
//if runway is available and the scheduled time of flight is equal to when the runway is available
else if(scheduledTime == whenAvailable || scheduledTime.isBefore(whenAvailable)) {
actualTime = whenAvailable;
whenAvailable = actualTime.plusMinutes(reserveTime);
}
else { //if scheduledTime > whenAvailable
actualTime = scheduledTime;
whenAvailable = actualTime.plusMinutes(reserveTime);
}
}
//if the runway is not available aka currentTime < whenAvailable
else {
actualTime = whenAvailable;
whenAvailable = actualTime.plusMinutes(reserveTime);
}
flights.add(flight);
previousSchedTime = scheduledTime; //update previousSchedTime to scheduledTime
}
/**
*
* #return acutialTime the runway was used by flight
*/
protected LocalTime getActualTimeRunway() {
return actualTime;
}
/**
*
* #return the time the runway is available
*/
protected LocalTime getWhenAvailable() {
return whenAvailable;
}
/**
*
* #return List of all the flights that used the runway
*/
protected List<Flight> getFlights(){
List<Flight> tmpList = new LinkedList<Flight>();
for(Flight f : flights) {
tmpList.add(f);
}
return tmpList;
}
/**
*
* #param runwayNumber set the number of the runway
*/
protected void setRunwayNumber(int runwayNumber) {
if(runwayNumber < 1) {
throw new IllegalArgumentException();
} //end of if
this.runwayNumber = runwayNumber;
}
/**
*
* #return the number of the runway
*/
protected Integer getRunwayNumber() {
return runwayNumber;
}
/**
*
* #return the most recent previous time that the runway was scheduled for arrival or departure. This is used
// as a condition in the assignFlight method below
*/
protected LocalTime getPreviousSchedTime() {
return previousSchedTime;
}
/**
* NOTE: this is intended to only be used for testing in other classes when used with reflection
* #param previousSchedTime sets the previousScedTime
*/
private void setPreviousSchedTime(LocalTime previousSchedTime) {
this.previousSchedTime = previousSchedTime;
}
/**
* Override compareTo method of Comparable interface
* Set priority of runway instance when compared other runway instances
*/
#Override
public int compareTo(Runway other) {
if(this.getWhenAvailable() == null && other.getWhenAvailable() == null) {
return 0;
}
else if(this.getWhenAvailable() == null && other.getWhenAvailable() != null) {
return -1;
}
else if(this.getWhenAvailable() !=null && other.getWhenAvailable() == null) {
return 1;
}
else if(this.getWhenAvailable() !=null && other.getWhenAvailable() != null) {
if(this.getWhenAvailable().equals(other.getWhenAvailable())) {
return 0;
}
else if(this.getWhenAvailable().isBefore(other.getWhenAvailable())) {
return -1;
}
else if(this.getWhenAvailable().isAfter(other.getWhenAvailable())) {
return 1;
}
}
return 0;
}
/**
* Intended use is only for JUnit testing when used with reflection
* #param wA set whenAvailable time
*/
private void setWhenAvailable(LocalTime wA) {
this.whenAvailable = wA;
}
} //end of Runway class ----------------------------------------
Below is a class that implements the compareTo method through Priority Queues:
public class stackExchange {
public static void main(String[] args) {
Flight f1 = new Flight("00:01", "ARRIVAL","A001");
Flight f2 = new Flight("00:00", "DEPARTURE","D001");
Flight f3 = new Flight("00:01", "DEPARTURE","D002");
Flight f4 = new Flight("00:00", "DEPARTURE","D003");
PriorityQueue<Flight> flightsPQ = new PriorityQueue<Flight>();
flightsPQ.add(f1);
flightsPQ.add(f2);
flightsPQ.add(f3);
flightsPQ.add(f4);
Runway r1 = new Runway();
r1.setRunwayNumber(1);
Runway r2 = new Runway();
r2.setRunwayNumber(2);
Runway r3 = new Runway();
r3.setRunwayNumber(3);
Runway r4 = new Runway();
r4.setRunwayNumber(4);
PriorityQueue<Runway> runwaysPQ = new PriorityQueue<Runway>();
runwaysPQ.add(r1);
runwaysPQ.add(r2);
runwaysPQ.add(r3);
runwaysPQ.add(r4);
while(!flightsPQ.isEmpty()) {
Flight tmpFlight = flightsPQ.poll(); //remove priority flight from flightsPQ
Runway tmpRunway = runwaysPQ.poll(); //remove priority runway from runwaysPQ
tmpRunway.assignFlight(tmpFlight, tmpFlight.getScheduledTime(), tmpFlight.getReserveTime()); //assign the priority flight to the runwy
tmpFlight.setActualTime(tmpRunway.getActualTimeRunway()); //set the actual time the flight was used
tmpFlight.setRunwayUsed(tmpRunway); //tell the flight which runway it used
//print out the flight data that used the runway and the number of the runway used
//format: scheduledTime of flight | eventType | identifier | actualTime the flight used the runway | the number of the runway used (used to distinguish runway over
// other runways
System.out.println(tmpFlight.getScheduledTime() + "|" + tmpFlight.getEvent() + "|" + tmpFlight.getIdent() + "|" + tmpFlight.getActualTime()
+ "|" + tmpFlight.getRunwayUsed().getRunwayNumber());
runwaysPQ.add(tmpRunway); //add the runway back into runwaysPQ
}
} //end of main
} //end of stackExchange class
In the beginning whenAvailable is null, so all the runways have equal priority. As per documentation:
The head of this queue is the least element with respect to the specified ordering. If multiple elements are tied for least value, the head is one of those elements -- ties are broken arbitrarily.
So you should probably first compare availability time, and then also the number of a runway if you want consistent ordering.
The methods setDates and setTimes have as preconditions that none of their arguments are null. This is to be checked by means of an assertion. (This means that if the precondition is not met, the program will fail at the assertion, and an AssertionError will be thrown.)
here is my code:
public class Section
{
/**
* Default section number.
*/
private static final String DEFAULT_SECTION_NUMBER = "";
/**
* Constant for building Strings with newline characters within them.
*/
private static final String LINE_SEPARATOR = System.
getProperty("line.separator");
/**
* The maximum number of students permitted into a section.
*/
private static final int MAXIMUM_STUDENTS_PER_SECTION = 30;
/**
* Valid length for a sectionNumber string.
*/
private static final int SECTION_NUMBER_LENGTH = 3;
/**
* Shared variable for keeping count of the number of section objects in
* existence.
*/
private static int count = 0;
/**
* The date at which the section is finished.
*/
private Date endDate;
/**
* The end time for the meeting of the section.
*/
private Time2 endTime;
/**
* The list of students in the class. This declaration uses the Java 7 facility
* of not repeating the generic type if that type can be inferred by the
* compiler.
*/
private final List<Student> roster = new ArrayList<>();
/**
* The three-character designation of the section (called a
* “number”).
*/
private String sectionNumber = DEFAULT_SECTION_NUMBER;
/**
* The date on which the section starts to meet.
*/
private Date startDate;
/**
* The time of day at which the section meets.
*/
private Time2 startTime;
/**
* The course of which this is a section.
*/
private final Course thisCourse;
/**
* Constructor.
*
* #param course the course of which this is a section
* #param sectionNumber the section number (within the course) of this section
* #throws SectionException
*/
public Section(Course course, String sectionNumber) throws SectionException
{
/* Increment the collective count of all Section objects that have been
created. Do this first as the object already exists. */
++count;
this.thisCourse = course;
try
{
if( isValidSectionNumber(sectionNumber) )
this.sectionNumber = sectionNumber;
}
catch (Exception ex)
{
throw new SectionException("Error in constructor", ex);
}
}
/**
* Add a student to the course.
*
* #param student the student object to be added. If the course is full, the
* student is not added
*/
public void addStudent(Student student)
{
if( roster.size() != MAXIMUM_STUDENTS_PER_SECTION )
roster.add(student);
}
/**
* Get details about the current state of this section, including the course of
* which it is part, the dates it starts and ends, times, etc., and the current
* count of the enrollment.
*
* #return the section details
*/
public String getDetails()
{
return String.join(LINE_SEPARATOR,
"Section: " + this.toString(),
"Course: " + thisCourse.getDetails(),
"Dates: " + startDate + " to " + endDate,
"Times: " + startTime + " to " + endTime,
"Enrollment: " + roster.size());
}
/**
* Create a string that represents the information about the students in the
* course.
*
* #return a string that represents the information about the students in the
* course
*/
public String getRoster()
{
/* The following commented-out code is the obvious way to do this, using
String concatenation (and this is acceptable). However, the recommended
Java approach to this kind of operation is to use a StringJoiner (new
class in Java 8), as this uses less garbage collection resources. */
// String result = "";
// for( Student student : roster )
// {
// result += ( result.isEmpty() ? "" : LINE_SEPARATOR) + student;
// }
// return result;
StringJoiner stringJoiner = new StringJoiner(LINE_SEPARATOR);
for( Student student : roster )
stringJoiner.add(student.toString());
return stringJoiner.toString();
}
/**
* Get a count of the number of students registered (on the roster) for this course.
*
* #return a count of the number of students registered for this course
*/
public int getRosterCount()
{
return roster.size();
}
/**
* Get the section number for this course.
*
* #return the section number for this course
*/
public String getSectionNumber()
{
return sectionNumber;
}
/**
* Set the start and end dates for the section.
*
* #param startDate the start date
* #param endDate the end date
*/
public void setDates(Date startDate, Date endDate)
{
/* There is no requirement to validate these. */
this.startDate = startDate;
this.endDate = endDate;
}
/**
* Set the start time and the end time for the meetings of the section.
*
* #param startTime the start time for meetings of the section
* #param endTime the end time for the meetings of the section
*/
public void setTimes(Time2 startTime, Time2 endTime)
{
/* There is no requirement to validate these. */
this.startTime = startTime;
this.endTime = endTime;
}
/**
* Section number (prefixed)
*
* #return Section number (prefixed)
*/
#Override
public String toString()
{
return thisCourse.toString() + "-" + sectionNumber;
}
/**
* Finalization. Reduce the instance count by 1.
*
* #throws Throwable standard interface.
*/
#SuppressWarnings("FinalizeDeclaration")
#Override
protected void finalize() throws Throwable
{
/* Decrement the count of the collective total of all Section objects. */
--count;
super.finalize();
}
/**
* Get a count of how many total Section objects are currently in existence.
*
* #return a count of how many Section objects are currently in existence
*/
public static int getSectionCount()
{
return count;
}
/**
* Validate the sectionNumber string. It must be of the correct length.
*
* #param sectionNumber the sectionNumber string
* #return true if the string if valid, otherwise false
*/
private static boolean isValidSectionNumber(String sectionNumber)
{
return sectionNumber != null &&
sectionNumber.length() == SECTION_NUMBER_LENGTH;
}
}
would i simply place 'assert' before this.startDate = startDate; and so forth??? my book only has one example and it is for ensuring a value is between 0 and 10.
this is the example my book uses:
public class AssertTest
{
public static void main(string[] args)
{
Scanner input = new Scanner(System.in);
System.out.print("Enter a number between 0 and 10: ");
int number = input.nextInt();
//assert that the value is >= 0 and <= 10
assert (number >= 0 && number <= 10) : "bad number: " + number;
System.out.printf("You entered %d%n", number);
}
}
so could i say
assert this.startDate = startDate
assert this.endDate = endDate
and so on?
First of all the methods setTime and setDates are public what suggests that they may be used outside of the package. Given that you have no control over parameters - using assert would not be considered as the best practice. You should rather use Runtime Exceptions such as IllegalArgumentException when value can be supplied externally (and you have no control over it):
if (startDate == null || endDate == null)
throw new IllegalArgumentException("Non-null arguments are required");
The syntax for the Assert would be as follows:
assert startDate != null;
assert endDate != null;
You can also use the following syntax in order to output additional information when assertion fails:
assert startDate != null : "startDate was set to null"
assert endDate != null : "endDate was set to null"
I've posted my program for review on code review (stackexchange).
Everything worked fine, After I came home I was told to use a IDE.
I opened my source with Eclipse IDE, and then I started getting (both on the IDE, or without) this error upon run:
Exception in thread "main" java.lang.NullPointerException
at games.Spin.rand(Spin.java:68)
at games.Spin.<init>(Spin.java:10)
at games.GameHandler.<init>(GameHandler.java:8)
at Mains.startGame(Mains.java:16)
at Mains.main(Mains.java:9)
Why is it doing that? My mate has reviewed my code, and could not find anything wrong with it?.
I am very new to java, tried at attempting going deeper in OO.
My code is located at code review thread (3 classes):
https://codereview.stackexchange.com/questions/28197/improving-my-java-object-oriented-review
What is wrong with it? Why is it giving me that exception?
Line 68: return r.nextInt(x);
public int rand(int x) {
return r.nextInt(x);
}
That's how I create r object:
/**
* Creating new Random object.
**/
private Random r = new Random();
Mains.java:
import games.GameHandler;
import java.util.Scanner;
import java.io.*;
public class Mains {
public static void main (String[] args) {
//Start the game
startGame();
}
private static void startGame() {
//Declares
GameHandler handler = new GameHandler();
Scanner console = new Scanner(System.in);
boolean game = true;
String input = "";
//Print program welcome text
handler.printStart();
//While in game...
while (game) {
//Getting input ready for new commands from the player
input = console.nextLine();
//Checking if input was set.
if (input != null) {
//Selecting the game you want to play.
handler.selectGame(input);
//If game was selected.. then.. let's start playing.
while (handler.inGame) {
//Use will say something.
input = console.nextLine();
//If it was "exit", it will go back and select another game.
if (input.equals("exit")) {
handler.exitGame();
} else {
//Play again.
handler.continueGame(input);
}
}
}
}
}
}
GameHandler.java:
package games;
import java.io.*;
public class GameHandler {
private String[] games = {"Spin", "Tof"};
private String[] navigation = {"Back", "Start"};
private Spin spin = new Spin();
private boolean spinGame = false;
private boolean tofGame = false;
public boolean inGame = false;
/**
* Method printStart
*
* Will welcome the player to the program.
*/
public void printStart() {
this.print(0, "Welcome to the program!");
this.print(0, "Please select a game: " + this.availableGames());
}
/**
* Method available games
*
* This will print all the games that are located in the games array in one row.
**/
private String availableGames() {
String names = "";
for (int i = 0; i < games.length; i++) {
names = (names + games[i]);
if (i < games.length -1) {
names = (names + ", ");
}
}
return names;
}
/**
* Method selectGame
*
* This will select the given game.
* #param command The entered command.
**/
public void selectGame(String command) {
if (this.inArray(command))
{
if (command.equalsIgnoreCase("spin")) {
this.startGame("spin");
} else if (command.equalsIgnoreCase("tof")) {
this.startGame("tof");
}
} else {
this.print(0, "Could not find game!");
}
}
/**
* Method inArray
*
* This will check if the entered game name is exisiting in the games array.
* If yes, will return a boolean true, else false.
*
* #param value The entered game name.
* #return boolean true/false.
**/
private boolean inArray(String value) {
int returning = 0;
for (String s : games) {
if (value.equalsIgnoreCase(s)) {
returning = 1;
}
}
if (returning == 1) {
return true;
} else {
return false;
}
}
/**
* Method startGame
*
* Will start the game, and print instructions.
* will set the game boolean to true.
**/
private void startGame(String game) {
switch (game) {
case "spin":
this.print(0, "Welcome to spin game!");
this.print(0, "Please click on any key to spin!");
spinGame = true;
break;
case "tof":
break;
}
inGame = true;
}
/**
* Method continueGame
*
* Will continue the game, either spin again, or print new question or even answer.
* #param command The entered command.
**/
public void continueGame(String command) {
while (inGame) {
if (spinGame) {
this.spinWheel();
// Break out of the loop.
break;
}
}
}
/**
* Method exitGame
*
* Exit the game..
**/
public void exitGame() {
spinGame = false;
tofGame = false;
this.printStart();
}
/**
* Method spinWheel
*
* This will spin the wheel.
**/
private void spinWheel() {
this.print(0, spin.spinWheel());
}
/**
* Method print
*
* Prints text using System.out
* #param type printing type (Println/print).
* #param message The message
**/
private void print(int type, String message) {
switch (type) {
case 0:
System.out.println(message);
break;
case 1:
System.out.print(message);
break;
}
}
}
Spin.java:
package games;
import java.util.Random;
public class Spin {
/**
* The base auth we are going to work with..
**/
private int auth = this.rand(1000) / 5;
/**
* Creating new Random object.
**/
private Random r = new Random();
/**
* Method spinWheel
*
* Spins the damn wheel..
* #return spinned value + if you won or not.
**/
public String spinWheel() {
return this.spinWheel(this.rand(100));
}
/**
* spinWheel
*
* Returning results.
**/
private String spinWheel(int number) {
int result = this.Calculate(this.rand(number));
if (result < 101) {
return "You have won the game!" + result;
} else {
return "You've lost the game!" + result;
}
}
/**
* Method calculate
*
* Calculates the spin.
* #return the spinned number.
**/
private int Calculate(int Number) {
int var = this.rand(101);
int holder = (var * Number) / 2;
return holder + this.auth;
}
/**
* Shortcut for nextInt of Random
**/
public int rand(int x) {
return r.nextInt(x);
}
}
rand is invoked before the Random instance r is initialised. Switch the order or these 2 statements
private int auth = this.rand(1000) / 5;
private Random r = new Random();
should be
private Random r = new Random();
private int auth = this.rand(1000) / 5;
Make the assignment of r the first thing in your Spinwheel class definition, i.e. put it before it is used in this.rand(1000):
public class Spin {
/**
* Creating new Random object.
**/
private Random r = new Random();
/**
* The base auth we are going to work with..
**/
private int auth = this.rand(1000) / 5;
r is null, so you can't call any instance method on r. Make sure you intialize r before using it.
More specifically, in this line:
private int auth = this.rand(1000) / 5;
you're calling the rand() method before r has been initialized (it's initialized right after).
This is the line causing the NullPointerException:
private int auth = this.rand(1000) / 5;
Since this line comes before the initialization for r, you are invoking rand before r was initialized. In that case r is null in rand and that's your exception.
This is obvious from your stack trace:
at games.Spin.rand(Spin.java:68)
at games.Spin.<init>(Spin.java:10)
Note that the exception is happening in the initializer. From there, it's easy to back out what is going on.
You need to initialize r first, that is, move the initialization line for r before the initialization line for auth. Thus:
private Random r = new Random();
private int auth = this.rand(1000) / 5;
This is because r is being used before it is instantiated within statement private int auth = this.rand(1000) / 5; . So , JVM is seeing r as null , which is leading to NPE. To get rid of this problem within Spin class declare the fields as follows:
private Random r = new Random();
private int auth = this.rand(1000) / 5;
I compiled successfully three files and when I tried to launch a class which contains a public static void main then I got errors. Here is the error :
C:\Documents and Settings\Ambre-28\Mes documents\JavaMESDKProjects\exempleRXTX\src\net\net>java Example
Exception in thread "main" java.lang.NoClassDefFoundError: Example (wrong name:
net/Example)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$000(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: Example. Program will exit.
Here are the codes :
package net;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Vector;
/**
* This is a very simple example showing the most basic use of
* {#link net.Network} and {#link net.Network_iface}. Feel free to use,
* overwrite, or just ignore code as you like.
*
* As a default, a connection speed of 115200 baud is assumed. You can use a
* different speed by giving it as an <b>int</b> as the first command line
* argument or changing the default speed in the source code.
*
* #author Raphael Blatter (raphael#blatter.sg)
*/
public class Example implements net.Network_iface {
// set the speed of the serial port
public static int speed = 115200;
private static net.Network network;
private static boolean resend_active = false;
public static void main(String[] args) {
network = new net.Network(0, new net.Example(), 255);
// reading the speed if
if (args.length > 0) {
try {
speed = Integer.parseInt(args[0]);
} catch (NumberFormatException e) {
System.out.println("the speed must be an integer\n");
System.exit(1);
}
}
// initializing reader from command line
int i, inp_num = 0;
String input;
BufferedReader in_stream = new BufferedReader(new InputStreamReader(
System.in));
// getting a list of the available serial ports
Vector<String> ports = network.getPortList();
// choosing the port to connect to
System.out.println();
if (ports.size() > 0) {
System.out.println("the following serial ports have been detected:");
}
else {
System.out.println("sorry, no serial ports were found on your computer\n");
System.exit(0);
}
for (i = 0; i < ports.size(); ++i) {
System.out.println(" " + Integer.toString(i + 1) + ": " + ports.elementAt(i));
}
boolean valid_answer = false;
while (!valid_answer) {
System.out.println("enter the id (1,2,...) of the connection to connect to: ");
try {
input = in_stream.readLine();
inp_num = Integer.parseInt(input);
if ((inp_num < 1) || (inp_num >= ports.size() + 1))
System.out.println("your input is not valid");
else
valid_answer = true;
} catch (NumberFormatException ex) {
System.out.println("please enter a correct number");
} catch (IOException e) {
System.out.println("there was an input error\n");
System.exit(1);
}
}
// connecting to the selected port
if (network.connect(ports.elementAt(inp_num - 1), speed)) {
System.out.println();
} else {
System.out.println("sorry, there was an error connecting\n");
System.exit(1);
}
// asking whether user wants to mirror traffic
System.out.println("do you want this tool to send back all the received messages?");
valid_answer = false;
while (!valid_answer) {
System.out.println("'y' for yes or 'n' for no: ");
try {
input = in_stream.readLine();
if (input.equals("y")) {
resend_active = true;
valid_answer = true;
} else if (input.equals("n")) {
valid_answer = true;
} else if (input.equals("q")) {
System.out.println("example terminated\n");
System.exit(0);
}
} catch (IOException e) {
System.out.println("there was an input error\n");
System.exit(1);
}
}
// reading in numbers (bytes) to be sent over the serial port
System.out.println("type 'q' to end the example");
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
}
System.out.println("\nenter a number between 0 and 254 to be sent ('q' to exit): ");
try {
input = in_stream.readLine();
if (input.equals("q")) {
System.out.println("example terminated\n");
network.disconnect();
System.exit(0);
}
inp_num = Integer.parseInt(input);
if ((inp_num > 255) || (inp_num < 0)) {
System.out.println("the number you entered is not valid");
} else {
int temp[] = { inp_num };
network.writeSerial(1, temp); // ecriture dans le port série
System.out.println("sent " + inp_num + " over the serial port");
}
} catch (NumberFormatException ex) {
System.out.println("please enter a correct number");
} catch (IOException e) {
System.out.println("there was an input error");
}
}
}
/**
* Implementing {#link net.Network_iface#networkDisconnected(int)}, which is
* called when the connection has been closed. In this example, the program
* is ended.
*
* #see net.Network_iface
*/
public void networkDisconnected(int id) {
System.exit(0);
}
/**
* Implementing {#link net.Network_iface#parseInput(int, int, int[])} to
* handle messages received over the serial port. In this example, the
* received bytes are written to command line (0 to 254) and the message is
* sent back over the same serial port.
*
* #see net.Network_iface
*/
public void parseInput(int id, int numBytes, int[] message) {
if (resend_active) {
network.writeSerial(numBytes, message);
System.out.print("received and sent back the following message: ");
} else {
System.out.print("received the following message: ");
}
System.out.print(message[0]);
for (int i = 1; i < numBytes; ++i) {
System.out.print(", ");
System.out.print(message[i]);
}
System.out.println();
}
/**
* Implementing {#link net.Network_iface#writeLog(int, String)}, which is
* used to write information concerning the connection. In this example, all
* the information is simply written out to command line.
*
* #see net.Network_iface
*/
public void writeLog(int id, String text) {
System.out.println(" log: |" + text + "|");
}
}
package net;
import gnu.io.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Vector;
/**
* Used to simplify communication over a Serial port. Using the RXTX-library
* (rxtx.qbang.org), one connection per instance of this class can be handled.
* In addition to handling a connection, information about the available Serial
* ports can be received using this class.
*
* A separate {#link Thread} is started to handle messages that are being
* received over the Serial interface.
*
* This class also makes packages out of a stream of bytes received, using a
* {#link #divider}, and sending these packages as an array of <b>int</b>s (each
* between 0 and 255) to a function implemented by a class implementing the
* {#link net.Network_iface}-interface.
*
* #author Raphael Blatter (raphael#blatter.sg)
* #author heavily using code examples from the RXTX-website (rxtx.qbang.org)
*/
public class Network {
private InputStream inputStream;
private OutputStream outputStream;
/**
* The status of the connection.
*/
private boolean connected = false;
/**
* The Thread used to receive the data from the Serial interface.
*/
private Thread reader;
private SerialPort serialPort;
/**
* Communicating between threads, showing the {#link #reader} when the
* connection has been closed, so it can {#link Thread#join()}.
*/
private boolean end = false;
/**
* Link to the instance of the class implementing {#link net.Network_iface}.
*/
private Network_iface contact;
/**
* A small <b>int</b> representing the number to be used to distinguish
* between two consecutive packages. It can only take a value between 0 and
* 255. Note that data is only sent to
* {#link net.Network_iface#parseInput(int, int, int[])} once the following
* 'divider' could be identified.
*
* As a default, <b>255</b> is used as a divider (unless specified otherwise
* in the constructor).
*
* #see net.Network#Network(int, Network_iface, int)
*/
private int divider;
/**
* <b>int</b> identifying the specific instance of the Network-class. While
* having only a single instance, 'id' is irrelevant. However, having more
* than one open connection (using more than one instance of {#link Network}
* ), 'id' helps identifying which Serial connection a message or a log
* entry came from.
*/
private int id;
private int[] tempBytes;
int numTempBytes = 0, numTotBytes = 0;
/**
* #param id
* <b>int</b> identifying the specific instance of the
* Network-class. While having only a single instance,
* {#link #id} is irrelevant. However, having more than one open
* connection (using more than one instance of Network),
* {#link #id} helps identifying which Serial connection a
* message or a log entry came from.
*
* #param contact
* Link to the instance of the class implementing
* {#link net.Network_iface}.
*
* #param divider
* A small <b>int</b> representing the number to be used to
* distinguish between two consecutive packages. It can take a
* value between 0 and 255. Note that data is only sent to
* {#link net.Network_iface#parseInput(int, int, int[])} once the
* following {#link #divider} could be identified.
*/
public Network(int id, Network_iface contact, int divider) {
this.contact = contact;
this.divider = divider;
if (this.divider > 255)
this.divider = 255;
if (this.divider < 0)
this.divider = 0;
this.id = id;
tempBytes = new int[1024];
}
/**
* Just as {#link #Network(int, Network_iface, int)}, but with a default
* {#link #divider} of <b>255</b>.
*
* #see #Network(int, Network_iface, int)
*/
public Network(int id, Network_iface contact) {
this(id, contact, 255);
}
/**
* Just as {#link #Network(int, Network_iface, int)}, but with a default
* {#link #divider} of <b>255</b> and a default {#link #id} of 0. This
* constructor may mainly be used if only one Serial connection is needed at
* any time.
*
* #see #Network(int, Network_iface, int)
*/
public Network(Network_iface contact) {
this(0, contact);
}
/**
* This method is used to get a list of all the available Serial ports
* (note: only Serial ports are considered). Any one of the elements
* contained in the returned {#link Vector} can be used as a parameter in
* {#link #connect(String)} or {#link #connect(String, int)} to open a
* Serial connection.
*
* #return A {#link Vector} containing {#link String}s showing all available
* Serial ports.
*/
#SuppressWarnings("unchecked")
public Vector<String> getPortList() {
Enumeration<CommPortIdentifier> portList;
Vector<String> portVect = new Vector<String>();
portList = CommPortIdentifier.getPortIdentifiers();
CommPortIdentifier portId;
while (portList.hasMoreElements()) {
portId = (CommPortIdentifier) portList.nextElement();
if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
portVect.add(portId.getName());
}
}
contact.writeLog(id, "found the following ports:");
for (int i = 0; i < portVect.size(); i++) {
contact.writeLog(id, (" " + (String) portVect.elementAt(i)));
}
return portVect;
}
/**
* Just as {#link #connect(String, int)}, but using 115200 bps as a default
* speed of the connection.
*
* #param portName
* The name of the port the connection should be opened to (see
* {#link #getPortList()}).
* #return <b>true</b> if the connection has been opened successfully,
* <b>false</b> otherwise.
* #see #connect(String, int)
*/
public boolean connect(String portName) {
return connect(portName, 115200);
}
/**
* Opening a connection to the specified Serial port, using the specified
* speed. After opening the port, messages can be sent using
* {#link #writeSerial(String)} and received data will be packed into
* packets (see {#link #divider}) and forwarded using
* {#link net.Network_iface#parseInput(int, int, int[])}.
*
* #param portName
* The name of the port the connection should be opened to (see
* {#link #getPortList()}).
* #param speed
* The desired speed of the connection in bps.
* #return <b>true</b> if the connection has been opened successfully,
* <b>false</b> otherwise.
*/
public boolean connect(String portName, int speed) {
CommPortIdentifier portIdentifier;
boolean conn = false;
try {
portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
if (portIdentifier.isCurrentlyOwned()) {
contact.writeLog(id, "Error: Port is currently in use");
} else {
serialPort = (SerialPort) portIdentifier.open("RTBug_network",
2000);
serialPort.setSerialPortParams(speed, SerialPort.DATABITS_8,
SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
inputStream = serialPort.getInputStream();
outputStream = serialPort.getOutputStream();
reader = (new Thread(new SerialReader(inputStream)));
end = false;
reader.start();
connected = true;
contact.writeLog(id, "connection on " + portName
+ " established");
conn = true;
}
} catch (NoSuchPortException e) {
contact.writeLog(id, "the connection could not be made");
e.printStackTrace();
} catch (PortInUseException e) {
contact.writeLog(id, "the connection could not be made");
e.printStackTrace();
} catch (UnsupportedCommOperationException e) {
contact.writeLog(id, "the connection could not be made");
e.printStackTrace();
} catch (IOException e) {
contact.writeLog(id, "the connection could not be made");
e.printStackTrace();
}
return conn;
}
/**
* A separate class to use as the {#link net.Network#reader}. It is run as a
* separate {#link Thread} and manages the incoming data, packaging them
* using {#link net.Network#divider} into arrays of <b>int</b>s and
* forwarding them using
* {#link net.Network_iface#parseInput(int, int, int[])}.
*
*/
private class SerialReader implements Runnable {
InputStream in;
public SerialReader(InputStream in) {
this.in = in;
}
public void run() {
byte[] buffer = new byte[1024];
int len = -1, i, temp;
try {
while (!end) {
if ((in.available()) > 0) {
if ((len = this.in.read(buffer)) > -1) {
for (i = 0; i < len; i++) {
temp = buffer[i];
// adjust from C-Byte to Java-Byte
if (temp < 0)
temp += 256;
if (temp == divider) {
if (numTempBytes > 0) {
contact.parseInput(id, numTempBytes,
tempBytes);
}
numTempBytes = 0;
} else {
tempBytes[numTempBytes] = temp;
++numTempBytes;
}
}
}
}
}
} catch (IOException e) {
end = true;
try {
outputStream.close();
inputStream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
serialPort.close();
connected = false;
contact.networkDisconnected(id);
contact.writeLog(id, "connection has been interrupted");
}
}
}
/**
* Simple function closing the connection held by this instance of
* {#link net.Network}. It also ends the Thread {#link net.Network#reader}.
*
* #return <b>true</b> if the connection could be closed, <b>false</b>
* otherwise.
*/
public boolean disconnect() {
boolean disconn = true;
end = true;
try {
reader.join();
} catch (InterruptedException e1) {
e1.printStackTrace();
disconn = false;
}
try {
outputStream.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
disconn = false;
}
serialPort.close();
connected = false;
contact.networkDisconnected(id);
contact.writeLog(id, "connection disconnected");
return disconn;
}
/**
* #return Whether this instance of {#link net.Network} has currently an
* open connection of not.
*/
public boolean isConnected() {
return connected;
}
/**
* This method is included as a legacy. Depending on the other side of the
* Serial port, it might be easier to send using a String. Note: this method
* does not add the {#link #divider} to the end.
*
* If a connection is open, a {#link String} can be sent over the Serial
* port using this function. If no connection is available, <b>false</b> is
* returned and a message is sent using
* {#link net.Network_iface#writeLog(int, String)}.
*
* #param message
* The {#link String} to be sent over the Serial connection.
* #return <b>true</b> if the message could be sent, <b>false</b> otherwise.
*/
public boolean writeSerial(String message) {
boolean success = false;
if (isConnected()) {
try {
outputStream.write(message.getBytes());
success = true;
} catch (IOException e) {
disconnect();
}
} else {
contact.writeLog(id, "No port is connected.");
}
return success;
}
/**
* If a connection is open, an <b>int</b> between 0 and 255 (except the
* {#link net.Network#divider}) can be sent over the Serial port using this
* function. The message will be finished by sending the
* {#link net.Network#divider}. If no connection is available, <b>false</b>
* is returned and a message is sent using
* {#link net.Network_iface#writeLog(int, String)}.
*
* #param numBytes
* The number of bytes to send over the Serial port.
* #param message
* [] The array of<b>int</b>s to be sent over the Serial
* connection (between 0 and 256).
* #return <b>true</b> if the message could be sent, <b>false</b> otherwise
* or if one of the numbers is equal to the #{#link Network#divider}
* .
*/
public boolean writeSerial(int numBytes, int message[]) {
boolean success = true;
int i;
for (i = 0; i < numBytes; ++i) {
if (message[i] == divider) {
success = false;
break;
}
}
if (success && isConnected()) {
try {
for (i = 0; i < numBytes; ++i) {
outputStream.write(changeToByte(message[i]));
}
outputStream.write(changeToByte(divider));
} catch (IOException e) {
success = false;
disconnect();
}
} else if (!success) {
// message contains the divider
contact.writeLog(id, "The message contains the divider.");
} else {
contact.writeLog(id, "No port is connected.");
}
return success;
}
private byte changeToByte(int num) {
byte number;
int temp;
temp = num;
if (temp > 255)
temp = 255;
if (temp < 0)
temp = 0;
number = (byte) temp;
return number;
}
}
package net;
/**
* An instance of a class implementing this interface has to be passed to the
* constructor of {#link net.Network}. It will be used by {#link net.Network} to
* forward received messages, write to a log and take action when the connection
* is closed.
*
* #see net.Network#Network(int, Network_iface, int)
*
* #author Raphael Blatter (raphael#blatter.sg)
*/
public interface Network_iface {
/**
* Is called to write connection information to the log. The information can
* either be ignored, directed to stdout or written out to a specialized
* field or file in the program.
*
* #param id
* The <b>int</b> passed to
* {#link net.Network#Network(int, Network_iface, int)} in the
* constructor. It can be used to identify which instance (which
* connection) a message comes from, when several instances of
* {#link net.Network} are connected to the same instance of a
* class implementing this interface.
* #param text
* The text to be written into the log in human readable form.
* Corresponds to information about the connection or ports.
*/
public void writeLog(int id, String text);
/**
* Is called when sequence of bytes are received over the Serial interface.
* It sends the bytes (as <b>int</b>s between 0 and 255) between the two
* {#link net.Network#divider}s passed via the constructor of
* {#link net.Network} (
* {#link net.Network#Network(int, Network_iface, int)}), without the
* {#link net.Network#divider}s. Messages are only forwarded using this
* function, once a {#link net.Network#divider} has been recognized in the
* incoming stream.
*
* #param id
* The <b>int</b> passed to
* {#link net.Network#Network(int, Network_iface, int)} in the
* constructor. It can be used to identify which instance a
* message comes from, when several instances of
* {#link net.Network} are connected to the same instance of a
* class implementing this interface.
* #param numBytes
* Number of valid bytes contained in the message
* #param message
* Message received over the Serial interface. The complete array
* of bytes (as <b>int</b>s between 0 and 255) between
* {#link net.Network#divider} is sent (without
* {#link net.Network#divider}s).
*/
public void parseInput(int id, int numBytes, int[] message);
/**
* Is called when the network has been disconnected. This call can e.g. be
* used to show the connection status in a GUI or inform the user using
* other means.
*
* #param id
* {#link net.Network#id} of the corresponding
* {#link net.Network} instance (see {#link net.Network#id}).
*/
public void networkDisconnected(int id);
}
Each class is a separate file. So why this error is raised ?
You should be launching it from the parent directory as
java net.Example
When you run the java command, it takes the full class name, including the package name. So in your case the JVM was trying to find a class just called Example - it found Example.class as a file, but then failed because that class file contains the class net.Example, not Example.
You need to be in the parent directory (...\exempleRXTX\src\net) so that when the JVM looks for net.Example it will look in the ...\exempleRXTX\src\net\net directory for a file called Example.class.
Check where the .class files are being generated and ensure that classpath settings are right, However it seems that ur nt running the `java command' from a proper directory as mentioned by #Jon.
Note: Specifying '.'(single dot) as the classpath value will configure java to search for the .class files in same directory (from where u r trying java command).
I would like to create a version of Java's deflater not synchronizing on its ZStreamRef instance.
I started by copying the code into a Deflater2 class. The code compiles, however, when I create an instance of that class, I get:
Exception in thread "main" java.lang.UnsatisfiedLinkError: net.dwst.bricolo.ResetGZip.Deflater2.initIDs()V
at net.mypackage.Deflater2.initIDs(Native Method)
at net.mypackage.Deflater2.<clinit>(Deflater2.java:65)
at net.mypackage.SpeedTest.main(SpeedTest.java:13)
How can I create an instance of Deflater2 without triggering this exception?
I am providing the code for Deflater2:
package net.mypackage;
public class Deflater2 {
private final ZStreamRef zsRef;
private byte[] buf = new byte[0];
private int off, len;
private int level, strategy;
private boolean setParams;
private boolean finish, finished;
/**
* Compression method for the deflate algorithm (the only one currently
* supported).
*/
public static final int DEFLATED = 8;
/**
* Compression level for no compression.
*/
public static final int NO_COMPRESSION = 0;
/**
* Compression level for fastest compression.
*/
public static final int BEST_SPEED = 1;
/**
* Compression level for best compression.
*/
public static final int BEST_COMPRESSION = 9;
/**
* Default compression level.
*/
public static final int DEFAULT_COMPRESSION = -1;
/**
* Compression strategy best used for data consisting mostly of small
* values with a somewhat random distribution. Forces more Huffman coding
* and less string matching.
*/
public static final int FILTERED = 1;
/**
* Compression strategy for Huffman coding only.
*/
public static final int HUFFMAN_ONLY = 2;
/**
* Default compression strategy.
*/
public static final int DEFAULT_STRATEGY = 0;
static {
/* Zip library is loaded from System.initializeSystemClass */
initIDs();
}
/**
* Creates a new compressor using the specified compression level.
* If 'nowrap' is true then the ZLIB header and checksum fields will
* not be used in order to support the compression format used in
* both GZIP and PKZIP.
* #param level the compression level (0-9)
* #param nowrap if true then use GZIP compatible compression
*/
public Deflater2(int level, boolean nowrap) {
this.level = level;
this.strategy = DEFAULT_STRATEGY;
this.zsRef = new ZStreamRef(init(level, DEFAULT_STRATEGY, nowrap));
}
/**
* Creates a new compressor using the specified compression level.
* Compressed data will be generated in ZLIB format.
* #param level the compression level (0-9)
*/
public Deflater2(int level) {
this(level, false);
}
/**
* Creates a new compressor with the default compression level.
* Compressed data will be generated in ZLIB format.
*/
public Deflater2() {
this(DEFAULT_COMPRESSION, false);
}
/**
* Sets input data for compression. This should be called whenever
* needsInput() returns true indicating that more input data is required.
* #param b the input data bytes
* #param off the start offset of the data
* #param len the length of the data
* #see Deflater#needsInput
*/
public void setInput(byte[] b, int off, int len) {
if (b== null) {
throw new NullPointerException();
}
if (off < 0 || len < 0 || off > b.length - len) {
throw new ArrayIndexOutOfBoundsException();
}
synchronized (zsRef) {
this.buf = b;
this.off = off;
this.len = len;
}
}
/**
* Sets input data for compression. This should be called whenever
* needsInput() returns true indicating that more input data is required.
* #param b the input data bytes
* #see Deflater#needsInput
*/
public void setInput(byte[] b) {
setInput(b, 0, b.length);
}
/**
* Sets preset dictionary for compression. A preset dictionary is used
* when the history buffer can be predetermined. When the data is later
* uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
* in order to get the Adler-32 value of the dictionary required for
* decompression.
* #param b the dictionary data bytes
* #param off the start offset of the data
* #param len the length of the data
* #see Inflater#inflate
* #see Inflater#getAdler
*/
public void setDictionary(byte[] b, int off, int len) {
if (b == null) {
throw new NullPointerException();
}
if (off < 0 || len < 0 || off > b.length - len) {
throw new ArrayIndexOutOfBoundsException();
}
synchronized (zsRef) {
ensureOpen();
setDictionary(zsRef.address(), b, off, len);
}
}
/**
* Sets preset dictionary for compression. A preset dictionary is used
* when the history buffer can be predetermined. When the data is later
* uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
* in order to get the Adler-32 value of the dictionary required for
* decompression.
* #param b the dictionary data bytes
* #see Inflater#inflate
* #see Inflater#getAdler
*/
public void setDictionary(byte[] b) {
setDictionary(b, 0, b.length);
}
/**
* Sets the compression strategy to the specified value.
* #param strategy the new compression strategy
* #exception IllegalArgumentException if the compression strategy is
* invalid
*/
public void setStrategy(int strategy) {
switch (strategy) {
case DEFAULT_STRATEGY:
case FILTERED:
case HUFFMAN_ONLY:
break;
default:
throw new IllegalArgumentException();
}
synchronized (zsRef) {
if (this.strategy != strategy) {
this.strategy = strategy;
setParams = true;
}
}
}
/**
* Sets the current compression level to the specified value.
* #param level the new compression level (0-9)
* #exception IllegalArgumentException if the compression level is invalid
*/
public void setLevel(int level) {
if ((level < 0 || level > 9) && level != DEFAULT_COMPRESSION) {
throw new IllegalArgumentException("invalid compression level");
}
synchronized (zsRef) {
if (this.level != level) {
this.level = level;
setParams = true;
}
}
}
/**
* Returns true if the input data buffer is empty and setInput()
* should be called in order to provide more input.
* #return true if the input data buffer is empty and setInput()
* should be called in order to provide more input
*/
public boolean needsInput() {
return len <= 0;
}
/**
* When called, indicates that compression should end with the current
* contents of the input buffer.
*/
public void finish() {
synchronized (zsRef) {
finish = true;
}
}
/**
* Returns true if the end of the compressed data output stream has
* been reached.
* #return true if the end of the compressed data output stream has
* been reached
*/
public boolean finished() {
synchronized (zsRef) {
return finished;
}
}
/**
* Fills specified buffer with compressed data. Returns actual number
* of bytes of compressed data. A return value of 0 indicates that
* needsInput() should be called in order to determine if more input
* data is required.
* #param b the buffer for the compressed data
* #param off the start offset of the data
* #param len the maximum number of bytes of compressed data
* #return the actual number of bytes of compressed data
*/
public int deflate(byte[] b, int off, int len) {
if (b == null) {
throw new NullPointerException();
}
if (off < 0 || len < 0 || off > b.length - len) {
throw new ArrayIndexOutOfBoundsException();
}
synchronized (zsRef) {
ensureOpen();
return deflateBytes(zsRef.address(), b, off, len);
}
}
/**
* Fills specified buffer with compressed data. Returns actual number
* of bytes of compressed data. A return value of 0 indicates that
* needsInput() should be called in order to determine if more input
* data is required.
* #param b the buffer for the compressed data
* #return the actual number of bytes of compressed data
*/
public int deflate(byte[] b) {
return deflate(b, 0, b.length);
}
/**
* Returns the ADLER-32 value of the uncompressed data.
* #return the ADLER-32 value of the uncompressed data
*/
public int getAdler() {
synchronized (zsRef) {
ensureOpen();
return getAdler(zsRef.address());
}
}
/**
* Returns the total number of uncompressed bytes input so far.
*
* <p>Since the number of bytes may be greater than
* Integer.MAX_VALUE, the {#link #getBytesRead()} method is now
* the preferred means of obtaining this information.</p>
*
* #return the total number of uncompressed bytes input so far
*/
public int getTotalIn() {
return (int) getBytesRead();
}
/**
* Returns the total number of uncompressed bytes input so far.</p>
*
* #return the total (non-negative) number of uncompressed bytes input so far
* #since 1.5
*/
public long getBytesRead() {
synchronized (zsRef) {
ensureOpen();
return getBytesRead(zsRef.address());
}
}
/**
* Returns the total number of compressed bytes output so far.
*
* <p>Since the number of bytes may be greater than
* Integer.MAX_VALUE, the {#link #getBytesWritten()} method is now
* the preferred means of obtaining this information.</p>
*
* #return the total number of compressed bytes output so far
*/
public int getTotalOut() {
return (int) getBytesWritten();
}
/**
* Returns the total number of compressed bytes output so far.</p>
*
* #return the total (non-negative) number of compressed bytes output so far
* #since 1.5
*/
public long getBytesWritten() {
synchronized (zsRef) {
ensureOpen();
return getBytesWritten(zsRef.address());
}
}
/**
* Resets deflater so that a new set of input data can be processed.
* Keeps current compression level and strategy settings.
*/
public void reset() {
synchronized (zsRef) {
ensureOpen();
reset(zsRef.address());
finish = false;
finished = false;
off = len = 0;
}
}
/**
* Closes the compressor and discards any unprocessed input.
* This method should be called when the compressor is no longer
* being used, but will also be called automatically by the
* finalize() method. Once this method is called, the behavior
* of the Deflater object is undefined.
*/
public void end() {
synchronized (zsRef) {
long addr = zsRef.address();
zsRef.clear();
if (addr != 0) {
end(addr);
buf = null;
}
}
}
/**
* Closes the compressor when garbage is collected.
*/
protected void finalize() {
end();
}
private void ensureOpen() {
assert Thread.holdsLock(zsRef);
if (zsRef.address() == 0)
throw new NullPointerException("Deflater has been closed");
}
private static native void initIDs();
private native static long init(int level, int strategy, boolean nowrap);
private native static void setDictionary(long addr, byte[] b, int off,
int len);
private native int deflateBytes(long addr, byte[] b, int off, int len);
private native static int getAdler(long addr);
private native static long getBytesRead(long addr);
private native static long getBytesWritten(long addr);
private native static void reset(long addr);
private native static void end(long addr);
}
Your problem is not in java code.
There can be the following reasons:
the library that you are using or other library that your library depends on is not in library path (java.library.path option)
One of the native libraries you try to use does not match your platforms. For example you are running on 32 bit platform and trying to use 64bit library.
Take a look here: How to add native library to "java.library.path" with Eclipse launch (instead of overriding it)