package greenfoot.platforms.standalone;
import greenfoot.GreenfootImage;
import greenfoot.UserInfoVisitor;
import greenfoot.UserInfo;
import greenfoot.platforms.GreenfootUtilDelegate;
import greenfoot.util.GreenfootStorageException;
import threadchecker.OnThread;
import threadchecker.Tag;
import java.awt.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.URL;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.List;
| Implementation of GreenfootUtilDelegate for standalone applications.
|
@OnThread(Tag.Simulation)
public class GreenfootUtilDelegateStandAlone
implements GreenfootUtilDelegate{
private SocketChannel socket;
private boolean failedLastConnection;
private boolean firstStorageException = true;
private boolean storageStandalone;
private String storageHost;
private String storagePort;
private String storagePasscode;
private String storageScenarioId;
private String storageUserId;
private String storageUserName;
@OnThread(Tag.Any)
public GreenfootUtilDelegateStandAlone(boolean storageStandalone,
String storageHost, String storagePort, String storagePasscode,
String storageScenarioId, String storageUserId,
String storageUserName)
{
this.storageStandalone = storageStandalone;
this.storageHost = storageHost;
this.storagePort = storagePort;
this.storagePasscode = storagePasscode;
this.storageScenarioId = storageScenarioId;
this.storageUserId = storageUserId;
this.storageUserName = storageUserName;
}
| Create stand-alone delegate with no support for storage.
|
@OnThread(Tag.Any)
public GreenfootUtilDelegateStandAlone()
{
this(false, "", "", "", "", "", "");
}
@Override
@OnThread(Tag.Any)
public URL getResource(String path)
{
URL res = this.getClass().getClassLoader().getResource(path);
if (res != null && (res.toString().contains("!") || res.getProtocol().equals("file"))) {
return res;
}
else {
if (path.indexOf('\\') != -1) {
path = path.replace('\\', '/');
res = this.getClass().getClassLoader().getResource(path);
if (res != null && res.toString().contains("!")) {
return res;
}
}
return null;
}
}
@Override
@OnThread(Tag.Any)
public Iterable getSoundFiles()
{
InputStream is = this.getClass().getClassLoader().getResourceAsStream("soundindex.list");
ArrayList<String> r = new ArrayList<String>();
if (is != null)
{
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
try
{
while ((line = reader.readLine()) != null)
{
r.add(line);
}
}
catch (IOException e)
{
}
}
return r;
}
| Returns the path to a small version of the greenfoot logo.
|
@Override
@OnThread(Tag.Any)
public String getGreenfootLogoPath()
{
return this.getClass().getClassLoader().getResource("greenfoot.png").toString();
}
| Closes the connection (well, silently drops it), but allows
| a subsequent connection attempt
|
private void closeConnection(Exception e)
{
e.printStackTrace();
socket = null;
failedLastConnection = false;
}
@Override
public boolean isStorageSupported()
{
try
{
ensureStorageConnected();
return getCurrentUserInfo() != null;
}
catch (GreenfootStorageException e)
{
if (firstStorageException)
{
e.printStackTrace();
}
firstStorageException = false;
return false;
}
}
| Tries to connect to the server, if not already connected.
|
| If it returns without throwing an exception, you can assume you are connected.
|
| @throws GreenfootStorageException if there is a problem
|
private void ensureStorageConnected() throws GreenfootStorageException
{
if (socket != null && socket.isConnected())
return;
if ((socket == null || !socket.isConnected()) && failedLastConnection)
throw new GreenfootStorageException("Already failed to connect to storage server on last attempt");
if (!storageStandalone)
throw new GreenfootStorageException("Standalone storage not supported");
System.err.println("Attempting to reconnect to storage server");
int userId;
try
{
userId = Integer.parseInt(storageUserId);
if (userId < 0)
throw new GreenfootStorageException("User not logged in");
}
catch (NumberFormatException e)
{
throw new GreenfootStorageException("Invalid user ID");
}
short port;
try
{
port = Short.parseShort(storagePort);
}
catch (NumberFormatException e)
{
throw new GreenfootStorageException("Error connecting to storage server -- invalid port: " + e.getMessage());
}
try
{
if (storagePasscode == null)
throw new GreenfootStorageException("Could not find passcode to send back to server");
failedLastConnection = true;
socket = SocketChannel.open();
if (!socket.connect(new InetSocketAddress(storageHost, port)))
{
socket = null;
throw new GreenfootStorageException("Could not connect to storage server");
}
ByteBuffer buffer = makeRequest((storagePasscode.length() / 2) + 4 + 4);
for (int i = 0; i < storagePasscode.length() / 2; i++)
{
byte b = (byte)(0xFF & Short.parseShort(storagePasscode.substring(i * 2, i * 2 + 2), 16));
buffer.put(b);
}
try
{
buffer.putInt(Integer.parseInt(storageScenarioId));
buffer.putInt(userId);
}
catch (NumberFormatException e)
{
socket = null;
throw new GreenfootStorageException("Invalid scenario ID: " + e.getMessage());
}
buffer.flip();
socket.write(buffer);
failedLastConnection = false;
}
catch (IOException e)
{
socket = null;
throw new GreenfootStorageException("Error connecting to storage server: " + e.getMessage());
}
catch (AccessControlException ace) {
if (socket != null) {
try {
socket.close();
}
catch (IOException ioe) {
}
socket = null;
}
}
}
private ByteBuffer makeRequest(int plusBytes)
{
ByteBuffer buf = ByteBuffer.allocate(4 + plusBytes);
buf.putInt(plusBytes);
return buf;
}
private void readFullBuffer(ByteBuffer buf, int amount) throws IOException
{
int totalBytes = 0;
while (totalBytes < amount)
{
int bytesRead = socket.read(buf);
if (bytesRead > 0)
totalBytes += bytesRead;
else{ throw new IOException("Connection unexpectedly closed by remote end");
}
}
buf.flip();
}
private ByteBuffer readResponse() throws IOException
{
ByteBuffer buf = ByteBuffer.allocate(4);
readFullBuffer(buf, 4);
int size = buf.getInt();
buf = ByteBuffer.allocate(size);
readFullBuffer(buf, size);
return buf;
}
@Override
public UserInfo getCurrentUserInfo()
{
try
{
ensureStorageConnected();
ByteBuffer buf = makeRequest(1);
buf.put((byte) 1);
buf.flip();
socket.write(buf);
buf = readResponse();
if (1 != buf.getInt())
return null;
return readLines(buf, 1, true)[0];
}
catch (IOException e)
{
closeConnection(e);
return null;
}
catch (BufferUnderflowException e)
{
closeConnection(e);
return null;
}
catch (GreenfootStorageException e)
{
closeConnection(e);
return null;
}
}
private static String getString(ByteBuffer buf) throws BufferUnderflowException
{
int len = buf.getShort();
if (len == -1)
return null;
char[] cs = new char[len];
for (int i = 0; i < len; i++)
{
cs[i] = buf.getChar();
}
return new String(cs);
}
private static void putString(ByteBuffer buf, String value)
{
if (value == null)
{
buf.putShort((short) -1);
}
else
{
buf.putShort((short)value.length());
for (int i = 0; i < value.length(); i++)
{
buf.putChar(value.charAt(i));
}
}
}
private UserInfo[] readLines(ByteBuffer buf, int numLines, boolean useSingleton) throws BufferUnderflowException
{
int numInts = buf.getInt();
int numStrings = buf.getInt();
UserInfo[] r = new UserInfo[numLines];
for (int line = 0; line < numLines; line++)
{
String userName = getString(buf);
int score = buf.getInt();
int rank = buf.getInt();
r[line] = UserInfoVisitor.allocate(userName, rank, useSingleton ? getUserName() : null);
r[line].setScore(score);
for (int i = 0; i < numInts; i++)
{
int x = buf.getInt();
if (i < UserInfo.NUM_INTS)
r[line].setInt(i, x);
}
for (int i = 0; i < numStrings; i++)
{
String s = getString(buf);
if (i < UserInfo.NUM_STRINGS)
r[line].setString(i, s);
}
}
return r;
}
@Override
public boolean storeCurrentUserInfo(UserInfo data)
{
try
{
ensureStorageConnected();
int payloadLength = 0;
payloadLength += 4 + 4 + (1 + UserInfo.NUM_INTS) * 4;
for (int i = 0; i < UserInfo.NUM_STRINGS; i++)
payloadLength += stringSize(data.getString(i));
ByteBuffer buf = makeRequest(1 + payloadLength);
buf.put((byte) 2);
buf.putInt(data.getScore());
buf.putInt(UserInfo.NUM_INTS);
buf.putInt(UserInfo.NUM_STRINGS);
for (int i = 0; i < UserInfo.NUM_INTS; i++)
buf.putInt(data.getInt(i));
for (int i = 0; i < UserInfo.NUM_STRINGS; i++)
putString(buf, data.getString(i));
buf.flip();
socket.write(buf);
buf = readResponse();
byte code = buf.get();
if (code != 0)
{
throw new GreenfootStorageException("Error storing data, code: " + Byte.toString(code));
}
return true;
}
catch (IOException e)
{
closeConnection(e);
return false;
}
catch (BufferUnderflowException e)
{
closeConnection(e);
return false;
}
catch (GreenfootStorageException e)
{
closeConnection(e);
return false;
}
}
private static int stringSize(String string)
{
if (string == null)
return 2;
else{ return 2 + (2 * string.length());
}
}
@Override
public List getTopUserInfo(int limit)
{
try
{
ensureStorageConnected();
ByteBuffer buf = makeRequest(1 + 4);
buf.put((byte) 3);
buf.putInt(limit);
buf.flip();
socket.write(buf);
buf = readResponse();
int numUsers = buf.getInt();
UserInfo[] storage = readLines(buf, numUsers, false);
List<UserInfo> r = new ArrayList<UserInfo>();
for (UserInfo s : storage)
{
r.add(s);
}
return r;
}
catch (IOException e)
{
closeConnection(e);
return null;
}
catch (BufferUnderflowException e)
{
closeConnection(e);
return null;
}
catch (GreenfootStorageException e)
{
closeConnection(e);
return null;
}
}
@Override
public List getNearbyUserInfo(int limit)
{
try
{
ensureStorageConnected();
ByteBuffer buf = makeRequest(1 + 4);
buf.put((byte) 5);
buf.putInt(limit);
buf.flip();
socket.write(buf);
buf = readResponse();
int numUsers = buf.getInt();
if (numUsers < 0)
return null;
UserInfo[] storage = readLines(buf, numUsers, false);
List<UserInfo> r = new ArrayList<UserInfo>();
for (UserInfo s : storage)
{
r.add(s);
}
return r;
}
catch (IOException e)
{
closeConnection(e);
return null;
}
catch (BufferUnderflowException e)
{
closeConnection(e);
return null;
}
catch (GreenfootStorageException e)
{
closeConnection(e);
return null;
}
}
@Override
public GreenfootImage getUserImage(String userName)
{
if (userName == null || userName.equals(""))
userName = storageUserName;
try
{
ensureStorageConnected();
ByteBuffer buf = makeRequest(1 + 2 + (2*userName.length()));
buf.put((byte) 4);
putString(buf, userName);
buf.flip();
socket.write(buf);
buf = readResponse();
int numBytes = buf.getInt();
byte[] fileData = new byte[numBytes];
buf.get(fileData);
try
{
return UserInfoVisitor.readImage(fileData);
}
catch (IllegalArgumentException e)
{
return null;
}
}
catch (IOException e)
{
closeConnection(e);
return null;
}
catch (GreenfootStorageException e)
{
closeConnection(e);
return null;
}
}
@Override
public String getUserName()
{
return storageUserName;
}
}
top,
use,
map,
class GreenfootUtilDelegateStandAlone
. GreenfootUtilDelegateStandAlone
. GreenfootUtilDelegateStandAlone
. getResource
. getSoundFiles
. getGreenfootLogoPath
. closeConnection
. isStorageSupported
. ensureStorageConnected
. makeRequest
. readFullBuffer
. readResponse
. getCurrentUserInfo
. getString
. putString
. readLines
. storeCurrentUserInfo
. stringSize
. getTopUserInfo
. getNearbyUserInfo
. getUserImage
. getUserName
793 neLoCode
+ 8 LoComm