Verbindungsaufbau zur Plentymarkets SOAP Api Version 110 mit Java

Das folgende Beispiel zeigt die Verwendung der Plentymarkets SOAP Api Version 110. Die SOAP-Klassen wurden mittels dem in Eclipse eingebauten Tool zur Erstellung von Java-Klassen anhand einer WSDL-Datei generiert.

public class PlentyConnector {
	private Logger logger = Logger.getLogger(PlentyConnector.class);
	private String TOKEN = "";
	private int USERID = -1;
	private PlentySoapApiFunctionContainerServiceStub service = null;

// die weiteren Methoden werden separat gezeigt

}

In der folgenden Methoden wird ein Token geladen, sofern dies noch nicht geschehen ist.

   private void createService(String accountUser, String accountPassword, String portAddress) throws Exception {
		try {
			service = new PlentySoapApiFunctionContainerServiceStub(portAddress);
			if (this.TOKEN.equals("") || USERID == -1) {
                                //request a new token
				GetAuthentificationToken req = new GetAuthentificationToken();
				req.setOLogin(new PlentySoapRequest_GetAuthentificationToken());
				req.getOLogin().setUsername(accountUser);
				req.getOLogin().setUserpass(accountPassword);
				GetAuthentificationTokenResponse resp = service.getAuthentificationToken(req);
				this.TOKEN = resp.get_return().getToken();
				this.USERID = resp.get_return().getUserID();
			}
                        //modify the service and set the userid and token as a header element
			SOAPFactory factory = OMAbstractFactory.getSOAP12Factory();
		    SOAPHeaderBlock header = factory.createSOAPHeaderBlock("verifyingToken", null);
		    OMFactory omFactory = OMAbstractFactory.getOMFactory();
		    OMNode userNameNode = omFactory.createOMElement(new QName("UserID"));
		    ((OMElement) userNameNode).setText(""+USERID);
		    header.addChild(userNameNode);
		    OMNode passwordNode = omFactory.createOMElement(new QName("Token"));
		    ((OMElement) passwordNode).setText(TOKEN);
		    header.addChild(passwordNode);
		    service._getServiceClient().addHeader(header);
			System.out.println("token: " + this.TOKEN + " userid: " + this.USERID);
		}
		catch(Exception e) {
			logger.error("Authentification token not loaded correctly!");
			throw e;
		}
	}

Die nächste Methode zeigt am Beispiel der Serverzeit, wie weitere Aufrufe erfolgen können:

	private void getServerTime() {
		try {
	    	PlentySoapResponse_GetServerTime resp = service.getServerTime(new GetServerTime()).get_return();
	    	System.out.println("Servertime : "+resp.getTimestamp());
	   }   
	   catch(Exception e) {
		   logger.error("Server time not loaded correctly: " + e.getMessage(), e);
	   }
	}

In der nachfolgenden Methode wird ein Aufruf mit ein paar Testdaten durchgeführt, um die Funktionsweise zu veranschaulichen:

	public void executePlentyCall() throws Exception {
		System.out.println("login");
		createService("MyUserName", "MyPassword", "http://my.plenty.installation.de/soap/version110/");
		getServerTime();
}

Die SOAP-Klassen zum Verbindungsaufbau wurden mit Hilfe des axis2-Tools wsdl2java.bat erstellt.

java über Kommandozeile auf Linux-Server installieren

Java-Version installieren

Zunächst wird die aktuelle Java-Version (derzeit 1.7.45) heruntergeladen. Der Download kann über die Java-Download-Seite erfolgen, oder mittels folgendem Kommando:
wget --no-cookies --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com" "http://download.oracle.com/otn-pub/java/jdk/7u45-b18/jdk-7u45-linux-i586.tar.gz"

Danach kann Java wie auf http://www.java.com/de/download/help/linux_install.xml beschrieben installiert werden.

Dazu auf der Konsole den Befehl
tar zxvf jdk-7u45-linux-i586.tar.gz
absetzen. Der Benutzer muss sich dazu in einem Verzeichnis befinden, in dem er Schreibrechte hat, siehe dazu http://www.java.com/de/download/help/linux_install.xml#Java for Linux Platforms. Anschließend sollten noch die Pfad-Angaben ergänzt werden.

MysqlDataTruncation: Data truncation: Data too long for column

Beim Speichern eines neuen Datensatzes in einem Java-Webservice, bin ich auf den Fehler „Data too long for column“ gestoßen. Eigentlich eine klare Sache – doch nicht in diesem Fall.

Die Entwicklungsumgebung:

  • jboss application server
  • Java 1.7, JPA und Hibernate
  • MySQL-Datenbank

Die Java-Bean hat ein Feld namens myclass vom Typen MyClass (Klassennamen wurde geändert ;-)). Das sieht ungefähr so aus:

@Column(nullable=false);
private MyClass myclass;

Das Bauen der War-Datei und das Deployen funktioniert reibungslos. Auch können andere Datensätze problemlos eingetragen werden. Doch sobald oben erwähnter Datensatz mittels em.persist in Die Datenbank übernommen werden soll, erscheint eine recht lange Fehlermeldung. Ein Auszug der Fehlermeldung:

Caused by: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'myclass' at row 1
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4188) [mysql-connector-java-5.1.20.jar:]
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4122) [mysql-connector-java-5.1.20.jar:]
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2570) [mysql-connector-java-5.1.20.jar:]
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2731) [mysql-connector-java-5.1.20.jar:]
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2818) [mysql-connector-java-5.1.20.jar:]
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2157) [mysql-connector-java-5.1.20.ja
r:]
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2460) [mysql-connector-java-5.1.20.jar:
]
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2377) [mysql-connector-java-5.1.20.jar:
]
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2361) [mysql-connector-java-5.1.20.jar:
]
at org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.executeUpdate(WrappedPreparedStatement.java:493)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:133) [hibernate
-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]

Ein Blick in die Datenbank zeigt, dass die Spalte als tinyblob angelegt wurde. Offensichtlich weiß JPA also nicht genau, was ich in dieser Spalte speichern möchte und nimmt an, dass es sich um einen größeren Wert handeln könnte. Daher muss die Spalte etwas genauer spezifiziert werden:

@OneToOne(cascade={CascadeType.REFRESH,CascadeType.MERGE},fetch = FetchType.EAGER)
@JoinColumn(nullable=false)
private MyClass myclass;

Aus @Column wurd ein @JoinColumn und die One-To-One-Beziehung wurde explizit hinzugefügt. Beim Erstellen der Datenbank-Tabelle ist aus dem Feld ein INT mit der Länge 11 geworden und das Hinzufügen des Datensatzes funktioniert wie erwartet.