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