diff --git a/app-common/src/main/java/net/wasdev/gameon/room/common/Exit.java b/app-common/src/main/java/net/wasdev/gameon/room/common/Exit.java index e737a2c..8eca392 100644 --- a/app-common/src/main/java/net/wasdev/gameon/room/common/Exit.java +++ b/app-common/src/main/java/net/wasdev/gameon/room/common/Exit.java @@ -1,16 +1,39 @@ package net.wasdev.gameon.room.common; +/******************************************************************************* + * Copyright (c) 2015 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ + public class Exit { private String name; private String room; + private State state; + private String description; + + public enum State { + open, closed, locked + } public Exit() { //no-args constructor for JSON serialisation } - public Exit(String exitName, String endRoom) { + public Exit(String exitName, String endRoom, String description) { name = exitName; room = endRoom; + this.description = description; } public String getName() { @@ -34,6 +57,20 @@ public String toString() { return "Exit : " + name + " -> " + room; } + public State getState() { + return state; + } + public void setState(State state) { + this.state = state; + } + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + } diff --git a/app-common/src/main/java/net/wasdev/gameon/room/common/RegistrationResponse.java b/app-common/src/main/java/net/wasdev/gameon/room/common/RegistrationResponse.java index 23f833f..082fb4e 100644 --- a/app-common/src/main/java/net/wasdev/gameon/room/common/RegistrationResponse.java +++ b/app-common/src/main/java/net/wasdev/gameon/room/common/RegistrationResponse.java @@ -1,3 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2015 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ package net.wasdev.gameon.room.common; import java.util.UUID; diff --git a/app-common/src/main/java/net/wasdev/gameon/room/common/Room.java b/app-common/src/main/java/net/wasdev/gameon/room/common/Room.java index 50de204..0bb0ade 100644 --- a/app-common/src/main/java/net/wasdev/gameon/room/common/Room.java +++ b/app-common/src/main/java/net/wasdev/gameon/room/common/Room.java @@ -1,3 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2015 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ package net.wasdev.gameon.room.common; import java.util.ArrayList; diff --git a/concierge-app/src/test/java/net/wasdev/gameon/concierge/TestDynamicConcierge.java b/concierge-app/src/test/java/net/wasdev/gameon/concierge/TestDynamicConcierge.java new file mode 100644 index 0000000..f49af69 --- /dev/null +++ b/concierge-app/src/test/java/net/wasdev/gameon/concierge/TestDynamicConcierge.java @@ -0,0 +1,56 @@ +package net.wasdev.gameon.concierge; + +import static org.junit.Assert.*; + +import net.wasdev.gameon.room.common.Exit; +import net.wasdev.gameon.room.common.Room; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.junit.Test; + +/** + * The dynamic strategy will make it harder to draw out a map of the rooms because there is some + * arbitrariness. + */ +public class TestDynamicConcierge { + + @Test + public void registerARoom() { + // We want the room itself to come up and publish to the concierge. So the flow will require the room to say "Here I am concierge" + Concierge c = addEasyStartingRoom(); + assertEquals("The start room should be the first room we add", "Starting Room", c.getStartingRoom().getRoomName()); + } + + @Test + public void placeTwoRoomsNearEachother() { + // We want the room itself to come up and publish to the concierge. So the flow will require the room to say "Here I am concierge" + Concierge c = new Concierge(new DynamicGrowthPlacement()); + Room anEasyRoom = new Room("Starting Room"); + List exits = new ArrayList(); + exits.add(new Exit("North", "Second Room", "Test room")); + anEasyRoom.setExits(exits); + UUID startingRoomUUID = c.registerRoom(anEasyRoom); + + Room secondRoomAsRegistered = new Room("Second Room"); + UUID secondRoomUUID = c.registerRoom(secondRoomAsRegistered); + Room secondRoomAsFound = c.exitRoom(startingRoomUUID, "North"); + assertEquals("The secondRoom should be returned", secondRoomUUID, secondRoomAsFound.getAssignedID()); + } + + + + + private Concierge addEasyStartingRoom() { + Concierge c = new Concierge(); + Room anEasyRoom = new Room("Starting Room"); + List exits = new ArrayList(); + exits.add(new Exit("North", "Second Room", "Test room")); + anEasyRoom.setExits(exits); + c.registerRoom(anEasyRoom); + return c; + } + +} diff --git a/room-app/.gitignore b/room-app/.gitignore index 3b7263f..34ba53a 100644 --- a/room-app/.gitignore +++ b/room-app/.gitignore @@ -14,3 +14,4 @@ /src/main/webapp/META-INF/ /target +/target diff --git a/room-app/src/main/java/net/wasdev/gameon/room/BoringRoom.java b/room-app/src/main/java/net/wasdev/gameon/room/BoringRoom.java index fc5896b..e79c0e4 100644 --- a/room-app/src/main/java/net/wasdev/gameon/room/BoringRoom.java +++ b/room-app/src/main/java/net/wasdev/gameon/room/BoringRoom.java @@ -1,6 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2015 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ package net.wasdev.gameon.room; -import javax.servlet.ServletException; +import javax.json.Json; +import javax.json.JsonObjectBuilder; import net.wasdev.gameon.room.common.Exit; import net.wasdev.gameon.room.common.Room; @@ -13,25 +29,48 @@ * This is a really boring room that doesn't do anything but let people * exit it. */ -public class BoringRoom implements RoomProvider { - private static final String name = "Boring"; - private static final String ENV_ROOM_SVC = "service.room"; +public class BoringRoom { + protected static final String name = "Boring"; + protected static final String ENV_ROOM_SVC = "service.room"; + protected static final String description = "You are the worlds most boring room. There is nothing to do here. There is an exit to the North"; private String endPoint = null; + protected final Room room; + + public BoringRoom() { + room = new Room(name); + getConfig(); + room.setAttribute("endPoint", endPoint + "/ws"); + Exit exit = new Exit("N", "NotWiredUpExit", "A very plain looking door"); + exit.setState(Exit.State.open); + room.addExit(exit); + } - @Override public Room getRoom() throws Exception { - Room room = new Room(name); - getConfig(); - room.setAttribute("endPoint", endPoint); - room.addExit(new Exit("N", "NotWiredUpExit")); return room; } - private void getConfig() throws ServletException { + private void getConfig() { endPoint = System.getProperty(ENV_ROOM_SVC, System.getenv(ENV_ROOM_SVC)); if(endPoint == null) { - throw new ServletException("The location for the concierge service cold not be " + throw new RuntimeException("The location for the concierge service cold not be " + "found in a system property or environment variable named : " + ENV_ROOM_SVC); } } + + protected JsonObjectBuilder toJSON() { + JsonObjectBuilder response = Json.createObjectBuilder(); + response.add(Constants.TYPE, "location"); + response.add(Constants.NAME, name); + response.add(Constants.DESCRIPTION, description); + JsonObjectBuilder exits = Json.createObjectBuilder(); + for(Exit exit : room.getExits()) { + JsonObjectBuilder jsexit = Json.createObjectBuilder(); + jsexit.add(Constants.STATE, exit.getState().name()); + jsexit.add(Constants.DESCRIPTION, exit.getState().name()); + exits.add(exit.getName(), jsexit); + } + response.add(Constants.EXITS, exits); + return response; + } + } diff --git a/room-app/src/main/java/net/wasdev/gameon/room/WebSocket.java b/room-app/src/main/java/net/wasdev/gameon/room/BoringRoomWS.java similarity index 63% rename from room-app/src/main/java/net/wasdev/gameon/room/WebSocket.java rename to room-app/src/main/java/net/wasdev/gameon/room/BoringRoomWS.java index f229447..aada58a 100644 --- a/room-app/src/main/java/net/wasdev/gameon/room/WebSocket.java +++ b/room-app/src/main/java/net/wasdev/gameon/room/BoringRoomWS.java @@ -17,7 +17,11 @@ import java.io.Closeable; import java.io.IOException; +import java.io.StringReader; +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; import javax.websocket.CloseReason; import javax.websocket.EndpointConfig; import javax.websocket.OnClose; @@ -31,30 +35,57 @@ * WebSocket endpoint for player's interacting with the room */ @ServerEndpoint(value = "/ws") -public class WebSocket { +public class BoringRoomWS extends BoringRoom implements RoomProvider { @OnOpen public void onOpen(Session session, EndpointConfig ec) { // (lifecycle) Called when the connection is opened - Log.endPoint(this, "I'm open!"); + Log.endPoint(this, "This room is starting up"); // Store the endpoint id in the session so that when we log and push // messages around, we have something more user-friendly to look at. session.getUserProperties().put("endptId", "player id!"); + try { + session.getBasicRemote().sendText(toJSON().build().toString()); + } catch (IOException e) { + Log.endPoint(this, "Error processing connection : " + e.getMessage()); + tryToClose(session); + } } @OnClose public void onClose(Session session, CloseReason reason) { - // (lifecycle) Called when the connection is closed - Log.endPoint(this, "I'm closed!"); + // (lifecycle) Called when the connection is closed, treat this as the player has left the room + Log.endPoint(this, "A player has left the room"); } @OnMessage public void receiveMessage(String message, Session session) throws IOException { + JsonObject msg = Json.createReader(new StringReader(message)).readObject(); + if(session.getUserProperties().get(Constants.USERNAME) == null) { + //we have a new user so tell everyone that a new player is in town + if(msg.containsKey("username")) { + String username = msg.get("username").toString(); + session.getUserProperties().put(Constants.USERNAME, username); + broadcast(session, "Player " + username + " has entered the room", "You have entered the room"); + } + } + if(msg.containsKey("content")) { + Log.endPoint(this, "Command received from the user, " + this); + if(msg.get("content").toString().equalsIgnoreCase("\"look\"")) { + JsonObjectBuilder response = Json.createObjectBuilder(); + response.add("type", "chat"); + response.add("username", msg.get("username")); + response.add("content", description); + session.getBasicRemote().sendText(response.build().toString()); + return; + } + + } // Called when a message is received. if ("stop".equals(message)) { Log.endPoint(this, "I was asked to stop, " + this); - session.close(); + tryToClose(session); } else { Log.endPoint(this, "I got a message: " + message); // Send something back to the client for feedback @@ -79,13 +110,20 @@ public void onError(Throwable t) { * @param id * @param message */ - void broadcast(Session session, int id, String message) { + void broadcast(Session session, String message, String clientMsg) { // Look, Ma! Broadcast! // Easy as pie to send the same data around to different sessions. for (Session s : session.getOpenSessions()) { try { if (s.isOpen()) { + if(session.getId().equals(s.getId())) { + //this is potentially a specific broadcast to the client + if(clientMsg != null) { + s.getBasicRemote().sendText(clientMsg); + continue; + } + } Log.endPoint(this, "--> ep=" + s.getUserProperties().get("endptId") + ": " + message); s.getBasicRemote().sendText(message); } diff --git a/room-app/src/main/java/net/wasdev/gameon/room/Constants.java b/room-app/src/main/java/net/wasdev/gameon/room/Constants.java new file mode 100644 index 0000000..7961c08 --- /dev/null +++ b/room-app/src/main/java/net/wasdev/gameon/room/Constants.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2015 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ +package net.wasdev.gameon.room; + +public interface Constants { + // A field enum or just free-form? + String USERNAME = "username"; + String BOOKMARK = "bookmark"; + String CONTENT = "content"; + String LOCATION = "location"; + String TYPE = "type"; + String NAME = "name"; + String DESCRIPTION = "description"; + String EXITS = "exits"; + String STATE = "state"; +} diff --git a/room-app/src/main/java/net/wasdev/gameon/room/LifecycleManager.java b/room-app/src/main/java/net/wasdev/gameon/room/LifecycleManager.java index 0ada9ac..fab514a 100644 --- a/room-app/src/main/java/net/wasdev/gameon/room/LifecycleManager.java +++ b/room-app/src/main/java/net/wasdev/gameon/room/LifecycleManager.java @@ -1,3 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2015 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ package net.wasdev.gameon.room; import java.util.Set; diff --git a/room-app/src/main/java/net/wasdev/gameon/room/Log.java b/room-app/src/main/java/net/wasdev/gameon/room/Log.java index 37517fa..6af8611 100644 --- a/room-app/src/main/java/net/wasdev/gameon/room/Log.java +++ b/room-app/src/main/java/net/wasdev/gameon/room/Log.java @@ -1,3 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2015 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ package net.wasdev.gameon.room; import java.util.logging.Logger; diff --git a/room-app/src/main/java/net/wasdev/gameon/room/RoomProvider.java b/room-app/src/main/java/net/wasdev/gameon/room/RoomProvider.java index 4e67558..379d145 100644 --- a/room-app/src/main/java/net/wasdev/gameon/room/RoomProvider.java +++ b/room-app/src/main/java/net/wasdev/gameon/room/RoomProvider.java @@ -1,11 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2015 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ package net.wasdev.gameon.room; import net.wasdev.gameon.room.common.Room; -/* - * Copyright 2015 IBM Corp. - */ - public interface RoomProvider { Room getRoom() throws Exception; } diff --git a/room-wlpcfg/servers/gameon-room/server.env b/room-wlpcfg/servers/gameon-room/server.env index 63b4d56..6581934 100644 --- a/room-wlpcfg/servers/gameon-room/server.env +++ b/room-wlpcfg/servers/gameon-room/server.env @@ -1,2 +1,2 @@ service.concierge=http://localhost:9081/concierge-app-0.0.1-SNAPSHOT/concierge/registerRoom -service.room=http://localhost:9080/rooms/ws +service.room=ws://localhost:9080/rooms diff --git a/room-wlpcfg/servers/gameon-room/server.xml b/room-wlpcfg/servers/gameon-room/server.xml index c7e6057..046228f 100644 --- a/room-wlpcfg/servers/gameon-room/server.xml +++ b/room-wlpcfg/servers/gameon-room/server.xml @@ -6,13 +6,12 @@ localConnector-1.0 jaxrs-2.0 cdi-1.2 + jsonp-1.0 - -