Java String aus anonymer Klasse zwischenspeichern und zurückgeben

apolyton

Lt. Junior Grade
Registriert
Nov. 2007
Beiträge
390
Hallo,

ich probiere mich derzeit am GWT aus und schreibe eine kleine Webanwendung. Da ich den Zugriff auf die XML-Datei an zentrale Stelle händeln möchte, möchte ich da eine extra Klasse zu schreiben.

Code:
public class XmlFileHandler {

	public static String docText;
	
	public static String loadXml() {
		RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET,
				"job_applications.xml");

		try {
			requestBuilder.sendRequest(null, new RequestCallback() {

				@Override
				public void onError(Request request, Throwable exception) {
					requestFailed(exception);
				}

				@Override
				public void onResponseReceived(Request request,
						Response response) {
					docText = response.getText();
				}
			});
		} catch (RequestException ex) {
			requestFailed(ex);
		}
		return docText;
	}

	private static void requestFailed(Throwable exception) {
		Window.alert("Failed to send the message: " + exception.getMessage());
	}
}
Das Problem an der Sache ist, dass mir docText jedes Mal null zurückliefert, obwohl ich das doch mit "docText = response.getText()" zwischenspeichere.

Woran kann das liegen? Gibt es da irgendwie eine praktikable Lösung dazu?

Ich steh total aufm Schlauch und komme einfach nicht weiter.

Ich brauch dringend Hilfe.

Danke im Voraus
 
Wird vielleicht von der Gegenstelle ein leerer String oder null zurückgegeben?
 
Von welcher Gegenstelle? Die Gegenstelle soll doch den String in der nachfolgenden Form erhalten:

Code:
String s = XmlFileHandler.loadXml();
Ich hab noch ein bissl weiter gegoogelt. Scheint so, dass aus anonymen Klassen nichts direkt zurückgegeben werden kann. Aber dazu hab ich ja die docText-Variable erzeugt, damit die den String zwischenspeichern kann.

Hm, sehr merkwürdig!? :confused_alt:
 
würde sagen, das liegt an der Natur des Callbacks bzw. Callbackhandlers: zeitlich gesehen tritt vielleicht das "return docText" vor dem "docText = response.getText()" auf


-- allerdings habe ich dieses Googleding nur kurs angesehen gehabt und ich weiß auch nicht in welchem Zusammenhang deine "kleine Webanwendung" steht.

Ist das innerhalb eines Servlets? Seam oder ein anderes Framework. Ejb 3?
 
Ich hab die Klasse noch etwas erweitert und umgeschrieben. Wesentlich viel hat sich aber im Prinzip nicht geändert. Sieht jetzt so aus:

Code:
public class XmlFileHandler extends ArrayList<ApplicationItem> {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public XmlFileHandler() {
		RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET,
				"job_applications.xml");

		try {
			requestBuilder.sendRequest(null,  new RequestCallback() {

				@Override
				public void onError(Request request, Throwable exception) {
					requestFailed(exception);
				}

				@Override
				public void onResponseReceived(Request request,
						Response response) {
					renderXML(response.getText());
				}
			});
		} catch (RequestException ex) {
			requestFailed(ex);
		}
	}

	private void renderXML(String text) {
		Document applicationDOM = XMLParser.parse(text);
		Element applicationElement = applicationDOM.getDocumentElement();
		XMLParser.removeWhitespace(applicationElement);

		NodeList applicationList = applicationElement
				.getElementsByTagName("company");

		for (int i = 0; i < applicationList.getLength(); i++) {
			Element application = (Element) applicationList.item(i);

			Element address = (Element) application.getElementsByTagName(
					"address").item(0);
			Element job = (Element) application.getElementsByTagName("job")
					.item(0);
			Element contact = (Element) application.getElementsByTagName(
					"contact").item(0);

			ApplicationItem item = new ApplicationItem();
			item.setCompanyName(getElementTextValue(address, "name"));
			item.setContactAvailable(Boolean.parseBoolean(contact
					.getAttribute("available")));
			item.setContactTitle(getElementTextValue(contact, "title"));
			item.setContactFirstName(getElementTextValue(contact, "firstName"));
			item.setContactLastName(getElementTextValue(contact, "lastName"));
			item.setContactPhoneNumber(getElementTextValue(contact,
					"phoneNumber"));
			item.setContactEmail(getElementTextValue(contact, "eMail"));
			item.setStreet(getElementTextValue(address, "street"));
			item.setZipCode(getElementTextValue(address, "zipCode"));
			item.setCity(getElementTextValue(address, "city"));
			item.setState(getElementTextValue(address, "state"));
			item.setSenderFormat(getElementTextValue(address, "senderformat"));
			item.setJobTitle(getElementTextValue(job, "title"));
			item.setJobProfession(getElementTextValue(job, "profession"));

			Element progressHistory = (Element) application
					.getElementsByTagName("progressHistory").item(0);
			NodeList statusList = progressHistory
					.getElementsByTagName("status");

			for (int p = 0; p < statusList.getLength(); p++) {
				Element currentStatus = (Element) statusList.item(p);
				// Status status = new Status();

				// status.setStatusType(currentStatus.getAttribute("type"));
				// status.setStatusTitle(getElementTextValue(currentStatus,
				// "title"));
				// status.setNotes(getElementTextValue(currentStatus, "notes"));
				// status.setDate(parseDate(getElementTextValue(currentStatus,
				// "date")));

				String statusType = currentStatus.getAttribute("type");
				String statusTitle = getElementTextValue(currentStatus, "title");
				String statusNotes = getElementTextValue(currentStatus, "notes");
				Date statusDate = parseDate(getElementTextValue(currentStatus,
						"date"));
				Status status = new Status(statusType, statusTitle,
						statusNotes, statusDate);
				item.add(status);
			}
			add(item);
		}
	}

	private static void requestFailed(Throwable exception) {
		Window.alert("Failed to send the message: " + exception.getMessage());
	}
	
	private String getElementTextValue(Element parent, String elementTag) {
		Node node = parent.getElementsByTagName(elementTag).item(0)
				.getFirstChild();
		String nodeValue = "";

		if (node != null) {
			nodeValue = node.getNodeValue();
		}
		return nodeValue;
	}
	
	private Date parseDate(String dateToFormat) {
		DateTimeFormat sourceFormatter = DateTimeFormat.getFormat("yyyy-MM-dd");
		return sourceFormatter.parse(dateToFormat);
	}
}

Das komische ist, dass sämtliche zuvor hinzugefügte Daten nach folgendem Block einfach nicht mehr da sind. Sie sind weg.

Code:
requestBuilder.sendRequest(null,  new RequestCallback() {

				@Override
				public void onError(Request request, Throwable exception) {
					requestFailed(exception);
				}

				@Override
				public void onResponseReceived(Request request,
						Response response) {
					renderXML(response.getText());
				}
			});

-- allerdings habe ich dieses Googleding nur kurs angesehen gehabt und ich weiß auch nicht in welchem Zusammenhang deine "kleine Webanwendung" steht.

Ist das innerhalb eines Servlets? Seam oder ein anderes Framework. Ejb 3?
Keine Ahnung, was du hier meinst. Ich arbeite hier mit dem GWT und nichts anderem. Prinzipiell möchte ich mit der Klasse einfach eine XML-Datei laden und dort Schritt für Schritt alle Werte auslesen und in der Arraylist speichern.
 
hmmm laut apidoc vom gwt verlangt der RequestBuilder eine qualifizierte URL. Ob hier ein String mit einer Datei ausreicht? Du könntest es mit einer "richtigen" URL (z.B. einer Datei aus dem Internet probieren)

Werde denn irgendwelche Exceptions geworfen?

Wird denn der Callbackhandler überhaupt irgendwann aufgerufen?
 
Also, aufgerufen wird der Callbackhandler auf jeden Fall, nur sind dann alle zuvor gespeicherten Objekte weg.

Ich hab noch weiter geforscht und bin dabei über folgenden Artikel gestolpert: http://www.oreilly.de/catalog/gwebtoolkitger/chapter/ch02.pdf

Wichtig ist der zweite Absatz auf Seite 16 der PDF. Dort steht, dass die Daten ja durch den Requestbuilder asynchron abgerufen werden. Vermutlich ist da längst Objekt erzeugt worden ehe alle Daten geladen und gespeichert werden konnten. Frage ist jetzt, wie ich das synchronisieren kann, damit die Daten auch später verfügbar sind.

Exceptions werden keine geworfen.
 
Synchronisiert Anfragen heisst das du auf die Antwort warten musst. leider hast du aber in GWT keine Möglichkeit sleep zu verwenden. Die beste möglichkeit ist deinen Code so aufzubauen das beim asynchronem callback (also in onResponseReceived) das auswerten deiner Daten erst angestossen wird. Wenn du wirklich keine möglichkeit dafür siehst gibt es noch die sehr unschöne möglichkeit eines busy waits... also in einer schleife immer wieder fragen ob schon ein Ergebnis da ist und erst dann zurückgeben. Das wird aber vorraussichtlich dazu führen das dein browser nicht mehr reagiert bis ein return kommt.
 
Du müsstest das ganze dann etwas anders aufbauen. Von ArrayList ableiten stell ich mir da grade schwierig vor. Aber du könntest z.B. Die klasse umschreiben so das sie ein beliebiges Array mit dem response text befüllt. Nennen wir die mal XMLtoArray mit einer statischen methode parse() dann sagt du im onResponse soetwas wie:
Code:
public void onResponseReceived(Request request, Response response) {
	ArrayList list = new ArrayList();
	XMLtoArray.parse(response.getText(), list);
	processList(list);
}

in die methode processList(ArrayList list) schreibst du dann was auch immer du machen willst nach dem laden der liste...
 
Ah, danke. Werde ich mal zu gegebener Zeit ausprobieren

Edit: Ich glaube, dass ich jetzt die richtige Lösung gefunden habe. Mit JAXP verarbeite ich die XML-Datei serverseitig und gebe dann die dort erstellte Arraylist per RPC an den Client zurück. Der Client nimmt nur noch die Anfragen entgegen und leitet diese ggf. wieder an der Server. So müsste ich eigentlich meinem Ziel erreichen.
 
Zuletzt bearbeitet:
ohne jetzt genau zu wissen was du da vor hast nur ein hinweis:
RPCs sind im GWT auch asynchron.
Aber wenn dir das nichts macht passts denke ich.
 
Naja, hoffentlich klappt das so, wie ich es mir gedacht hab. Bis jetzt siehts gut aus.

Eine Frage habe ich noch: Ich habe bspw. eine Klasse mit mehreren Variablen, die direkt mit den XML-Daten operieren können (siehe JAXB). Gibt es da jetzt in JAXB die Möglichkeit bestimmte Variablen in Kategorien einzuteilen? Habe bis jetzt noch nichts dazu gefunden.

Ich gebe mal am besten Beispiel. Folgende Klasse:
Code:
public class ApplicationItem {

	private static final long serialVersionUID = 1L;

	@XmlAttribute(name = "id")
	private int id;
	private String companyName;
	private Boolean contactAvailable = false;
	private String contactTitle = "";
	private String contactFirstName = "";
	private String contactLastName = "";
	private String contactPhoneNumber = "";
	private String contactEmail = "";
	private String street;
	private String houseNumber;
	private String zipCode;
	private String city;
	private String state;
	private String senderFormat;
	private String jobTitle;
	private String jobProfession;
	private ArrayList<Status> statusList;

	public ApplicationItem() {
		statusList = new ArrayList<Status>();
	}

        ... entsprechende Getter- und Setter-Methoden sind vorhanden
}
Bspw. sollen alle "contact"-Variablen zu einem Contact-XML-Element zusammengefasst werden. Das selbe Prozedere auch bei jobTitle und jobProfession.
als XML sollten die dann in etwa so aussehen:
Code:
<applications>
	<application>
		<contact available="true">
			<title></title>
			<firstName></firstName>
			<lastName></lastName>
			<phoneNumber></phoneNumber>
			<eMail></eMail>
		</contact>
		<job>
			<title></title>
			<profession></profession>
		</job>
	</application>
</application>
 
jaxb kenne ich leider nicht sry
edit: vieleicht fragst du da besser nochmal in einem neuen thema damit jemand drauf aufmerksam wird der sich damit auskennt :)
 
Zurück
Oben