File upload, benutze EJB3 und Swing-Client

ThirdKeeper

Mitglied
Hallo zusammen!

(!) Problemstellung:
Es werden mittels EJB3 Entities erzeugt und über JPA mit dem JBoss Container verwaltet.
Ein Entity beinhaltet ein Image zur Darstellstellung eines Artikels,
welches von der Clientseite zugewiesen werden soll.

Nun möchte ich die Datei auf den Server uploaden (in eine Directory) und die URL in der DB (über das Entity) verwalten. Die Bilddatei soll aus Performancegründen nicht in der Datenbank gespeichert werden!

Am liebsten würde ich das ganze über eine StatelessSessionBean realisieren,
aber meine Versuche dies um zu setzen sind bisher leider alle fehlgeschlagen.
Hat jemand dazu einen guten Tip für mich?

Eingesetzte Software:
Clientseite: Swing-Rich-Client
Sverseite: JBoss4.2.0.GA, Hibernate, MySQL 5.0

Ausschnitt der StatelessSessionBeanImpl (funktioniert leider nicht):
Code:
@Stateless
@Remote(ArticelService.class)
public class ArticelServiceImpl <T, PK extends Serializable> 
extends GenericDaoImpl <Articel, Long, Customer>
implements ArticelService{
...
	public void imageUpload(String imageId, ImageIcon img){
		save(new File(imageId+".jpg"), img);
	}

	public ImageIcon imageDownload(String imageId){
		return (ImageIcon) load(new File(imageId+".jpg"));
	}

	protected boolean save(File f, Object obj) {
		try {
			FileOutputStream fileStream = new FileOutputStream(f);
			ObjectOutputStream ObjectOutput = new ObjectOutputStream(fileStream);
			ObjectOutput.writeObject(obj);
			ObjectOutput.close();
			return true;
		} catch (IOException e) {
			System.err.println("Die Bilddatei wurde aufgrund eines Fehlers nicht gespeichert!");
			e.printStackTrace();
			return false;
		}
	}

	protected Object load(File file) {
		Object obj = null;
		try {
			FileInputStream fileInput = new FileInputStream(file);
			ObjectInputStream objectInput = new ObjectInputStream(fileInput);
			obj = objectInput.readObject();
			objectInput.close();
		} catch (Exception e) {
			System.err.println("Die Bilddatei wurde aufgrund eines Fehlers nicht gelesen!");
			e.printStackTrace();
		}
		return obj;
	}
}

Bitte helft mir, meine Nerven liegen schon völligst blank.
P.S. :google: hab ich schon lange, lange nach einer Lösung gesucht. ;)
 
Vielleicht schreibst du noch dazu, was nicht funktioniert? Welche Exception fliegt? Welcher Stacktrace liegt dann vor?

Vielleicht noch ein paar Gedanken (auch allgemeiner Natur, nicht unbedingt problemspezifisch) zu Sachen, die mir nach kurzem Hinschauen auffallen: Wieso parametrisierst du die Serviceimplementierung? Die Instanzen werden doch vom Container erzeugt und den kümmert das wenig. Komisch ist auch, das eine Implementierung des Servicelayers eine DAO Implementierung extended. Eine EntityManagerFactory Property mit @PersistenceContext täts doch auch, oder?

Ansonsten sieht die Idee eigentlich nicht schlecht aus.

REINHAUN!
 
Hallo Oliver,

Wieso parametrisierst du die Serviceimplementierung?
Die Serviceimplementierung verwendet noch andere Methoden die hier nicht aufgelistet sind.
Sie erbt von der generischen Klasse GenericDaoImpl (wie auch andere ServieImpl in meinem Proojekt).

Dadurch werden gleiche Methoden mit unterschiedlichen Parametern durch identische Methodenaufrufe verwendbar und der Code muss nicht in jeder ServiceImpl neu geschrieben werden (Bessere Wartbarkeit und Wiederverwendbarkeit des Codes).

Eine EntityManagerFactory Property mit @PersistenceContext täts doch auch, oder?
Mit dem Pattern hab ich mich (zu meiner Schande) bisher noch nicht befasst. Was ich in kürze aber nacholen werde.

Zur ursprünglichen Problemstellung:
Der Code funktioniert, so wie er ganz oben abgebildet ist!
Der Fehler lag auf der Clientseit. :suspekt:

Nur ist die Vorgehensweise alles andere als effizient, denn eine Bilddatei (z.B. 498 kb) ist nach dem Transfer um ein vielfaches größer (z.B. 1.621 kb).
Deshalb hab ich mich für ImageIO umentschieden.

Versuche ich Serverseitig zu lese/schreiben (Code s.u.) funktioniert das leider nicht.
Code:
...
Client (JUnit-Test):
	@Test
	public void testImagesCRUD() throws Exception {
		Articel articel = null;

		if((articel=(Articel)articelRemote.findArticelByName("Keinohrhase").get(0)) != null){
			BufferedImage img = null;
			try {
				img = ImageIO.read(new File("D:/iIcons/test.png"));
				assertNotNull(img);
				assertTrue(articelRemote.imageUpload("tester", img));//Fehler in dieser Zeile!
				img = articelRemote.imageDownload("tester");
				assertNotNull(img);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}}

Server:
	public boolean imageUpload(String imageId, BufferedImage img){
		return save(new File(imageId+".png"), img);
	}

	protected boolean save(File file, BufferedImage img) {
			try {
				ImageIO.write(img, "png", file);
				return true;
			} catch (IOException e) {
				e.printStackTrace();
				return false;
			}
	}

	public BufferedImage imageDownload(String imageId){
		return load(imageId);
	}

	protected BufferedImage load(String imageId) {
		BufferedImage img = null;
		try {
			img = ImageIO.read(new File(imageId+".png"));
		} catch (FileNotFoundException e) {
			System.err.println("Die Bilddatei ist nicht auffindbar!");
			e.printStackTrace();
		} catch (IOException e) {
			System.err.println("Die Bilddatei wurde aufgrund eines IO-Fehlers nicht gelesen!");
			e.printStackTrace();
		}
		return img;
	}
Ein lokaler Aufruf über eine Main methode funktioniert!?

StackTrace:
Code:
java.lang.reflect.UndeclaredThrowableException
	at $Proxy10.imageUpload(Unknown Source)
	at de.test.DBUnitTest.testImagesCRUD(DBUnitTest.java:328)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99)
	at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81)
	at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
	at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75)
	at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45)
	at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:66)
	at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35)
	at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42)
	at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
	at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: java.rmi.MarshalException: Failed to communicate.  Problem during marshalling/unmarshalling; nested exception is: 
	java.io.NotSerializableException: java.awt.image.BufferedImage
	at org.jboss.remoting.transport.socket.SocketClientInvoker.handleException(SocketClientInvoker.java:122)
	at org.jboss.remoting.transport.socket.MicroSocketClientInvoker.transport(MicroSocketClientInvoker.java:644)
	at org.jboss.remoting.MicroRemoteClientInvoker.invoke(MicroRemoteClientInvoker.java:122)
	at org.jboss.remoting.Client.invoke(Client.java:1550)
	at org.jboss.remoting.Client.invoke(Client.java:530)
	at org.jboss.aspects.remoting.InvokeRemoteInterceptor.invoke(InvokeRemoteInterceptor.java:62)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
	at org.jboss.aspects.tx.ClientTxPropagationInterceptor.invoke(ClientTxPropagationInterceptor.java:61)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
	at org.jboss.aspects.security.SecurityClientInterceptor.invoke(SecurityClientInterceptor.java:53)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
	at org.jboss.ejb3.remoting.IsLocalInterceptor.invoke(IsLocalInterceptor.java:72)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
	at org.jboss.ejb3.stateless.StatelessRemoteProxy.invoke(StatelessRemoteProxy.java:103)
	... 22 more
Caused by: java.io.NotSerializableException: java.awt.image.BufferedImage
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.writeArray(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.writeObject(Unknown Source)
	at java.rmi.MarshalledObject.<init>(Unknown Source)
	at org.jboss.aop.joinpoint.MethodInvocation.writeExternal(MethodInvocation.java:318)
	at java.io.ObjectOutputStream.writeExternalData(Unknown Source)
	at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
	at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
	at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.writeObject(Unknown Source)
	at org.jboss.remoting.serialization.impl.java.JavaSerializationManager.sendObjectVersion2_2(JavaSerializationManager.java:120)
	at org.jboss.remoting.serialization.impl.java.JavaSerializationManager.sendObject(JavaSerializationManager.java:95)
	at org.jboss.remoting.marshal.serializable.SerializableMarshaller.write(SerializableMarshaller.java:120)
	at org.jboss.remoting.transport.socket.MicroSocketClientInvoker.versionedWrite(MicroSocketClientInvoker.java:967)
	at org.jboss.remoting.transport.socket.MicroSocketClientInvoker.transport(MicroSocketClientInvoker.java:557)
	at org.jboss.remoting.MicroRemoteClientInvoker.invoke(MicroRemoteClientInvoker.java:122)
	at org.jboss.remoting.Client.invoke(Client.java:1550)
	at org.jboss.remoting.Client.invoke(Client.java:530)
	at org.jboss.aspects.remoting.InvokeRemoteInterceptor.invoke(InvokeRemoteInterceptor.java:62)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
	at org.jboss.aspects.tx.ClientTxPropagationInterceptor.invoke(ClientTxPropagationInterceptor.java:61)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
	at org.jboss.aspects.security.SecurityClientInterceptor.invoke(SecurityClientInterceptor.java:53)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
	at org.jboss.ejb3.remoting.IsLocalInterceptor.invoke(IsLocalInterceptor.java:72)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
	at org.jboss.ejb3.stateless.StatelessRemoteProxy.invoke(StatelessRemoteProxy.java:103)
	at $Proxy10.imageUpload(Unknown Source)
	at de.mck.system.test.DBUnitTest.testImagesCRUD(DBUnitTest.java:328)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99)
	at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81)
	at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
	at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75)
	at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45)
	at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:66)
	at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35)
	at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42)
	at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
	at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
	at org.jboss.aspects.remoting.InvokeRemoteInterceptor.invoke(InvokeRemoteInterceptor.java:74)
	... 30 more
 
Hallo,

warum streamst du nicht direkt das Bild zum Client? (Der könnte das dann auch noch lokal Cachen...)

BufferedImages sind nicht Serialisierbar. ... mit einem ObjectOutputStream versendet man doch keine Bilder...

Dafür gibts natürlich mehrere Lösungen:
A) Auf dem Server liest du das Bild per ImageIO in ein byte[] ein und verschickst dieses zum Client. Auf dem Client liest du das byte[] (ByteArrayInputStream) mit ImageIO wieder ein und zeigst es an.

Anstatt ImageIO kannst du auch den JPegEncoder / JpegDecoder verwenden, der ist um einiges schneller.

B) Du stellst die Bilder über ein Servlet zum Download bereit. Du schickst zu den Artikelinformationen nur noch die ID des Bildes. Mit dieser Information werden sich der Client dann an den Server und läd das Bild (über eine URLConnection) runter wenn er es wirklich braucht, liest es dann als Bild ein und zeigt es dann entsprechend an.

Gruß Tom
 
Erst mal vielen Dank Tom,

mit den Angaben konnte ich das Ganze sinnvoll umsetzen.
Für alle die ein ähnliches Problem haben, hier eine mögliche Lösung zum jpg up-/download:

Converter:
Code:
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageDecoder;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class ImageConverter {
    public static byte[] bufferedImageToByteArray(BufferedImage img) {
		ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
		ObjectOutputStream objectStream;
		try {
			objectStream = new ObjectOutputStream(byteStream);
			JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(objectStream);
			encoder.encode(img);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return byteStream.toByteArray();
    }

    public static BufferedImage getBufferedImage(byte[] imageByteArray) {
    	ByteArrayInputStream byteStream = new ByteArrayInputStream(imageByteArray);
    	ObjectInputStream objectStream;
    	JPEGImageDecoder decoder = null;
		try {
			objectStream = new ObjectInputStream(byteStream);
			decoder = JPEGCodec.createJPEGDecoder(objectStream);
	        return decoder.decodeAsBufferedImage();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
    }
}

ServiceImpl:
Code:
...
	public boolean imageUpload(String imageId, byte [] byteImage){
		OutputStream out=null;
		try {
			out = new DataOutputStream(new FileOutputStream(DIR_HOME+imageId+".jpg"));
			ImageIO.write(ImageConverter.getBufferedImage(byteImage), "jpg", out);
                        out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return true;
	}

	public byte [] imageDownload(String imageId){
		try {
			return ImageConverter.bufferedImageToByteArray(ImageIO.read(new File(DIR_HOME+imageId+".jpg")));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
...

Client (JUnit Test):
Code:
@Test
	public void testImagesCRUD() throws Exception {
		Articel articel = null;

		if((articel=(Articel)articelRemote.findCustomerArticelByName("Keinohrhase").get(0)) != null){
			BufferedImage img = null;
			try {
				img = ImageIO.read(new File(DIR_HOME+"test.jpg"));
				assertNotNull(img);
				assertTrue(articelRemote.imageUpload("test2", ImageConverter.bufferedImageToByteArray(img)));

				img = ImageConverter.getBufferedImage(articelRemote.imageDownload("test2"));
				assertNotNull(img);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}else{

		}
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück