How can I change a local variable into a global one? - java

So I'm editing a source code for a game, and I have an event reading the game's chat. I need the game to read the chat, copy some words from the chat, enter a chat message with the first word, wait a bit, enter a chat message with the second word etc.
Right now, the code looks like that:
private final long PERIOD = 4000L; //timer
private long lastTime = System.currentTimeMillis() - PERIOD;
#SubscribeEvent
public void onChat(final ClientChatReceivedEvent e) { //look at the chat
final String chat = e.message.getUnformattedText();
if(chat.startsWith("Something")) { //if the chat message starts with "Something"
//Create the string chatp1 being "Something 123"
String click = chatp1.replace("Something ", ""); //Creates a string "click", which is chatp1 without the "Something ", so it's "123"
//After it basically does the same thing multiple times, but instead of "Something" it's "Something1" and instead of "123" it's "124" etc.
//Then I need to run the commands
MyGame.getMyGame().thePlayer.sendChatMessage("/Command " + click); //runs the command "/Command 123"
long thisTime12 = System.currentTimeMillis();
if ((thisTime12 - lastTime) >= PERIOD) { //waits
lastTime = thisTime12;
MyGame.getMyGame().thePlayer.sendChatMessage("/Command " + click2); //Runs the command "/Command 124"
//etc.
Now there's a problem: "click" and "click2" can not be found, which is obvious: these are local variables, not global ones. My question is: what is the easiest way of changing the code so "click" and "click2" can be found in the code? Should I claim them as global variables at the beginning (if so, how?) or something else?

Here is the Answer:
private final long PERIOD = 4000L; //timer
private long lastTime = System.currentTimeMillis() - PERIOD;
String click = "";
String click2 = "";
#SubscribeEvent
public void onChat(final ClientChatReceivedEvent e) { //look at the chat
final String chat = e.message.getUnformattedText();
if(chat.startsWith("Something")) { //if the chat message starts with "Something"
//Create the string chatp1 being "Something 123"
click = chatp1.replace("Something ", ""); //Creates a string "click", which is chatp1 without the "Something ", so it's "123"
//After it basically does the same thing multiple times, but instead of "Something" it's "Something1" and instead of "123" it's "124" etc.
//Then I need to run the commands
MyGame.getMyGame().thePlayer.sendChatMessage("/Command " + click); //runs the command "/Command 123"
long thisTime12 = System.currentTimeMillis();
if ((thisTime12 - lastTime) >= PERIOD) { //waits
lastTime = thisTime12;
MyGame.getMyGame().thePlayer.sendChatMessage("/Command " + click2); //Runs the command "/Command 124"
//etc.

Move their declaration into the class, so they become fields.

Related

Log events in Java summarily, not per occurence

My Java application does quite a lot of synchronization with databases. Each such single event is logged, e.g.
logger.info("Starting synchronization...");
synchronizeWithDatabase();
logger.info("Synchronization has ended.");
This clutters logs quite a lot. Would it be possible to log a summary every hour (e.g. "there were 60 successful synchronization events from 12:00:00 to 13:00:00") and only log errors per occurrence? I'm using slf4j Logger
The straightforward way is to write code to do what you want. Write a wrapper class that, for each "event", tracks the last time you actually logged the event, and the number of times it has occurred.
Then on a call for which the time-since-logged exceeds an hour, actually write the log message, and reset the counter.
Here's a sketch off the top of my head. Hasn't been near a compiler. Not intended as a fully-baked solution.
class QuenchData {
private static final long delta = 1000 * 60 * 60; // 1 hr
private long lastLogTime;
private int count;
void log(String message, Logger logger) {
long now = System.getTimeInMillis();
if (now < lastLogTime || now-lastLogTime >= delta) {
String andAlso = String.format(" [occurred %d times]", count);
logger.log(message + andAlso);
lastLogTime = now;
count = 0;
} else
count++;
}
}
}
class QuenchedLogger {
private Logger logger = new Logger(...whatever...);
private Map<String, QuenchData> history = new HashMap<>();
:
synchronized void log(String message) {
QuenchData qd = history.get(message);
if (qd == null)
history.put(message, (qd = new QuenchData()));
qd.log(message, logger);
}
}

Include parameters for spring shell before method

I am working on a Spring Shell project. The tool is a command line tool to manipulate data in a database. There are commands like add user (which adds a record to a table in database). In order to execute any commands the user of the tool has to be connected to the database. I would like to be able to run this all in one line. The user of my tool should be able to write a command like the following.
--database connection string xyz --username abc --password mno add user --username bob --role AA_ADMIN --company Microsoft
Here the three parameters database connection string, username and password are required to run the add user command.
Below I have included some sample code it is from the spring shell reference docs
package commands;
import org.springframework.shell.core.CommandMarker;
import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
import org.springframework.stereotype.Component;
#Component
public class UserManipulation implements CommandMarker {
private boolean simpleCommandExecuted = false;
#CliAvailabilityIndicator({"hw simple"})
public boolean isSimpleAvailable() {
//always available
return true;
}
#CliAvailabilityIndicator({"hw complex", "hw enum"})
public boolean isComplexAvailable() {
if (simpleCommandExecuted) {
return true;
} else {
return false;
}
}
#CliCommand(value = "hw simple", help = "Print a simple hello world message")
public String simple(
#CliOption(key = { "message" }, mandatory = true, help = "The hello world message") final String message,
#CliOption(key = { "location" }, mandatory = false, help = "Where you are saying hello", specifiedDefaultValue="At work") final String location) {
simpleCommandExecuted = true;
return "Message = [" + message + "] Location = [" + location + "]";
}
#CliCommand(value = "hw complex", help = "Print a complex hello world message")
public String hello(
#CliOption(key = { "message" }, mandatory = true, help = "The hello world message") final String message,
#CliOption(key = { "name1"}, mandatory = true, help = "Say hello to the first name") final String name1,
#CliOption(key = { "name2" }, mandatory = true, help = "Say hello to a second name") final String name2,
#CliOption(key = { "time" }, mandatory = false, specifiedDefaultValue="now", help = "When you are saying hello") final String time,
#CliOption(key = { "location" }, mandatory = false, help = "Where you are saying hello") final String location) {
return "Hello " + name1 + " and " + name2 + ". Your special message is " + message + ". time=[" + time + "] location=[" + location + "]";
}
#CliCommand(value = "hw enum", help = "Print a simple hello world message from an enumerated value")
public String eenum(
#CliOption(key = { "message" }, mandatory = true, help = "The hello world message") final MessageType message){
return "Hello. Your special enumerated message is " + message;
}
enum MessageType {
Type1("type1"),
Type2("type2"),
Type3("type3");
private String type;
private MessageType(String type){
this.type = type;
}
public String getType(){
return type;
}
}
}
So currently, hw simple is a command that is required to be executed before running hw complex or hw enum command. I do not want hw simple to be a command instead it the message parameter within the hw simple command should be a parameter that is required as a prerequisite to run hw complex or hw enum. So for example the command that I would like to run is.
--message hw complex --message abc --name1 def --name2 ghi --time 7:98 --location: Seattle
Does anyone know how to do this? If it is not possible to do this I would like to hear that or any alternative ideas if possible.
You have 2 options here:
either make those 3 additional parameters (database, username, password) parameters of each and every command that require them (note that in your particular example, you would need to rename one of those username parameters [the one to connect to the DB, or the one that represents the user to add] as you can't have 2 parameters with the same name obviously).
Use the #CliAvailabilityIndicator approach, similar to what is described in the example, where a first command (maybe named use or connect) first tests the connection with the 3 given parameters and stores them somewhere, so that any further "real" command (such as add user) can use those values.
Also note that you can actually use a combination of the two (i.e. use solution 2 to provide defaults, that may be overridden on a case by case basis by solution 1).
Lastly, please note that you'll never be able to have something like what you describe at the beginning of your question, as command names must be at the beginning and they can't contain -- (options do)

Java - How to measure a time out

I am making a ping program using Java sockets. One bug in my program is that sometimes it will not connect and will just sit there for ever. So I am trying to add a timeout (after twenty seconds) and the ping will fail. But I have no idea how to.
Here is part of my ping program:
boolean result = false;
long before1 = System.nanoTime();
out.println(new byte[64]);
System.out.println("(1) Sent 64 bytes of data to " + address
+ "...");
try {
if ((in.readLine()) != null) {
int size = in.readLine().toString().getBytes().length;
long after = System.nanoTime();
long s = ((after - before1) / 1000000L) / 1000;
System.out.println("(1) Recieved reply from " + address
+ " (" + size + " bytes), time = " + s
+ " seconds...");
result = true;
} else if ((in.readLine()) == null) {
long after = System.nanoTime();
long s = ((after - before1) / 1000000L) / 1000;
System.out.println("(1) Failed to recieve reply from "
+ address + ", time = " + s + " seconds...");
result = false;
}
} catch (IOException exc) {
long after = System.nanoTime();
long s = ((after - before1) / 1000000L) / 1000;
System.err.println("(1) Failed to recieve reply from "
+ address + ", time = " + s + " seconds...\nReason: "
+ exc);
result = false;
}
But I would like to measure time elapsed any where in my code, instead of:
long time = System.nanoTime();
If one part of my code is stuck doing something it will time out after 20 seconds.
Any suggestions on how to measure if twenty seconds has passed at the start of a try/catch block or anywhere else in my code so it doesn't get stuck during the ping?
As "jsn" and "jahory" said you need to do this with threads. Here's 2 useful links, you can check them ;)
How to implement timeout using threads
Adding a thread timeout to methods in Java
You can use Future and FutureTask:
ExecutorService pingExecutor = ... // executor service to run the ping in other thread
void showPing(final String target) throws InterruptedException {
Future<String> ping = executor.submit(new Callable<String>() {
public String call() {
String pingResult = ... // do your Ping stuff
return pingResult;
}});
System.out.println("Pinging..."); // do other things while searching
try {
System.out.println(future.get(20, TimeUnit.SECONDS)); // use future, waits 20 seconds for the task to complete
} catch (ExecutionException ex) {
} catch (TimeoutException tex) {
// Ping timed out
}
}
You can find some hints here: How do I call some blocking method with a timeout in Java?
Future interface looks like a good solution to your problem. Remember, however, that depending on what your task is doing, you probably would be not able to really cancel it. Additional info:
tutorial (see, in particular, Non-blocking algorithms section)

Need to fix my Java Timer code

Task - Turn a bulb on and off at a specified time during a day. I need to know how to fix my code as per the information given below. I also need to know if I am using the timer class correctly, that is, is my code design correct ? The code may work but it could be bad design which will cause problems later. I don't want that to happen.
Output is (This is not the output i really wanted :( ) -
This is the main program
Current time is - xxx
Future time is - xxx+5sec
Future time is - xxx+10sec
Main program ends
Bulb B1 is OFF
Desired output -
This is the main program
Current time is - xxx
Future time is - xxx+5sec
Future time is - xxx+10sec
Bulb B1 is ON //first on
Bulb B1 is OFF //then off
Main program ends//This should always be in the end.
How do I fix the code below to get what I want ?
Bulb Class
class Bulb {
private boolean state = false;//On or off
private String name;
Bulb(String name){
this.name = name;
}
public void setState(boolean state){
this.state = state;
if(this.state == true){
System.out.println("Bulb " + name + " is ON");
}else{
System.out.println("Bulb " + name + " is OFF");
}
}
public boolean getState(){
return this.state;
}
}
BulbJob class which is a TimerTask
import java.util.*;
class BulbJob extends TimerTask{
private Bulb bulbToHandle;
private boolean setBulbStateEqualTo;
BulbJob(Bulb toHandle){
this.bulbToHandle = toHandle;
}
//NOTE: Must be called before run(), otherwise default value is used
public void setBulbStateEqualTo(boolean setBulbStateEqualTo){
this.setBulbStateEqualTo = setBulbStateEqualTo;
}
//NOTE: call run() only before calling above method
public void run(){
this.bulbToHandle.setState(setBulbStateEqualTo);//Set on or off
}
}
BulbScheduler class - this schedules when the bulb is turned on or off.
import java.util.*;
#SuppressWarnings( "deprecation" )
class BulbScheduler {
public static void main(String args[]) throws InterruptedException{
System.out.println("This is the main program");
Timer time = new Timer();
Bulb b1 = new Bulb("B1");
BulbJob bj = new BulbJob(b1);
bj.setBulbStateEqualTo(true);//Task - Turn bulb on at time = afterCurrent
Date current = new Date();//Get current time and execute job ten seconds after this time
Date afterCurrent = (Date) current.clone();
System.out.println("Current time is - " + current);
int currentSecs = current.getSeconds();
int offset = 5;//number of seconds
afterCurrent.setSeconds(currentSecs + offset);
System.out.println("Future time is - " + afterCurrent);
time.schedule(bj, afterCurrent);//Schedule job "bj" at time = afterCurrent
//Now turn the bulb off at new time = newest afterTime
afterCurrent.setSeconds(currentSecs + 2 * offset);
System.out.println("Future time is - " + afterCurrent);
bj.setBulbStateEqualTo(false);//Task - Now turn the bulb off at time = afterCurrent
System.out.println("Main program ends");
}
}
This section:
time.schedule(bj, afterCurrent);//Schedule job "bj" at time = afterCurrent
//Now turn the bulb off at new time = newest afterTime
afterCurrent.setSeconds(currentSecs + 2 * offset);
only schedules one task. If you need to schedule it twice, do so explicitly:
time.schedule(bj, afterCurrent);//Schedule job "bj" at time = afterCurrent
//Now turn the bulb off at new time = newest afterTime
afterCurrent.setSeconds(currentSecs + 2 * offset);
time.schedule(bj, afterCurrent);//Schedule job "bj" at time = afterCurrent
Also. this line:
bj.setBulbStateEqualTo(false);
is executed in the main thread, so it will before both tasks. You should schedule that statement to run between the two tasks.
Code is fixed, but this version cannot exit main in the end -
import java.util.*;
#SuppressWarnings( "deprecation" )
class BulbScheduler {
public static void main(String args[]) throws InterruptedException{
System.out.println("This is the main program");
Timer timeOn = new Timer();
Timer timeOff = new Timer();
Bulb b1 = new Bulb("B1");
BulbJob bjOn = new BulbJob(b1);
BulbJob bjOff = new BulbJob(b1);
bjOn.setBulbStateEqualTo(true);//Task - Turn bulb on
bjOff.setBulbStateEqualTo(false);//Task - Then turn the bulb off later
Date current = new Date();//Get current time and execute job ten seconds after this time
Date afterCurrent = (Date) current.clone();
System.out.println("Current time is - " + current);
int currentSecs = current.getSeconds();
int offset = 3;//number of seconds
afterCurrent.setSeconds(currentSecs + offset);
System.out.println("Future time is - " + afterCurrent);
timeOn.schedule(bjOn, afterCurrent);//Schedule job "bj" at time = afterCurrent
//Now turn the bulb off at new time = latest afterCurrent
afterCurrent.setSeconds(currentSecs + 2 * offset);
System.out.println("Future time is - " + afterCurrent);
timeOff.schedule(bjOff, afterCurrent);
System.out.println("Main program ends");
}
}
you are not setting the time correctly. Need to use GreogarianCalendar.
java.util.Date is used but cannot use its setSeconds Read the Javadoc its pretty good and will help a lot. public void setSeconds(int seconds)
Deprecated. As of JDK version 1.1, replaced by Calendar.set(Calendar.SECOND, int seconds).
Sets the seconds of this Date to the specified value. This Date object is modified so that it represents a point in time within the specified second of the minute, with the year, month, date, hour, and minute the same as before, as interpreted in the local time zone.
You need to use java.util.GregorianCalendar # add(Calendar.SECOND, howManySeconds)
then use getDate() to get the Date object and send it to the Timer.
calling setSecond on a date wont change the other fields. see the java doc of Calendar.add and roll. http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Calendar.html and see the rules in the class inro.
Can also use the timer object's schedule(TimerTask task, long delay)
Schedules the specified task for execution after the specified delay (milliseconds).
Modified code -
import java.util.*;
class BulbScheduler {
private static java.text.SimpleDateFormat sdf1 = new java.text.SimpleDateFormat ("yy MM dd HH mm ss");
//helper
static String formatDate(Date d){
return sdf1.format(d);
}
public static void main(String args[]) throws InterruptedException{
System.out.println("This is the main method");
java.util.GregorianCalendar cal = new java.util.GregorianCalendar();
Bulb b1 = new Bulb("bulb 1", false);
Bulb b2 = new Bulb("bulb 2", false);
System.out.println("Time now " + formatDate(cal.getTime()));
Timer timer = new Timer("bulbs");
BulbJob b1On = new BulbJob(b1, true);
BulbJob b1Off = new BulbJob(b1, false);
BulbJob b2On = new BulbJob(b2, true);
BulbJob b2Off = new BulbJob(b2, false);
timer.schedule(b1On, 3 * 1000);//after 3 seconds
timer.schedule(b2On, 7 * 1000);//after 4 seconds
timer.schedule(b1Off, 6 * 1000);//after 6 seconds; before b2 on
b1On = new BulbJob(b1, true);
timer.schedule(b1On, 9 * 1000);
//if you want main to wait need to add code here to make it wait,
// but even if does the JVM wont exit. Its just a method. The JVM exits when all non daemon threads are done
// or System.exit is called
System.out.println("This is the main method ending; but other threads might be running ...");
//main thread JVM waits for all other non dameons to end
}
}
Changed BulbJob
import java.util.*;
class BulbJob extends TimerTask{
private Bulb bulbToHandle;
private boolean bulbNewState;//dont start propert names with set
//why a seperate property when we need to set the new state everytime and cannot reuse jobs?
BulbJob(Bulb toHandle, boolean newState){
this.bulbToHandle = toHandle;
bulbNewState= newState;
}
public void run(){
this.bulbToHandle.setState(bulbNewState);//Set on or off
}
}
class Bulb ...
public void setState(boolean state){
this.state = state;
System.out.println("Bulb " + name + " is " + (state ? "on" : "off") + " at " + BulbScheduler.formatDate(new java.util.Date()));//if okay too
}

How to Convert TimeStamps to Ticks (PPQ) - Real Time Midi

I'm currently reading in MIDI messages in real-time from my midi keyboard using a class that implements Receiver, and outputting the notes played.
The only information i receive when I press a note is the MidiMessage and a timeStamp.
I am trying to paint the notes as actual piano sheet music and currently the user has to set the bpm beforehand.
Therefore if I know the tempo is 120bpm (for example), how can I use the timeStamps to determine the length of the note pressed?
I'm assuming if I can convert the timeStamps into ticks (ppq), then I can use that to work out the timings.
Any help is greatly appreciated. Below is my "send" method in my Receiver class.
The 'firstStamp' and 'secondStamp' variables are just to output the length of a note. I took the timeStamp when a note was released and subtracted the timeStamp when it was pressed.
#Override
public void send(MidiMessage message, long timeStamp) {
String strMessage = null;
if (firstStamp == 0) {
firstStamp = timeStamp;
secondStamp = timeStamp;
}
firstStamp = secondStamp;
secondStamp = timeStamp;
stampDif = (secondStamp - firstStamp);
if (message instanceof ShortMessage) {
strMessage = decodeMessage((ShortMessage) message, timeStamp);
} else if (message instanceof MetaMessage) {
strMessage = decodeMessage((MetaMessage) message);
} else if (message instanceof SysexMessage) {
strMessage = decodeMessage((SysexMessage) message);
} else {
strMessage = "other message" + message.getStatus();
}
r_out.println("Timestamp: " + timeStamp + " " + strMessage);
r_printStream.println("Timestamp: " + timeStamp + " " + strMessage);
}
If the timestamp is in milliseconds then you can convert it to ticks like this:
long ticks = timestamp * bpm / (1000 * 60);
Bit you will get a high start tick since the timestamp is probably since Jan 1 1970. So if you want to have your first "tick" as 0 you need to keep track of if this is your first seen event.
if (tickOffset == -1) { // Using -1 as not initialized
tickOffset = ticks;
}
ticks = ticks - tickOffset;

Categories

Resources