I am reusing ObjectOutputStream to send updates between the two clients, this is the server code,
public void run() {
try {
toPlayer1.writeBoolean(true);
toPlayer1.flush();
while (true) {
try {
found = (boolean[][]) fromPlayer1.readObject();
player1Int = fromPlayer1.readInt();
} catch (Exception ex) {
// Handle exception here...
}
if (isWon(player1Int)) {
toPlayer1.writeInt(P1_WON);
toPlayer1.flush();
toPlayer2.writeInt(P1_WON);
toPlayer2.flush();
sendMove(toPlayer2, found, player1Int);
break;
} else {
toPlayer2.writeInt(CONTINUE);
toPlayer2.flush();
sendMove(toPlayer2, found, player1Int);
}
try {
found = (boolean[][]) fromPlayer2.readObject();
player2Int = fromPlayer2.readInt();
} catch (Exception ex) {
// Handle exception here...
}
if (isWon(player2Int)) {
toPlayer1.writeInt(P2_WIN);
toPlayer1.flush();
toPlayer2.writeInt(P2_WIN);
toPlayer2.flush();
sendMove(toPlayer1, found, player2Int);
break;
} else {
toPlayer1.writeInt(CONTINUE);
toPlayer1.flush();
sendMove(toPlayer1, found, player2Int);
}
}
} catch (IOException ex) {
System.err.println(ex);
}
}
private void sendMove(ObjectOutputStream out, boolean[][] found, int score) throws IOException {
try {
out.reset();
out.writeObject(found);
out.writeInt(score);
out.flush();
} catch (Exception ex) {
// Handle exception here...
}
out.writeInt(score);
}
the problem seems to be that some messages are not being delivered correctly, any suggestions? Am I using the flush() correctly? I have added reset(); it is still not working
update, these are the streams:
public void run() {
try {
toPlayer1 = new ObjectOutputStream(player1.getOutputStream());
fromPlayer1 = new ObjectInputStream(player1.getInputStream());
toPlayer2 = new ObjectOutputStream(player2.getOutputStream());
fromPlayer2 = new ObjectInputStream(player2.getInputStream());
regards, c
If you want an object or objects to be sent again, you need to call reset() on the ObjectOutputStream object.
The problem that reset() solves is that when you send an object in a object stream, the protocol attempts to preserve object identity. The first time you send it, the stream sends the object state. Subsequent times, it just sends a marker that says (in effect) "use this object that I sent you previously".
The reset() method says (in effect) to the ObjectOutputStream ... "forget about all objects that I sent previously".
So if you want to send the same object twice, you need to do something like this:
out.writeObject(found);
// change the state of 'found'
out.reset();
out.writeObject(found);
Note that this doesn't affect primitive values sent using their corresponding write methods. Primitive values don't have "identity" and are sent literally each time.
I should also point out that the following is very bad practice.
} catch (Exception ex) {
}
You are silently ignoring all exceptions. This is lazy and dangerous, and you are likely to come to regret it. (Don't do it even in sample code in SO Questions ... 'cos someone might copy your bad code or some Java beginner might emulate your bad habits.)
Related
I've got a very strange question in RuntimeServiceImpl::startProcessInstanceByKey.
The code is like this:
#Override
public String startProcessInstanceByKey(String processDefinitionKey, String businessKey,
String authenticatedUserId, Map < String, Object > variables) throws RiskManageException {
log.info("startProcessInstanceByKey,收到开启工作流 processDefinitionKey:{} ,businessKey:{},authenticatedUserId:{},variables:{}", //This can be printed normally
processDefinitionKey, businessKey, authenticatedUserId, JSON.toJSON(variables));
try {
Assert.notNull(authenticatedUserId, "userCode 不能为空");
Assert.notNull(processDefinitionKey, "流程定义key 不能为空");
processCoreService.getIdentityService().setAuthenticatedUserId(authenticatedUserId);
return processCoreService.getRuntimeService()
.startProcessInstanceByKey(processDefinitionKey, businessKey, variables).getProcessInstanceId(); //This statement didn`t execute
} catch (Exception e) {
throw new RiskManageException(ExceptionCodeEnum.START_PROCESS_ERROR, e); //Here throws an exception but the caller didn`t catch any
}
}
The process instance couldn't be created sometimes in a concurrent environment without any exception. It often happens when JDBC connections are about to use up. I want to know more detailed information, what should I do?
Here is my code:
whatever exception it throws I don't want to catch it outside, I want to continue my loop again by handling it separately. I don't want to use another try catch inside this try catch. Can someone guide me on this?
I don't want to use another try catch inside this try catch.
Yes you do.
MarketplaceBO marketplaceBOObject = new MarketplaceBO(entity.getMarketplaceID());
try {
marketplaceBOObject.loadFromSable();
} catch (WhateverException e) {
// Do something here, or, if you prefer, add the exception to a list and process later
doSomething() ;
// Continue your loop above
continue ;
}
if (marketplaceBOObject.isActive()) {
If you REALLY don't want to do this, your loadFromSable() method could return some object that provides information about success/failure of the call. But I wouldn't recommend that.
do this way -- this way your rest of the code will run no matter there is an exception or not
for (MerchantMarketplaceBO entity : merchantMarketplaceBOList) {
MarketplaceBO marketplaceBOObject = new MarketplaceBO(entity.getMarketplaceID());
try{
marketplaceBOObject.loadFromSable();
if (marketplaceBOObject.isActive()) {
resultVector.add(marketplaceBOObject.getCodigoMarketplace());
}
}
catch{
if (marketplaceBOObject.isActive()) {
resultVector.add(marketplaceBOObject.getCodigoMarketplace());
}
}
}
Another "trick" to deal with that is to move the body to the loop into a separate method having the "additional" try/catch block:
private MarketplaceBO loadFromSable(MerchantMarketplaceBO entity){
MarketplaceBO marketplaceBOObject = new MarketplaceBO(entity.getMarketplaceID());
try {
marketplaceBOObject.loadFromSable();
} catch (WhateverException e) {
// do something to make marketplaceBOObject a valid object
// or at least log the exception
}
return marketplaceBOObject;
}
But since we want to stick to the Same Layer of Abstraction principle we also need to move other part of that method to new smaller methods:
public void serveFromSableV2() {
String merchantCustomerID = ObfuscatedId.construct(request.getMerchantCustomerID()).getPublicEntityId();
try {
List<MerchantMarketplaceBO> merchantMarketplaceBOList =
getAllMerchantMarketplacesBOsByMerchant();
Vector<Marketplace> resultVector = new Vector<>();
for (MerchantMarketplaceBO entity : merchantMarketplaceBOList) {
MarketplaceBO marketplaceBOObject = loadFromSable(entity);
addToActiveMarketplacesList(marketplaceBOObject,resultVector);
}
verifyHavingActiveMarketPlaces(resultVector);
setResponseWithWrapped(resultVector);
} catch (EntityNotFoundException | SignatureMismatchException | InvalidIDException e) {
throw new InvalidIDException("merch=" + merchantCustomerID + "[" + request.getMerchantCustomerID() + "]"); //C++ stack throws InvalidIDException if marketplace is not found in datastore
}
}
You could refactor the load into a separate method that catches and returns the exception instead of throwing it:
private Optional<Exception> tryLoadFromSable(MarketplaceBO marketplaceBOObject) {
try {
marketplaceBOObject.loadFromSable();
return Optional.empty();
}
catch(Exception e) {
return Optional.of(e);
}
}
Then inside your loop:
//inside for loop...
MarketplaceBO marketplaceBOObject = new MarketplaceBO(entity.getMarketplaceID());
Optional<Exception> loadException = tryLoadFromSable(marketplaceBOObject);
if(loadException.isPresent()) {
//Do something here, log it, save it in a list for later processing, etc.
}
This example is based on an example from the book Restlet in Action.
If I try
public class StreamResource extends ServerResource
{
#Get
public Representation getStream() throws ResourceException, IOException
{
Representation representation = new WriterRepresentation(MediaType.TEXT_PLAIN)
{
#Override
public void write(Writer writer) throws IOException
{
String json = "{\"foo\" : \"bar\"}";
while (true)
{
writer.write(json);
}
}
};
return representation;
}
}
it works and it continuously sends the json string to the client.
If I introduce a delay in the while loop like this
String json = "{\"foo\" : \"bar\"}\r\n";
while (true)
{
writer.write(json);
try
{
Thread.sleep(250);
}
catch (InterruptedException e)
{}
}
I was hoping that the client would get data 4 times in a second BUT nothing seems to get to the client.
Can anyone explain why the introduction of Thread.sleep() does that? What is a good way to introduce delay in streaming data to the client?
You should try with the Jetty connector instead of the internal Restlet connector. This connector isn't ready for production even though we are working on fixing it.
You can also try the Simple extension which has less dependent JARs than the Jetty extension.
You can try to flush the buffer, like this:
String json = "{\"foo\" : \"bar\"}\r\n";
while (true)
{
writer.write(json);
writer.flush(); // flush the buffer.
try
{
Thread.sleep(250);
}
catch (InterruptedException e)
{}
}
Without writer.flush(), the writer waits to fill the internal buffer before writing the socket. Thread.sleep(250) reduces the output produced at each second, so that far more time is required to fill the buffer.
Ok, so I am making a game and the music changes when you are in different regions or if there is an interruption, like with an AI.
So I have JUST learned how to make music showup in my program, and now I am trying to make it stop, but I am unsure how to, below is a snippet of code where the music plays and then I try to overwite it with new music when an action occurs.
public static void songs(String word) {
String temp = word;
if (temp.equals("start")) {
try {
try {
blah = new FileInputStream("C:/Users/Austin/Desktop/Storage/programimages/game/battle.wav");
} catch (Throwable e) {
e.printStackTrace();
}
AudioStream as = new AudioStream(blah);
AudioPlayer.player.start(as);
System.out.println("going");
} catch (IOException e) {
System.err.println(e);
}
}
if (temp.equals("stop")) {
try {
try {
blah = new FileInputStream("C:/Users/Austin/Desktop/Storage/programimages/game/silence.wav");
} catch (Throwable e) {
e.printStackTrace();
}
AudioStream as = new AudioStream(blah);
AudioPlayer.player.stop(as);
System.out.println("stopping");
} catch (IOException e) {
System.err.println(e);
}
}
}
This is the only method I have been able to find that has the music play, but if you guys have any other suggestions please let me know.
Again, I want to have sound affects and music going, and right now all that happens is one song will play, and it will not stop under any circumstance until it hits the very end of its length. I want to be able to stop songs whenever a new one should come on, and also allow sound affects to pop up.
Thanks!
(since I am stuck on this and need an answer now I will probably repost on one or two more java sites so I can get a response ASAP, thank you though!!!!)
EDITED CODE: (still does not stop the current stream, any more suggestions appreciated)
public static void songs(String word) throws IOException {
String temp = word;
if (temp.equals("go")) {
try {
blah = new FileInputStream("C:/Users/Austin/Desktop/Storage/programimages/game/battle.wav");
} catch (Throwable e) {
e.printStackTrace();
}
AudioStream as = new AudioStream(blah);
AudioPlayer.player.start(as);
System.out.println("going");
}
if (temp.equals("stop")) {
//don't try and do things with a null object!
if (as != null) {
AudioPlayer.player.stop(as);
System.out.println("stopping1");
}
System.out.println("stopping2");
AudioPlayer.player.stop(as);
}
}
Currently you're creating a new AudioStream in your stop branch and calling the stop method using this. This is a different object to the one that is currently playing. Try making the AudioStream a class variable, and calling stop on that instead.
EDIT: at the top of the class containing your code...
class YourClass {
//the class member variable
private AudioStream as;
//[etc...]
In your start branch:
// 'as' has already been defined above
as = new AudioStream(blah);
AudioPlayer.player.start(as);
System.out.println("going");
In your stop branch:
try
{
//don't try and do things with a null object!
if (as != null)
{
AudioPlayer.player.stop(as);
}
System.out.println("stopping");
}
catch (IOException e)
{
System.err.println(e);
}
You may have trouble with the static identifier on your method - if you're calling this from within an instantiated class you don't need this.
I can't even access these sun.audio Objects on my Eclipse IDE--I know they are in rt.jar, but there is header info about them being proprietary and such.
Can the Java Sound library (javax.sound.sampled) handle what you want to do? Both Clip and SourceDataLine allow one to stop playback. That is a more usual way of playing sound, if you want to use native Java.
Playback into is here:
http://docs.oracle.com/javase/tutorial/sound/playing.html
But the documentation, overall, is not exactly rich with examples. There's example code at this site
http://www.jsresources.org/
and plenty of people here who could help if you run into problems with the native Java approach.
This is a very simple example of hibernate usage in java: a function that when it's called, it creates a new object in the database. If everything goes fine, the changes are stored and visible immediately (no cache issues). If something fails, the database should be restored as if this function was never called.
public String createObject() {
PersistentTransaction t = null;
try {
t = PersistentManager.instance().getSession().beginTransaction();
Foods f = new Foods(); //Foods is an Hibernate object
//set some values on f
f.save();
t.commit();
PersistentManager.instance().getSession().clear();
return "everything allright";
} catch (Exception e) {
System.out.println("Error while creating object");
e.printStackTrace();
try {
t.rollback();
System.out.println("Database restored after the error.");
} catch (Exception e1) {
System.out.println("Error restoring database!");
e1.printStackTrace();
}
}
return "there was an error";
}
Is there any error? Would you change / improve anything?
I don't see anything wrong with your code here. As #Vinod has mentioned, we rely on frameworks like Spring to handle the tedious boiler plate code. After all, you don't want code like this to exist in every possible DAO method you have. They makes things difficult to read and debug.
One option is to use AOP where you apply AspectJ's "around" advice on your DAO method to handle the transaction. If you don't feel comfortable with AOP, then you can write your own boiler plate wrapper if you are not using frameworks like Spring.
Here's an example that I crafted up that might give you an idea:-
// think of this as an anonymous block of code you want to wrap with transaction
public abstract class CodeBlock {
public abstract void execute();
}
// wraps transaction around the CodeBlock
public class TransactionWrapper {
public boolean run(CodeBlock codeBlock) {
PersistentTransaction t = null;
boolean status = false;
try {
t = PersistentManager.instance().getSession().beginTransaction();
codeBlock.execute();
t.commit();
status = true;
}
catch (Exception e) {
e.printStackTrace();
try {
t.rollback();
}
catch (Exception ignored) {
}
}
finally {
// close session
}
return status;
}
}
Then, your actual DAO method will look like this:-
TransactionWrapper transactionWrapper = new TransactionWrapper();
public String createObject() {
boolean status = transactionWrapper.run(new CodeBlock() {
#Override
public void execute() {
Foods f = new Foods();
f.save();
}
});
return status ? "everything allright" : "there was an error";
}
The save will be through a session rather than on the object unless you have injected the session into persistent object.
Have a finally and do a session close also
finally {
//session.close()
}
Suggestion: If this code posted was for learning purpose then it is fine, otherwise I would suggest using Spring to manage this boiler plate stuff and worry only about save.