Can anyone help me do this a bit better, I have an ArrayList with data been added everytime a question is answered in the session by calling the method saveQuestionToPlayersQuestion(), after all questions are answered the savePlayersQuestionsToDB() meth is called. I Have a Table in the schema for that data.
I have it working and saving to database, but don't think its the correct way of doing it.
Can I just Insert the arraylist at once, meaning instead of calling the
ConnectionClass.createPlaySessionInDB(pQ.getPlayer_id(),
pQ.getQuestion_tbl_id(), pQ.getAns(),
pQ.getPlayer_score(), pQ.getPlay_session_id());
for every object that's in the List, Its OK when only 3 question are answered, But what happens if they have to answer 20 or 30+ question. Is there a better way.
My declared ArrayList
private ArrayList<Play_Questions> playQuestionList;
playQuestionList = new ArrayList<Play_Questions>();
Here is the method I call to save each question answered to playQuestionList and the next method savePlayersQuestionsToDB() is the one called to save all the object to the DB using a enhanced for loop.
/**
* add the question to playQuestionList
*/
public void saveQuestionToPlayersQuestion() {
Play_Questions temp = new Play_Questions(playerId, question_tbl_id,
choosenAnswer, scorePerQuestion, nextPlaySessionId);
playQuestionList.add(temp);
playQuestionList.toString();
}
/**
* save the playQuestion to DataBase
*/
public void savePlayersQuestionsToDB() {
for (Play_Questions pQ : playQuestionList) {
if (pQ == null) {
System.out.println("Play Question List is empty");
} else
try {
ConnectionClass.createPlaySessionInDB(pQ.getPlayer_id(),
pQ.getQuestion_tbl_id(), pQ.getAns(),
pQ.getPlayer_score(), pQ.getPlay_session_id());
System.out.println("Worked check DB --->>");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out
.println("Error with ElbtView savePlayersQuestionsToDB()");
}
}
Here is the method in the Connection Class
public static void createPlaySessionInDB(int player_id,
int question_tbl_id, String ans, int player_score,
int play_session_id) throws SQLException {
String sql = "INSERT INTO player_questions (id, player_id, question_tbl_id, ans, player_score, play_session_id ) VALUES (null,?,?,?,?,?)";
try {
preparedStatement = preparedStatement(sql);
preparedStatement.setInt(1, player_id);
preparedStatement.setInt(2, question_tbl_id);
preparedStatement.setString(3, ans);
preparedStatement.setInt(4, player_score);
preparedStatement.setInt(5, play_session_id);
// execute the SQL statement
preparedStatement.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out
.println("Problem with ConnectionClass createPlaySessionInDB method: "
+ e.getMessage());
} finally {
// close the connection
getConnection().close();
}
}
Here is the Play_Questions class
public class Play_Questions {
private int player_id;
private int question_tbl_id;
private String ans;
private int player_score;
private int play_session_id;
/**
* Default Constructor
*/
public Play_Questions(){
this(0,0,null,0,0);
}
/**
* #param player_id:
* the players id
* #param question_tbl_id:
* the question id from question table
* #param ans:
* the answer selected by player
* #param player_score:
* the score they achieved for answering
* #param play_session_id:
* the play session id
*/
public Play_Questions(int player_id, int question_tbl_id, String ans,
int player_score, int play_session_id) {
this.player_id = player_id;
this.question_tbl_id = question_tbl_id;
this.ans = ans;
this.player_score = player_score;
this.play_session_id = play_session_id;
}
/**
* #return the player_id
*/
public int getPlayer_id() {
return player_id;
}
/**
* #param player_id the player_id to set
*/
public void setPlayer_id(int player_id) {
this.player_id = player_id;
}
/**
* #return the question_tbl_id
*/
public int getQuestion_tbl_id() {
return question_tbl_id;
}
/**
* #param question_tbl_id the question_tbl_id to set
*/
public void setQuestion_tbl_id(int question_tbl_id) {
this.question_tbl_id = question_tbl_id;
}
/**
* #return the ans
*/
public String getAns() {
return ans;
}
/**
* #param ans the ans to set
*/
public void setAns(String ans) {
this.ans = ans;
}
/**
* #return the player_score
*/
public int getPlayer_score() {
return player_score;
}
/**
* #param player_score the player_score to set
*/
public void setPlayer_score(int player_score) {
this.player_score = player_score;
}
/**
* #return the play_session_id
*/
public int getPlay_session_id() {
return play_session_id;
}
/**
* #param play_session_id the play_session_id to set
*/
public void setPlay_session_id(int play_session_id) {
this.play_session_id = play_session_id;
}
Your help in making me code this a bit better will be greatly appreciate.
Gman
This is my approach , its best you use a very transparent approach that models the problem close to a real life scenario .
public class Question
{
private int question_no ;
// The right answer for this question may be a , b or c
private String question_answer ;
private int question_point ;
public Question()
{
}
/**
* #return the question_id
*/
public int getQuestion_id() {
return question_no;
}
/**
* #param question_id the question_id to set
*/
public void setQuestion_id(int question_id) {
this.question_no = question_id;
}
/**
* #return the question_answer
*/
public String getQuestion_answer() {
return question_answer;
}
/**
* #param question_answer the question_answer to set
*/
public void setQuestion_answer(String question_answer) {
this.question_answer = question_answer;
}
/**
* #return the question_point
*/
public int getQuestion_point() {
return question_point;
}
/**
* #param question_point the question_point to set
*/
public void setQuestion_point(int question_point) {
this.question_point = question_point;
}
}
Now the answer class
/**
*
* Track an answer
*/
public class Answer
{
private String answer ;
// correct or failed
private String status ;
public Answer()
{
}
/**
* #return the answer
*/
public String getAnswer() {
return answer;
}
/**
* #param answer the answer to set
*/
public void setAnswer(String answer) {
this.answer = answer;
}
/**
* #return the status
*/
public String getStatus() {
return status;
}
/**
* #param status the status to set
*/
public void setStatus(String status) {
this.status = status;
}
}
Now the player class that encapsulates all the operations for each player after successful login a player object is added to session , it handles operations like marks , save to db ,etc
/**
*
* encapsulates a player
* Class should be placed in session for web applications
*/
public class Player
{
String username ;
String password ;
// holds all the questions arranged for this player without allowing duplicates in questions
Set questions = new HashSet<Question>();
// map this players question and answer
Map question_answers = new HashMap<Question, Answer>();
/**
*
* Allows you to dynamically set questions for players
* #param questions_
*/
public Player(Set questions_ )
{
this.questions = questions_;
}
// if you want the same set of questions for all players
public Player()
{
}
/**
* Question answered for this particular user
* please note that the player object is in session if it is a web application
* #param q
* #param a
*/
public void answerQuestion(Question q , Answer a)
{
question_answers.put(q, a);
}
/**
*
* The user might go back to a previous question to change an answer
* #param q
* #param a
*/
public void updateAnswer(Question q, Answer a)
{
// remove the question and update it with
if(question_answers.containsKey(q))
{
question_answers.remove(q);
}
// add the new q & a
answerQuestion(q, a);
}
/**
*
* finally save the players data
* here your db model counts it would have to cater for
* each players question and answer , send the batch update using batch prepared statements
*/
public void savePlayerData()
{
// db code is commented because i didnt write db codes
// status int the column will stand for correct or fail
// String save_sql =insert into results(player_id , question_id , answer , status) values(?,?,?,?)
// PreparedStatement pstat = dbConnection.prepareStatement(save_sql);
//dbConnection.setAutoCommit(false);
// if automark is enabled
autoMark();
Iterator it = question_answers.values().iterator();
while(it.hasNext())
{
// fetch each question
Question q = (Question)it.next();
// Fetch each answer based on the question
Answer a = (Answer)question_answers.get(q);
int question_id = q.getQuestion_id();
String answer = a.getAnswer();
String answer_status = a.getStatus();
/**
*
*
* commented cause i would have to write db backing code , lol !
*
* pstat.setInt(1, getUsername());
* pstat.setInt(2, question_id);
* pstat.setString(3 , answer);
* pstat.setString(4 , answer_status)
* pstat.addBatch();
* pstat.executeBatch();
*
*/
}
//dbConnection.setAutoCommit(false);
}
/**
*
* This method can allow your program to auto mark if
* the question and answer if it is based on a , b , c
*/
public void autoMark()
{
Iterator it = question_answers.values().iterator();
while(it.hasNext())
{
// fetch each question
Question q = (Question)it.next();
// Fetch each answer based on the question
Answer a = (Answer)question_answers.get(q);
if(q.getQuestion_answer().equalsIgnoreCase(a.getAnswer()))
{
a.setStatus("Correct");
}
else
{
a.setStatus("Failed");
}
updateAnswer(q, a);
}
}
}
So anytime a player answers a question u call
p.answerQuestion(Question q , Answer a)
The question object is the particular question answered and the answer object is created to ,match the question .
U can also track the users current question by adding a value called current_question on the player class with getter and setter(Question Object) to track the current question in cases where the user might go back to a previous question you can then call
p.updateAnswer(Question q, Answer a)
Same thing u pass the particular question an d the new answer object
p.savePlayerData()
Saves data to the db
p.autoMark()
This method is called in the p.savePlayerData() method before the records are saved so the db only holds final assessment & marked records , This can come in handy for intelligent reporting such as who has the highest score . Thats it if you have extra questions you can contact me tyger2007#gmail.com.
Ok I did manage to achieve what I was trying to do, here is the revised code to help others that have the same problem. This is not the definite way to do this just the only way I know at this time to acheive what I need to. If anyone has a nice, faster way of doing this I would love to know. Got some inspiration from this thread here Java: Insert multiple rows into MySQL with PreparedStatement
Here is the method I call to save each question answered to playQuestionList and the next method savePlayersQuestionsToDB(), Instead of doing the work here I pass the Arraylist to the Connection Class and loop through it there.
/**
* add the question to playQuestionList
*/
public void saveQuestionToPlayersQuestion() {
Play_Questions temp = new Play_Questions(playerId, question_tbl_id,
choosenAnswer, scorePerQuestion, nextPlaySessionId);
playQuestionList.add(temp);
}
/**
* save the playQuestion to DataBase
*/
public void savePlayersQuestionsToDB() {
try {
ConnectionClass.savePlaySessionInDB(playQuestionList);
System.out.println("Worked check DB --->>");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out
.println("Error with ElbtView savePlayersQuestionsToDB()");
}
}
and here is the method in the ConnectionClass
/**
* Creates a batch using addBatch()and then executes it by calling
* ececuteBatch()
*
* #param playQuestions
* the ArrayList<T> to be added to batch and then saved to DB
* #throws SQLException
* when executing the the batch
*/
public static void savePlaySessionInDB(
ArrayList<Play_Questions> playQuestions) throws SQLException {
try {
String sql = "INSERT INTO player_questions (id, player_id, question_tbl_id, ans, player_score, play_session_id ) VALUES (null,?,?,?,?,?)";
preparedStatement = preparedStatement(sql);
for (int i = 0; i < playQuestions.size(); i++) {
Play_Questions playQuestion = playQuestions.get(i);
preparedStatement.setInt(1, playQuestion.getPlayer_id());
preparedStatement.setInt(2, playQuestion.getQuestion_tbl_id());
preparedStatement.setString(3, playQuestion.getAns());
preparedStatement.setInt(4, playQuestion.getPlayer_score());
preparedStatement.setInt(5, playQuestion.getPlay_session_id());
preparedStatement.addBatch();
if ((i + 1) % 100 == 0) {
preparedStatement.executeBatch(); // excute every 100 items
}
}
preparedStatement.executeBatch();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out
.println("Problem with ConnectionClass savePlaySessionInDB(ArrayList<Play_Questions> playQuestions) method: "
+ e.getMessage());
} finally {
// close the connection
getConnection().close();
}
}
Defiantly open to a much better suggestion.
Gman
I must say that as this solution actually works perfectly now , in the long hol it might still pose some problems it actually depends on the nature of your application , is it an application that will be deployed and used by a lot of users ? or its just a test application ?, Anyway i do advise that you model your objects properly as this is the most important thing in object oriented programming ,
My suggestions :
Isolate Question , Player , Answer Objects , Having Objects Like Play_Question will make your application difficult to extend dynamically .
Use an Iterator for your loops , its been optimized to perform better than for loops especially in collection.
For me i naturally use a singleton connection class if it is a desktop application & JNDI if its a web application , the connection class uses a connection pool so my application does not open a new connection for every db request , it makes your application super fast in db request [http://jolbox.com/ bonecp connection pooling for Desktop apps if web use JNDI ]
Maps are very easy to use its a case of key/value pairs , All the same nice work and have fun. .
It's ok ,spent quite some time developing applications that generally I always develop to scale ,lol ,I used iterators in the Players class in the method savePlayerData() u can always use it with your collection classes .
Related
Trying to print the username in the method printShortSummary in the MessagePost class. The username is private in the Post class. Doing this for educational purposes. Still getting error that the username is private in Post.
import java.util.ArrayList;
/**
* This class stores information about a news feed post in a
* social network. Posts can be stored and displayed. This class
* serves as a superclass for more specific post types.
*
* #author Michael Kölling and David J. Barnes
* #version 0.2
*/
public class Post
{
private String username; // username of the post's author
private long timestamp;
private int likes;
private ArrayList<String> comments;
/**
* Constructor for objects of class Post.
*
* #param author The username of the author of this post.
*/
public Post(String author)
{
username = author;
timestamp = System.currentTimeMillis();
likes = 0;
comments = new ArrayList<>();
}
public void getUserName()
{
getUserName();
}
/**
* Record one more 'Like' indication from a user.
*/
public void like()
{
likes++;
}
/**
* Record that a user has withdrawn his/her 'Like' vote.
*/
public void unlike()
{
if (likes > 0) {
likes--;
}
}
/**
* Add a comment to this post.
*
* #param text The new comment to add.
*/
public void addComment(String text)
{
comments.add(text);
}
/**
* Return the time of creation of this post.
*
* #return The post's creation time, as a system time value.
*/
public long getTimeStamp()
{
return timestamp;
}
/**
* Display the details of this post.
*
* (Currently: Print to the text terminal. This is simulating display
* in a web browser for now.)
*/
public void display()
{
System.out.println(username);
System.out.print(timeString(timestamp));
if(likes > 0) {
System.out.println(" - " + likes + " people like this.");
}
else {
System.out.println();
}
if(comments.isEmpty()) {
System.out.println(" No comments.");
}
else {
System.out.println(" " + comments.size() + " comment(s). Click here to view.");
}
}
/**
* Create a string describing a time point in the past in terms
* relative to current time, such as "30 seconds ago" or "7 minutes ago".
* Currently, only seconds and minutes are used for the string.
*
* #param time The time value to convert (in system milliseconds)
* #return A relative time string for the given time
*/
private String timeString(long time)
{
long current = System.currentTimeMillis();
long pastMillis = current - time; // time passed in milliseconds
long seconds = pastMillis/1000;
long minutes = seconds/60;
if(minutes > 0) {
return minutes + " minutes ago";
}
else {
return seconds + " seconds ago";
}
}
}
import java.util.ArrayList;
/**
* This class stores information about a post in a social network news feed.
* The main part of the post consists of a (possibly multi-line)
* text message. Other data, such as author and time, are also stored.
*
* #author Michael Kölling and David J. Barnes
* #version 0.2
*/
public class MessagePost extends Post
{
private String message; // an arbitrarily long, multi-line message
/**
* Constructor for objects of class MessagePost.
*
* #param author The username of the author of this post.
* #param text The text of this post.
*/
public MessagePost(String author, String text)
{
super(author);
message = text;
}
public static void printShortSummary()
{
Post.getUserName();
System.out.print ("Message postfrom" + username);
}
/**
* Return the text of this post.
*
* #return The post's message text.
*/
public String getText()
{
return message;
}
}
You should be calling getUserName() but obviously cannot because it returns void and causes a Stack Overflow exception if called:
public void getUserName()
{
getUserName();
}
This should be
public String getUserName()
{
return userName;
}
And then that's how you access the user name from the subclass.
After that you would modify this method to be:
public static void printShortSummary()
{
//Post.getUserName();
System.out.print ("Message postfrom" + getUserName());
}
The portion where you have Post.getUserName(); doesn't make any sense, it's not a static method and can't be referenced in that manner.
If you don't have access to Post class or you don't wanna change Post class, you can use java Reflection API to access private members in any class
Ex:
public void printShortSummary() throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field field = Post.class.getDeclaredField("username");
field.setAccessible(true);
System.out.print("Message post from " + field.get(this).toString());
}
Note : Anyway this not the object oriented way
I just started using Realm in my current android app and so far it is great.
Unfortunately I´ve encountered a problem:
In my app the user can add different kind of entries (What did he eat this day? What drinks did he have?, etc.) into his diary.
One DiaryEntry object represents the sum off all entries for a given day (e.g. 21.05.2017, etc.).
public class DiaryEntry extends RealmObject {
// ID of the day this diary entry represents
#PrimaryKey private Integer dateId;
private RealmList<MealEntry> mealEntries;
private RealmList<DrinkEntry> drinkEntries;
private RealmList<SymptomEntry> symptomEntries;
private RealmList<MedicineEntry> medicineEntries;
public void addMealEntry(MealEntry mealEntry) {
mealEntries.add(mealEntry);
}
public RealmList<MealEntry> getMealEntries() {
return mealEntries;
}
public void addDrinkEntry(DrinkEntry drinkEntry) {
drinkEntries.add(drinkEntry);
}
public RealmList<DrinkEntry> getDrinkEntries() {
return drinkEntries;
}
public void addSymptomEntry(SymptomEntry symptomEntry) {
symptomEntries.add(symptomEntry);
}
public RealmList<SymptomEntry> getSymptomEntries() {
return symptomEntries;
}
public void addMedicineEntry(MedicineEntry medicineEntry) {
medicineEntries.add(medicineEntry);
}
public RealmList<MedicineEntry> getMedicineEntries() {
return medicineEntries;
}
}
To display this data for a particular day in the diary, all entries should be sorted by the time the user created them.
So every entry object contains a field 'time'.
private int time;
I came up with a temporary solution for my problem, but it´s far from perfect.
The follwing code is executed on the UI Thread, which obviously is bad practice.
List<RealmObject> entryList = new ArrayList<>();
OrderedRealmCollectionSnapshot<MealEntry> mealEntries = diaryEntry.getMealEntries().createSnapshot();
OrderedRealmCollectionSnapshot<DrinkEntry> drinkEntries = diaryEntry.getDrinkEntries().createSnapshot();
OrderedRealmCollectionSnapshot<MedicineEntry> medicineEntries = diaryEntry.getMedicineEntries().createSnapshot();
OrderedRealmCollectionSnapshot<SymptomEntry> symptomEntries = diaryEntry.getSymptomEntries().createSnapshot();
entryList.addAll(mealEntries);
entryList.addAll(drinkEntries);
entryList.addAll(medicineEntries);
entryList.addAll(symptomEntries);
Collections.sort(entryList, entryComparator);
The code to sort the entry list uses reflection by invoking the getter method for the time field:
public int compare(RealmObject entry1, RealmObject entry2) {
try {
Method timeGetter1 = entry1.getClass().getMethod("getTime");
Method timeGetter2 = entry2.getClass().getMethod("getTime");
int time1 = (Integer) timeGetter1.invoke(entry1);
int time2 = (Integer) timeGetter2.invoke(entry2);
return time1 - time2;
} catch (NoSuchMethodException e) {
e.printStackTrace();
Timber.d("No such method 'getTime'.");
}
// Other catch clauses
As I said earlier, all of this happens on the UI thread.
I know that I can´t pass RealmObjects, RealmLists and RealmResults across threads so I really have a hard time coming up with an async solution for that. I thought of starting a background thread and in there create copies of all the RealmList´s inside a DiaryEntry object. Then merge this unmanaged lists and sort it - all of that on the background thread.
So my question: Are there any preferred strategies for merging multiple RealmLists and sorting the merged list - all of that in an async fashion? Would my attempt I described above work?
Thanks #EpicPandaForce
I solved it exactly the way you described it and it works like a charm - now I even have the real-time functionality and no need to refresh the data manually, Nice :)
In case anybody faces the same problem I post some code pieces here that show how I solved it in code.
public class Entry extends RealmObject {
private static final int ENTRY_MEAL = 0;
private static final int ENTRY_DRINK = 1;
private static final int ENTRY_SYMPTOM = 2;
private static final int ENTRY_MEDICINE = 3;
/** The tag describes what kind of entry it represents */
private int tag;
/* Only one of these can be set, according to what this entry represents. */
#Nullable private MealEntry mealEntry;
#Nullable private DrinkEntry drinkEntry;
#Nullable private SymptomEntry symptomEntry;
#Nullable private MedicineEntry medicineEntry;
/** The time value this entry was created at */
/** Format: hours + minutes * 60 */
private int time;
public int getTime() {
return time;
}
/* Can only be accessed from within the 'data' package */
void setTime(int time) {
this.time = time;
}
/**
* Creates a new entry object in the realm database and tags it as 'MEAL'
*
* #param realm not null
* #param mealEntry the {#link MealEntry} object to map this entry to, not null
*
* #return the newly created entry
*/
static Entry createEntryAsMeal(#NonNull final Realm realm, #NonNull final MealEntry mealEntry) {
if(realm == null) {
throw new IllegalArgumentException("'realm' may not be null");
}
if(mealEntry == null) {
throw new IllegalArgumentException("'mealEntry' may not be null");
}
Entry entry = realm.createObject(Entry.class);
entry.tag = ENTRY_MEAL;
entry.mealEntry = mealEntry;
return entry;
}
/* Same methods for other tag types ... */
In MealEntry.class:
public class MealEntry extends RealmObject {
#PrimaryKey #Required private String id;
#Required private String title;
/** The entry objects this meal-entry is added to */
Entry entry;
/** This time value describes when the user consumed this meal **/
private int time;
// other fields
/**
* Creates a new MealEntry object in the realm.
* <p>
* Note: It is important to use this factory method for creating {#link MealEntry} objects in realm.
* Under the hood, a {#link Entry} object is created for every MealEntry and linked to it.
* </p>
*
* #param realm not null
*
* #return new MealEntry object which has been added to the <code>realm</code>
*/
public static MealEntry createInRealm(#NonNull Realm realm) {
if(realm == null) {
throw new IllegalArgumentException("'realm' may not be null");
}
MealEntry mealEntry = realm.createObject(MealEntry.class, UUID.randomUUID().toString());
mealEntry.entry = Entry.createEntryAsMeal(realm, mealEntry);
return mealEntry;
}
The 'time' field exists in the Entry.class and MealEntry.class so if the latter one changes the Entry must be updated accordingly:
/**
* Sets the time value for the <code>mealEntry</code> to the specified value.
* <p>
* Note: This method is necessary in order to sync the new time value with the underlying
* {#link Entry} object that is connected with the <code>mealEntry</code>.
* </p>
*
* #param mealEntry the {#link MealEntry} object to set the time for, not null
*
* #param time the new time value, must be in range of [0, 24*60] because of the format: hours*60 + minutes
*
*/
public static void setTimeForMealEntry(#NonNull MealEntry mealEntry, #IntRange(from=0, to=24*60) int time) {
if(mealEntry == null) {
throw new IllegalArgumentException("'mealEntry' may not be null");
}
mealEntry.setTime(time);
Entry entry = mealEntry.entry;
if(entry == null) {
throw new IllegalStateException("'mealEntry' contains no object of type 'Entry'! Something went wrong on creation of the 'mealEntry'");
}
/* Syncs the entries time value with the time value for this MealEntry. */
/* That´s important for sorting a list of all entries. */
entry.setTime(time);
}
Note: I could have stored only the ID of the corresponding Entry object inside the MealEntry and vice-versa for the Entry object store an ID to the corresponding MealEntry object. However I don´t know what a difference in perfomance this makes so I just went with the above approach.
One reason for the other approach though would be that I wouldn´t have to store the 'time' field twice, once in the Entry.class and once in the MealEntry.class, because in the Entry.class I could just get the time value by finding the corresponding MealEntry object by its ID and then get the time.
I'm trying to implement a small Java program which shows how process scheduling works. My current code is below. The issue I'm having is with the static method CPU.executeInstructions(Process process) and firstComeFirstServed() from the ProcessScheduler class. My program currently won't compile as it gives
incompatible type error: Object can not be converted to Process
from within firstComeFirstServed().
I've managed to make it compile by changing executeInstructions() argument from Process process to Object process, but as far as I can see there is nothing wrong with the previous method signature. I've thrown a couple of System.out.println() calls in around the program to print the class to the screen, which confirms that the object being operated on is a Process object. Can somebody explain what is going on here? What am I missing/not understanding?
package processes;
import java.util.logging.Level;
import java.util.logging.Logger;
import processes.ProcessScheduler.Algorithm;
public class ProcessManager {
private static Thread psThread;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// Create process table
ProcessTable pt;
//System.out.println("1 " + pt.getClass());
// Creat Process Scheduling Thread.
psThread = new Thread(new ProcessScheduler(Algorithm.FIRST_COME_FIRST_SERVE, pt = new ProcessTable()));
System.out.println("2 " + pt.getClass());
// Start Thread
psThread.start();
System.out.println("3 " + pt.getClass());
try {
// Add Process' to table
String[] instrucSet = {"sout","name"};
for(int i = 0; i < 5; i++){
pt.add(new Process(ProcessTable.processCounter, i + 1, 10 - i, instrucSet));
}
Thread.sleep(4000);
for(int i = 0; i < 5; i++){
pt.add(new Process(ProcessTable.processCounter, i + 1, 10 - i, instrucSet));
}
Thread.sleep(2000);
ProcessScheduler.run = false;
} catch (InterruptedException ex) {
Logger.getLogger(ProcessManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
package processes;
public class Process {
private int quanta, priority, pID;
private String [] instructions;
/**
* Constructor for Process class.
* #param p_id process id
* #param instruction_set Instructions to be processed by the CPU.
* #param quanta Represents length of time (known or estimated) taken to execute process
*/
public Process(int p_id, int quanta, String instruction_set[]){
// Initialise instance variables
this.pID = p_id;
this.quanta = quanta;
this.instructions = instruction_set;
}
/**
* Constructor for Process class.
* #param quanta Represents length of time (known or estimated) taken to execute process
* #param priority Represents the priority of the process, from 1 to infinity with 1 having highest priority.
* #param instruction_set Instructions to be processed by the CPU.
*/
public Process(int p_id,int quanta, int priority, String instruction_set[]){
// Initialise instance variables
this.pID = p_id;
this.quanta = quanta;
this.priority = priority;
this.instructions = instruction_set;
}
/**
* #return Returns length of process, which may either be a known or estimated quantity.
*/
public int getQuanta() {
return quanta;
}
/**
* #return Returns process priority level.
*/
public int getPriority() {
return priority;
}
/**
* #return Returns process id, a unique value generated when the process is accepted onto the process table.
*/
public int getpID() {
return pID;
}
/**
* #return Returns an array holding the instructions to be processed for this process.
*/
public String[] getInstructions() {
return instructions;
}
#Override
public String toString(){
return "Process ID: " + this.getpID() + ". Quanta: " + this.getQuanta() + ". Priority: " + this.getPriority();
}
}
package processes;
import java.util.ArrayList;
/**
*
* #author dave
*/
public class ProcessTable extends ArrayList {
// P_id counter;
public static int processCounter = 0;
public ProcessTable(){
super();
}
/**
* Adds the specified process to the collection and increments the processCounter
* #param aProcess The process to be added to the Process Table.
* #return Returns true if successfully added.
*/
public boolean add(Process aProcess){
boolean sucessful = super.add(aProcess);
if(sucessful)
processCounter++;
return sucessful;
}
/**
* Prints the process table to console.
*/
public void displayProcessTable(){
for(int i = 0; i < this.size(); i++){
System.out.println(this.get(i).toString());
}
}
}
package processes;
/**
*
* #author dave
*/
public final class CPU {
private CPU(){
}
public static void executeInstructions(Process process){
System.out.println(process.toString());
}
}
package processes;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author dave
*/
public class ProcessScheduler implements Runnable {
public static boolean run;
// The algorithm to be used.
private String alg;
// To hold reference to a Proces Table.
public static ProcessTable pt;
// Class constants for scheduling algorithm type. Used in class constructor.
// Enum for
public enum Algorithm {FIRST_COME_FIRST_SERVE, SHORTEST_JOB_FIRST, ROUND_ROBIN, PRIORITY_QUEUE};
/**
* #param scheduling_algorithm Sets the scheduling algorithm to be used when
* #param process_table A Process Table instant that Process will be added to.
* passing jobs to the CPU for execution.
*/
public ProcessScheduler(Algorithm scheduling_algorithm, ProcessTable process_table){
//System.out.println("4 " + pt.getClass());
// Create reference Process Table
//pt = new ProcessTable();
pt = process_table;
System.out.println("5 " + pt.getClass());
// Start scheduling based on algorithm represented by enum in constructor arg.
switch(scheduling_algorithm){
case FIRST_COME_FIRST_SERVE:
alg = "fcfs";
break;
case SHORTEST_JOB_FIRST:
alg = "sjf";
break;
case ROUND_ROBIN:
alg = "rr";
case PRIORITY_QUEUE:
alg = "pq";
default:
alg = "pq";
break;
}
}
/**
* Start Scheduling processes to the CPU
*/
public void run() {
//boolean run = true;
int sleepTime = 1000;
//Display algorithm to screen
try {
run = true;
while(run){
if(!pt.isEmpty()){
switch (alg) {
case "fcfs":
System.out.println("6 " + pt.getClass());
firstComeFirstServed();
break;
case "sjf":
shortestJobFirst();
break;
case "rr":
roundRobin();
break;
case "pq":
priorityQueue();
break;
}
} else {
Thread.sleep(sleepTime);
}
}
} catch (InterruptedException ex) {
Logger.getLogger(ProcessScheduler.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Executes all processes in Process Table on a First Come First Served
* basis (the order in which they were added to the collection).
*/
private void firstComeFirstServed(){
System.out.println("7 " + pt.getClass());
for(int i = 0; i < pt.size(); i++){
CPU.executeInstructions(pt.get(i));
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(ProcessScheduler.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void shortestJobFirst(){
System.out.println("in SJF");
}
private void roundRobin(){
System.out.println("in RR");
}
private void priorityQueue(){
System.out.println("in PQ");
}
}
As others have noted, ProcessTable should extend ArrayList<Process>. However there isn't much reason for the ProcessTable class to exist at all. All is does is provide an incorrectly implemented counter (should not be static) and a display method. I would remove it and just use ArrayList<Process>.
Your ProcessTable definition should be like this:
public static class ProcessTable extends ArrayList<Process>
The problem is your ProcessTable class that extends ArrayList is not generic.
You can start by modifying it with
public class ProcessTable<E> extends ArrayList<E> {
Then when you instantiate it, you can specify the class type ProcessTable will hold inside
ProcessTable<Process> pt;
That way the compiler will know which class will return the pt.get(i) call.
if not, it will treat it as Object.
EDIT:
As #EJP noted, being more specific to your problem you probably want to extend ArrayList with the specific class type it will work with
public class ProcessTable extends ArrayList<Process>
I am starting to develop my skills in JAVA, however I have a doubt.
I'm creating an object in JAVA, created the constructor and so on, then, it asks "Change the AGE_RECENT value from 1 to 3", I initially declared this as final because I never thought it would change, so no SET or GET were created. I am wondering how can I change the value from 1 to 3 in the SET Method.
I have this variable
private static int AGE_RECENT=1;
I did this.
public void setAgeRecent() {
Vehicle.AGE_RECENT = 3;
}
It works if you run the program, it changes the variable's value, however nothing was declared in that method as every SET method.
Just wondering how can I do this. If this is correct, good, if not, thanks for helping!
As someone asked, the code.
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package tp1;
/**
*
* #author Nelson
*/
public class Vehicle {
/** Variáveis da classe, têm como função **/
private String registration;
private int registrationYear;
private double consumption;
private double autonomy;
private int cilinderCapacity;
/**
* Final variables. They are final because they do not suffer any kind of modification during the project.
* YEAR_OMISSION is 2016 because the currect year is 2016.
* ENVIRONMENTAL_CHARGE_OMISSION is 0.10(10 cents), gave this value because there is nothing to mention the
especific value, hence why I gave 0.10.
* RATING_RECENT = Is a string, just has the text "RECENT" inside.
* RATING_COMTEMPORY - Another string, just with the "Comtempory" text inside.
* RATING_CLASSIC - Yet again another string, with the "Classic" text.
* AGE_RECENT - It is to help to compare if a vehicle is recent or not, it has the value 3.
* AGE_CLASSIC - It is to again help to compare, value is 20.
*/
private static final int YEAR_OMISSION = 2016;
private static final double ENVIRONMENTAL_CHARGE_OMISSION=0.10;
private static final String RATING_RECENT="Recent";
private static final String RATING_CONTEMPORY="Contempory";
private static final String RATING_CLASSIC="Classic";
private static int AGE_RECENT=1;
private static final int AGE_CLASSIC=20;
/**
* Constructor of the object, it has the Registration
* #param registration
* #param registrationYear - The year the vehicle was first registered.
* #param consumption - How many liters the vehicle consumes.
* #param autonomy - How many KMs a vehicle can go without refuelling.
* #param cilinderCapacity - How many Cubic Inches the engine has.
*/
public Vehicle(String registration,int registrationYear, double consumption, double autonomy, int cilinderCapacity) {
this.registration = registration;
this.registrationYear = registrationYear;
this.consumption = consumption;
this.autonomy = autonomy;
this.cilinderCapacity = cilinderCapacity;
}
/**
* Null Constructor, it has no values, they will be attributed in the MAIN Class.
*/
public Vehicle() {
this.registration = "";
this.registrationYear = 0;
this.consumption = 0;
this.autonomy = 0;
this.cilinderCapacity =0;
this.registrationYear = YEAR_OMISSION;
}
/**
* Copy Constructor.
*/
public Vehicle(Vehicle vehicle) {
this.registration = vehicle.getRegistration();
this.registrationYear = vehicle.getRegistrationYear();
this.consumption = vehicle.getConsumption();
this.autonomy = vehicle.getAutonomy();
this.cilinderCapacity = vehicle.getCilinderCapacity();
}
public String getRegistration() {
return registration;
}
public int getRegistrationYear() {
return registrationYear;
}
public double getConsumption() {
return consumption;
}
public double getAutonomy() {
return autonomy;
}
public int getCilinderCapacity() {
return cilinderCapacity;
}
public double getYearRecent() {
return AGE_RECENT;
}
public double getAgeRecent(){
return AGE_RECENT;
}
public void setRegistration(String registration) {
this.registration = registration;
}
public void setRegistrationYear(int registrationYear) {
this.registrationYear = registrationYear;
}
public void setConsumption(double consumption) {
this.consumption = consumption;
}
public void setAutonomy(double autonomy) {
this.autonomy = autonomy;
}
public void setCilinderCapacity(int cilinderCapacity) {
this.cilinderCapacity = cilinderCapacity;
}
public void setAgeRecent() {
Vehicle.AGE_RECENT = 3;
}
/**
* Calculate the age of the vehicle to compare in the vehicleRating method
* #return The year, which is 2016 minus the year the vehicle was first registered.
*/
private int calculateAge(){
return YEAR_OMISSION-this.registrationYear;
}
/**
* Calculate the Circulation Tax.
* #return Returns the value of the Environmental Charge multiplied by the Cilinder Capacity of the vehicle.
*/
public double calculateCirculationTax(){
return ENVIRONMENTAL_CHARGE_OMISSION*cilinderCapacity;
}
/**
* Classify the vehicle based on the age.
* If the result given by the calculateAge method is minor than the AGE_RECENT variable(3), then it will
return "Recent"
* If the result is between Age_RECENT and AGE_CLASSIC(20), then it will say "Contemporary"
* If none of the IFs apply, it will return "Classic".
**/
public static String vehicleRating(Vehicle vehicle) {
if(vehicle.calculateAge() < Vehicle.AGE_RECENT) {
return Vehicle.RATING_RECENT; }
else if ((vehicle.calculateAge()>=Vehicle.AGE_RECENT)&&(vehicle.calculateAge()<=Vehicle.AGE_CLASSIC)){
return Vehicle.RATING_CONTEMPORY;}
else
return Vehicle.RATING_CLASSIC;
}
#Override
public String toString() {
return "Vehicle{" + "registration=" + registration + ", registrationYear=" + registrationYear + ", consumption=" + consumption + ", autonomy=" + autonomy + ", cilinderCapacity=" + cilinderCapacity + '}';
}
}
A setter that takes no arguments is simply a method, not a setter. In order to work as a setter a method must take a parameter that matches the type of the value being set - in your case, that would be int:
public static void setAgeRecent(int age) {
AGE_RECENT = age;
}
Note a few things here:
Since AGE_RECENT is static, setAgeRecent should be static
Since AGE_RECENT and setAgeRecent are static members of the same class Vehicle, you do not need to qualify AGE_RECENT with Vehicle
Now users of your class would be able to call your static setter as follows:
Vehicle.setAgeRecent(3);
A static varible, or class variable, may be used without the need to create an instance of that class. But its value may be changed freely at runtime.
A final variable is not a variable in a true sense, because it's value can't be changed at runtime.
Thus, you may have a set method for a static variable, but never to a final variable.
My question is: How do I access values from another thread?
I have two .java files, Main.java and TrackHands.java
Main.java
/**
* This is the main class, it is used to start the program. The only use of this
* is to make everything more organized.
*/
package Kinect;
//import processing.core.PApplet;
/**
* #author Tony Nguyen <Tony.Nguyen#HvA.nl>
*
*/
public class Main
{
public static void main(String _args[])
{
Thread trackHands = new Thread(new TrackHands());
trackHands.start();
}
}
TrackHands.java
/*
* This uses the normal Java layout to track the user and prints out the coordinates of the left and right hand
*/
package Kinect;
import SimpleOpenNI.*;
import processing.core.PApplet;
import processing.core.PVector;
/**
* #author Tony Nguyen <Tony.Nguyen#HvA.nl>
* #version 1.0
*/
public class TrackHands extends PApplet implements Runnable
{
private int handLeftX, handLeftY = 0; // Holds the coordinates of the left hand
SimpleOpenNI kinect = new SimpleOpenNI(this); // kinect object
/**
* Constructor Takes no parameters
*/
public TrackHands()
{
}
/**
* run This will be executed when the thread starts
*/
#Override
public void run()
{
IntVector userList = new IntVector(); // Make a vector of ints to store the list of users
PVector leftHand = new PVector(); // Make a vector to store the left hand
PVector convertedLeftHand = new PVector();
kinect.enableDepth();
kinect.enableUser(SimpleOpenNI.SKEL_PROFILE_ALL);
kinect.setMirror(true);
while (true)
{
kinect.update();
kinect.getUsers(userList); // Write the list of detected users into the vector
if (userList.size() > 0) // Checks if a user is found
{
int userId = userList.get(0); // Get first user
if (kinect.isTrackingSkeleton(userId)) // If successfully calibrated
{
kinect.getJointPositionSkeleton(userId,
SimpleOpenNI.SKEL_LEFT_HAND, leftHand); // Put the position of the left hand into that vector
kinect.convertRealWorldToProjective(leftHand,
convertedLeftHand);
this.handLeftX = round(convertedLeftHand.x);
this.handLeftY = round(convertedLeftHand.y);
}
}
}
}
// User-tracking callbacks!
public void onNewUser(int userId)
{
System.out.println("Start pose detection");
kinect.startPoseDetection("Psi", userId);
}
public void onEndCalibration(int userId, boolean successful)
{
if (successful)
{
System.out.println(" User calibrated !!!");
kinect.startTrackingSkeleton(userId);
} else
{
System.out.println(" Failed to calibrate user !!!");
kinect.startPoseDetection("Psi", userId);
}
}
public void onStartPose(String pose, int userId)
{
System.out.println("Started pose for user");
kinect.stopPoseDetection(userId);
kinect.requestCalibrationSkeleton(userId, true);
}
}
I have tried to use a getter and a setter to get the values from TrackHands.java into another thread.
Tried creating objects and passing the values as parameters, but then my program will not use these new values in the run() method.
To get values from TrackHands, use a get method that accesses an instance variable that is set in run()
class TrackHands {
Object output;
public void run() {
while(true) {
output = new Object();
}
}
public Object getOutput() {
return output;
}
}
Pass TrackHands into your consumer object and use it to call get getOutput() method.
Passing values in is a bit trickier, because you might cause race condition. Try something like this
class TrackHands {
Object input = null;
public boolean setInput(Object input) {
if(this.input == null) {
this.input = input;
return true;
} else {
return false;
}
}
}
When your run() method uses input, set it to null so that another thread can pass in another input. Your producer thread will use this loop to pass in input:
public void sendInput(TrackHands th, Object input) {
boolean done = false;
while(!done) {
done = th.setInput(input);
}
}
This will keep trying to pass in input until it succeeds.
setInput uses the synchronized keyword so that only one thread can call this method at once, otherwise you'll get a race condition.
A friend of mine solved my problem.
I want to thank everyone for helping me!
Main.java
/**
* This is the main class, it is used to start the program. The only use of this
* is to make everything more organized.
*/
package Kinect;
//import processing.core.PApplet;
/**
* #author Tony Nguyen <Tony.Nguyen#HvA.nl>
*
*/
public class Main
{
public static void main(String _args[])
{
// PApplet.main(new String[]
// {
// Sensor.class.getName()
// });
ValueStore valueStore = new ValueStore(); // ADDED THIS LINE
Thread trackHands = new Thread(new TrackHands(valueStore)); // ADDED THIS LINE
trackHands.start();
}
}
TrackHands.java
/*
* This uses the normal Java layout to track the user and prints out the coordinates of the left and right hand
*/
package Kinect;
import SimpleOpenNI.*;
import processing.core.PApplet;
import processing.core.PVector;
/**
* #author Tony Nguyen <Tony.Nguyen#HvA.nl>
* #version 1.0
*/
public class TrackHands extends PApplet implements Runnable
{
private int handLeftX, handLeftY, handRightX, handRightY = 0; // Holds the coordinates of the left hand
SimpleOpenNI kinect = new SimpleOpenNI(this); // kinect object
private ValueStore valuesStore; // ADDED THIS LINE
/**
* Constructor Takes no parameters
*/
public TrackHands()
{
}
public TrackHands(ValueStore valuesStore)
{
this.valuesStore = valuesStore;
}
/**
* run This will be executed when the thread starts
*/
#Override
public void run()
{
IntVector userList = new IntVector(); // Make a vector of ints to store the list of users
PVector leftHand = new PVector(); // Make a vector to store the left hand
PVector rightHand = new PVector(); // Make a vector to store the right hand
PVector convertedLeftHand = new PVector(); // Make a vector to store the actual left hand
PVector convertedRightHand = new PVector(); // Make a vector to store the actual right hand
kinect.enableDepth();
kinect.enableUser(SimpleOpenNI.SKEL_PROFILE_ALL);
kinect.setMirror(true);
while (true)
{
kinect.update();
kinect.getUsers(userList); // Write the list of detected users into the vector
if (userList.size() > 0) // Checks if a user is found
{
int userId = userList.get(0); // Get first user
if (kinect.isTrackingSkeleton(userId)) // If successfully calibrated
{
kinect.getJointPositionSkeleton(userId,
SimpleOpenNI.SKEL_LEFT_HAND, leftHand); // Put the position of the left hand into that vector
kinect.getJointPositionSkeleton(userId,
SimpleOpenNI.SKEL_RIGHT_HAND, rightHand); // Put the position of the left hand into that vector
kinect.convertRealWorldToProjective(leftHand,
convertedLeftHand);
kinect.convertRealWorldToProjective(rightHand,
convertedRightHand);
this.handLeftX = round(convertedLeftHand.x);
this.handLeftY = round(convertedLeftHand.y);
this.handRightX = round(convertedRightHand.x);
this.handRightY = round(convertedRightHand.y);
valuesStore.setHandValues(handLeftX, handLeftY, handRightX, handRightY); // ADDED THIS LINE
}
}
}
}
// User-tracking callbacks!
public void onNewUser(int userId)
{
System.out.println("Start pose detection");
kinect.startPoseDetection("Psi", userId);
}
public void onEndCalibration(int userId, boolean successful)
{
if (successful)
{
System.out.println(" User calibrated !!!");
kinect.startTrackingSkeleton(userId);
} else
{
System.out.println(" Failed to calibrate user !!!");
kinect.startPoseDetection("Psi", userId);
}
}
public void onStartPose(String pose, int userId)
{
System.out.println("Started pose for user");
kinect.stopPoseDetection(userId);
kinect.requestCalibrationSkeleton(userId, true);
}
}
Then added a class to store the values so another class can access it.
ValueStore.java
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package Kinect;
/**
*
* #author Tony Nguyen <Tony.Nguyen#HvA.nl>
*/
public class ValueStore
{
private int leftX, leftY, rightX, rightY = 0;
public void setHandValues(int leftX, int leftY, int rightX, int rightY)
{
this.leftX = leftX;
this.leftY = leftY;
this.rightX = rightX;
this.rightY = rightY;
}
public int getLeftX()
{
return this.leftX;
}
}