ManagedProperty ApplicationScope

Diskutiere ManagedProperty ApplicationScope im Application Tier Bereich.
E

engeliii23

Hi zusammen

Habe bis jetzt nur immer als Gast gelesen, jetzt habe ich selbst mal eine Frage.

Ich implementiere gerade eine eigene GameLobby, und jetzt ist mir aufgefallen, dass mir beim Storen der einzelnen GameRooms ein Fehler unterlaufen ist.
Und zwar habe ich als Key einen String verwendet und als Value mein eigener GameRoom.
Java:
private Map<String, GameRoom> gameRooms;
Jetzt habe ich festgestellt, dass, obwohl ich den selben Key aus Copy-Past verwendet habe, beim Beitreten in einen vorhandenen GameRoom einene Fehler gibt, nämlich, dass die GameID nicht übereinstimmt.

Ich habe auch schon eine Vermutung.. Und hoffe deshalb, dass Ihr mir einen einfacheren Weg zeigen könnt. Ich vermute, dass die HashMap den Key mit == überprüft, was zur Folge hat, dass nicht beide String-Objekte gleich sind. Denn wenn ich mir die ganze Map ausgebe und diese dann in einem TestProgramm mit equals vergleiche, dann ist alles zu 100% true. Was ich aber dann komisch finde ist, dass ich in ca. 80% der Tests durch komme, nur in 20% nicht. Wieso ist das so?

Danke schon mal im Voraus für eure Hilfe.
 
Zuletzt bearbeitet von einem Moderator:
faetzminator

faetzminator

Ich habe auch schon eine Vermutung.. Und hoffe deshalb, dass Ihr mir einen einfacheren Weg zeigen könnt. Ich vermute, dass die HashMap den Key mit == überprüft, was zur Folge hat, dass nicht beide String-Objekte gleich sind. [...]
Falsch, natürlich vergleicht die [japi]HashMap[/japi] mit [c]equals()[/c] (und [c]hashCode()[/c]).
Denn wenn ich mir die ganze Map ausgebe und diese dann in einem TestProgramm mit equals vergleiche, dann ist alles zu 100% true. Was ich aber dann komisch finde ist, dass ich in ca. 80% der Tests durch komme, nur in 20% nicht. Wieso ist das so?
Weil die Keys nicht übereinstimmen. Lass die mal zwischen "" ausgeben, dann siehst du auch "versteckte" Leerzeichen etc.
 
M

Michael...

Ich habe auch schon eine Vermutung.. Und hoffe deshalb, dass Ihr mir einen einfacheren Weg zeigen könnt. Ich vermute, dass die HashMap den Key mit == überprüft
Falsch vermutet: Neben dem Hash der Keys wird auf == || equals geprüft.
Ich vermute der Fehler liegt an anderer Stelle.
 
E

engeliii23

Lass die mal zwischen "" ausgeben, dann siehst du auch "versteckte" Leerzeichen etc.
Wieso sollte ich dann versteckte leerzeichen sehen?
Achso, Tschuldigung, ich habe vergessen zu sagen, dass ich natürlich, bevor ich die Keys store, immer trimme, um eben genau die Leerzeichen etc. zu verhindern. Die Keys sind gleich, sie sind vom System generiert, der einzige unterschied ist, dass der zweite über Copy-Paste eingesetzt wird, aber auch dann funktionierts (meistens).
 
E

engeliii23

Falsch vermutet: Neben dem Hash der Keys wird auf == || equals geprüft.
Ich vermute der Fehler liegt an anderer Stelle.
Okay, aber wo..? :S Ich das Ganze geschieht via Webpage (JSF 2.0), und die Strings sind ja gleich, deshalb kapiere ich das ja nicht mehr.. ich versuche jett sicher schon 2 Tage daran...
 
E

engeliii23

Hööh...? Kannst du mir das mal genauer erklären..? Trotz trim noch leerzeichen(wtf)?

Okay also soll ich den token so ausgeben:
Java:
System.out.print("\"" + token + "\"");
Oder was....?? Und dann sollte ich z.t. leerzeichen sehen..?
 
faetzminator

faetzminator

Debugger oder Konsolenausgaben wären eine Idee, gerade wenn man noch die Keys der Map (sortiert) ausgibt. Dann kann man sich mit eigenen Augen davon überzeugen, dass die HashMap nicht lügt :)
 
N

nillehammer

Fragen wir mal anders: Welcher Teil Deines Codes (bitte ggf. posten) bringt Dich denn zu der Annahme, dass die HashMap gleiche Keys nicht erkennt?

Falls Du damit die Möglichkeit mehrfacher puts mit selbem Key meinst, ist das kein Indiz. Es wird dabei nämlich nur der Value des Mappings ersetzt. Auch der Aufruf von get, der null zurück gibt ist kein valider Beweis, wenn die Map null als Values zulässt.

Der einzig richtige Weg, fest zu stellen, ob ein Key in einer Map bereits vorhanden ist, ist der Aufruf von containsKey(...). Und ich bin ziemlich sicher, dass dieser bei gleichen Keys ein true zurück gibt.
 
Zuletzt bearbeitet von einem Moderator:
S

Spacerat

Verwendest du etwa IdentityHashMap? Dann wär's kein Wunder, weil die vergleicht ausschliesslich mit "==". Im übrigen trägt diese Map deswegen den Namen "Hash" völlig zu unrecht würd' ich sagen.
 
E

engeliii23

Aalso.. Zur allgemeinen Fehlerbeseitigung:

Der Aufruf erfolgt via generiertem Code, welcher dem GameRoom Owner mitgeteilt wird, wenn der Room erstellt ist. Dieser kann er dann den gewünschten Leuten mitteilen, welche dann joinen können, bis der Room voll ist. Dies geschieht über ein gganz normales h:form / inputtext des JSF:
HTML:
<h:outputLabel for="gameRoomId" value="Spiel ID: " />
<h:inputText id="gameRoomId" value="#{playerController.gameRoomId}" required="true" requiredMessage="Angabe ben&ouml;tigt!" />
<h:message for="gameRoomId" />
						
<h:commandLink action="#{playerController.joinGameRoom}" value="Spiel beitreten">
</h:commandLink>
Diese wird dann via playerController (SessionScoped) an den GamesController (ApplicationScoped) weitergeleitet, welcher dann den aufruf prüft, und die eingegebene GameID, welche im Player selbst gespeichert wird, prüft, und falls diese schon vorhanden ist, den Player dem Game hinzufügt:

Java:
	public boolean joinGameRoom(Player player) {
		boolean retc = false;
		if (gameRooms.containsKey(player.getGameRoomId())) {
			if (gameRooms.get(player.getGameRoomId()) != null) {
				if (gameRooms.get(player.getGameRoomId()).addPlayer(player)) {
					retc = true;
				}
			}
		}
		return retc;
	}
Jetzt seht ihr, dass ich containsKey, etc. alles verwende... Ich finde echt den Fehler nicht...... Und ps: Debugging habe ich auch schon versucht, der Room ist erstellt, alles ist vorhanden, der Key ist OHNE Leerschläge in der Map vorhanden....

Wie gesagt in ca. 20% der Fälle wird die GameID, welche ein simpler Token ist, 25 Zeichen ohne Sonderzeichen, nur a-zA-Z0-9.... immer alle 4 Zeichen mit Bindestrich getrennt...
 
faetzminator

faetzminator

Was gibt denn [c]false[/c] zurück? Zeile 3 oder 4? Kannst du das mal in Erfahrung bringen?
Ansonsten, verwendest du DI (Spring o.ä.)? Vielleicht klappt da was nicht mit der Session und App scoped DI? Oder du säuberst irgendwann die Objekte?
Oder wie auch immer, raten kann man lange...
 
E

engeliii23

Aalso..

Ich habe das ganze schon debuggt, die Objekte sind immernoch vorhanden, auch wenn es fehlschlägt. Die Zeile, die false zurückgibt, ist die:
Java:
if (gameRooms.containsKey(player.getGameRoomId())) {
aber wenn ich debugge und nachher von hand schaue, ist das Objekt mitsamt der UserListe des GamRooms vorhanden....

GamesController:
Java:
@ManagedBean
@ApplicationScoped
public class GamesController {
.....
.....
public boolean joinGameRoom(Player player) {
		boolean retc = false;
		if (gameRooms.containsKey(player.getGameRoomId())) {
			if (gameRooms.get(player.getGameRoomId()) != null) {
				if (gameRooms.get(player.getGameRoomId()).addPlayer(player)) {
					retc = true;
				}
			}
		}
		return retc;
	}
PlayerController:
Java:
@ManagedBean
@SessionScoped
public class PlayerController {

	@ManagedProperty(value="#{gamesController}")
	private GamesController gamesController;
.....
.....
	public void joinGameRoom() {
		if (gamesController.joinGameRoom(player)) {
			pageState+=2;
		} else {
			pageState = 1;
			player.setGameRoomId("");
		}
	}
So haben wir eine Verbindung. Und die steht ja, würde sonst ja nicht bis zum containsKey kommen.

Damit der Zusammenhang ganz hier ist noch die Atribute der Klasse Player:
Java:
public class Player {

	private String id;
	private String name;
	
	private String gameRoomInitType;
	private String gameRoomId;
Danach normale Getter und Setter jedes Attrubutes wo nötig, und beim setGameRoomId()--> trim()...
 
faetzminator

faetzminator

Da wir nicht für dich debuggen können, gib mal folgendes aus:
Java:
if (gameRooms.containsKey(player.getGameRoomId())) {
    // ...
} else {
    System.err.println("not found: '" + player.getGameRoomId() + "'");
    System.err.println("rooms: " + gameRooms.keySet());
}
 
E

engeliii23

Code:
not found: 'aNlFT-ez7d-yp6a-grZr-fQUN-uIuy-AHr0-Z8O0-PqU3-On2w'
rooms: []
okay, schritt weiter.. beim debuggen wird der room angezeigt... In dem Browser, in dem ich den Room rstellt habe, bleibt der Room auch (d.h. er existiert noch in der Map, sonst könnten die GameInfos nicht dargestellt werden, und die werden immer aus dem GameRoom geholt..). Wenn ich in dem Browser, der Joint, es aber nicht funktioniert hat, den Browsercache lösche ( = neue Session), dann gehts es wieder beim nächsten Versuch.... WTF?
Laggiger Browser..? Oder An den Scopes der Beans was verhauen? (müsste ja eben nicht, aber wieso ist die liste dann leer? Ich "resette" nirgends die liste... das game ist ja DA-.-

Java:
package ch.savk.gamelobby.web.global;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;

import ch.savk.gamelobby.rto.GameTypesRTO;
import ch.savk.gamelobby.type.GameRoom;
import ch.savk.gamelobby.type.GameType;
import ch.savk.gamelobby.type.Player;
import ch.savk.gamelobby.util.TokenGenerator;

@ManagedBean
@ApplicationScoped
public class GamesController {

	private List<Player> players;
	private Map<String, GameRoom> gameRooms;
	
	
	public GamesController() {
		players = new ArrayList<Player>();
		gameRooms = new HashMap<String, GameRoom>();
	}
	
	public void startGame(Player player) {
		gameRooms.get(player.getGameRoomId()).start();
	}
	
	public boolean joinGameRoom(Player player) {
		boolean retc = false;
		if (gameRooms.containsKey(player.getGameRoomId())) {
			if (gameRooms.get(player.getGameRoomId()) != null) {
				if (gameRooms.get(player.getGameRoomId()).addPlayer(player)) {
					retc = true;
				}
			}
		} else {
			System.err.println("not found: '" + player.getGameRoomId() + "'");
			System.err.println("rooms: " + gameRooms.keySet());
		}
		return retc;
	}
	
	public String addNewGameRoom(Player player) {
		GameRoom gameRoom = new GameRoom();
		String gameRoomToken = TokenGenerator.generateToken();
		gameRooms.put(gameRoomToken, gameRoom);
		return gameRoomToken;
	}
	
	public void registratePlayer(Player player) {
		players.add(player);
	}
	
	public void removePlayer(Player player) {
		players.remove(player);
		try {
			gameRooms.get(player.getGameRoomId()).removePlayer(player);
			if (gameRooms.get(player.getGameRoomId()).getPlayers().size() == 0) {
				gameRooms.remove(player.getGameRoomId());
			}
		} catch (Exception e) {}
	}
	
	public GameRoom getGameRoomById(String gameId) {
		return gameRooms.get(gameId);
	}

	public List<Player> getPlayers() {
		return players;
	}

	public List<GameType> getGameTypes() {
		return GameTypesRTO.getGameTypes();
	}
}
 
S

SlaterB

> @ManagedProperty(value="#{gamesController}")
> private GamesController gamesController;

mir fehlt das Detailwissen, aber ist das hier das richtige oder erstellt es vielleicht ein neues Objekt?
logge im Konstruktor von GamesController, zumindest wie oft es erstellt wird

> Laggiger Browser..?

den Browser lasse aus dem Spiel, in erster Linie musst du wissen, was auf Serverseite passiert,
das beginnt mit einem Log aller einkommenden Request (und ungefähre Ahnung/ Wissen/ Log, was das jeweils für Auswirkungen zum Zustand aller Datenstrukturen hat)

wenn der Browser cacht, dann kommt vielleicht kein Request zum Server, sollte nicht schlimm sein
 
E

engeliii23

@managedProperty erstellt kein neues Objekt, es assoziiert das vorhandene (Deshalb muss die Session gleich oder länger dauern, da sonst irgendwann null vorkommen würd.e..)... DI... bei angabe eines name="" im managedBean ist Namensänderung des Objektes möglich, ansonsten ist es unter dem Klassennamen zu finden... (einfach lowCamelCase).....
okay, aber weshalb funktioniert dann KEIN Join mit der Broswersession, und sobald eine neue aufgebaut wird, funktioniert es? (Werden dann ja auch neue userSessions serverseitig angelegt).
 
Zuletzt bearbeitet:
S

SlaterB

mal zurück auf
> not found: 'aNlFT-ez7d-yp6a-grZr-fQUN-uIuy-AHr0-Z8O0-PqU3-On2w' rooms: []

was ist diese Ausgabe? ist das ein Request eines 'joinenden Browsers B'?
diese Ausgabe sagt doch klipp und klar, dass die Map leer ist,
wenn das der Fall ist muss man dem Browser keinen Vorwurf machen,
mehr als in die Java-Klasse hineinzudringen und die Map abzufragen geht ja kaum

und du sagst,
- dass zu diesem Zeitpunkt ein anderer User A bereits einen Room erstellt hat, einen GamesController mit nicht-leerer Map kennt?
(auch nach der "rooms: [] " nochmal bestätigt?)
- dass bei irgendeiner Art Reset B dann auch den Raum findet, ohne dass dieser speziell angelegt wird, sondern jetzt gefunden, Map nicht leer?

mysteriöse Sache, ich kann vorerst beitragen:
- logge bitte auch den Hashcode von gamesController bei jeder Ausgabe, etwa
> System.err.println("rooms: " + hashCode()+", "+gameRooms.keySet());

- logge jedes Erstellen eines GamesController, gib dort gleich seinen hashCode() aus, damit man weiß welcher das ist,
logger mit new Error().printStackTrace(); die Aufrufer, vielleicht kann man ungefähr erkennen, wer das jeweils macht,
günstig ist natürlich genau zu verfolgen, welcher User gerade welchen Request macht,
auch im Log bzw. du weißt ja sicherlich was du gerade aufgerufen hast
 
E

engeliii23

>INFO: Server startup in 3904 ms
>GamesController: 1336627115
>GamesController: 1281510498
>not found: '9QSGw-DrYq-bq3R-7eOn-RBsd-rbWH-xG84-qQi4-9ywg-rw0H'
>rooms: []
>GamesController: 1336627115
>found
----------
Okay, du hast recht. Es wird ein neues Ojekt erzeugt, warum auch immer.... Jemand eine Idee.?

Ich probiers einfach mal mit @ManagedBean (name="<name>")
 
F

Fant

> @ManagedProperty(value="#{gamesController}")
> private GamesController gamesController;

mir fehlt das Detailwissen, aber ist das hier das richtige oder erstellt es vielleicht ein neues Objekt?
logge im Konstruktor von GamesController, zumindest wie oft es erstellt wird
Nein, mit der @ManagedProperty-Annotation nicht. Hier wird wirklich auf die ManagedBean aus dem entsprechenden Scope zurückgegriffen. Anders wäre das mit den @Inject-Annotation. Damit würde wirklich eine neue Instanz der Bean angelegt werden.
Um ganz sicher zu sein könnte man sich die Instanz des GameController aber testweise auch mal im Konstruktor manuell aus dem FacesContext holen.

Den Fehler hab ich aber auch noch nicht entdecken können.

Edit:
siehePost über mir: Jedenfalls sollte das so sein :eek:
 
Thema: 

ManagedProperty ApplicationScope

Passende Stellenanzeigen aus deiner Region:
Anzeige

Neue Themen

Anzeige

Anzeige
Oben