Author: pedro
Date: Thu Jun 9 15:50:28 2011
New Revision: 1133952
URL: http://svn.apache.org/viewvc?rev=1133952&view=rev
Log:
removing IObjectStreamFactory & Co and moving the default (de)serialization
code to JavaSerializer
Issue: WICKET-3778
Removed:
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/util/io/ClassStreamHandler.java
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/util/io/IObjectStreamFactory.java
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/util/io/WicketObjectInputStream.java
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/util/io/WicketObjectOutputStream.java
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/util/io/WicketObjectStreamFactory.java
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/util/io/WicketOutputStreamTest.java
Modified:
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/serialize/java/JavaSerializer.java
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/util/lang/WicketObjects.java
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/page/PersistentPageManagerTest.java
Modified:
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/serialize/java/JavaSerializer.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/serialize/java/JavaSerializer.java?rev=1133952&r1=1133951&r2=1133952&view=diff
==============================================================================
---
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/serialize/java/JavaSerializer.java
(original)
+++
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/serialize/java/JavaSerializer.java
Thu Jun 9 15:50:28 2011
@@ -16,19 +16,39 @@
*/
package org.apache.wicket.serialize.java;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.OutputStream;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.ThreadContext;
+import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.application.IClassResolver;
import org.apache.wicket.serialize.ISerializer;
-import org.apache.wicket.util.io.IObjectStreamFactory;
-import org.apache.wicket.util.lang.WicketObjects;
+import org.apache.wicket.settings.IApplicationSettings;
+import org.apache.wicket.util.io.IOUtils;
+import org.apache.wicket.util.io.SerializableChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* An implementation of {@link ISerializer} based on Java Serialization
(ObjectOutputStream,
* ObjectInputStream)
*
+ * Requires the application key to enable serialization and deserialisation
outside thread in which
+ * application thread local is set
+ *
* @see IObjectStreamFactory
*/
public class JavaSerializer implements ISerializer
{
+ private static final Logger log =
LoggerFactory.getLogger(JavaSerializer.class);
/**
* The key of the application which can be used later to find the
proper {@link IClassResolver}
*/
@@ -44,14 +64,189 @@ public class JavaSerializer implements I
this.applicationKey = applicationKey;
}
- public byte[] serialize(final Object page)
+ public byte[] serialize(final Object object)
{
- return WicketObjects.objectToByteArray(page, applicationKey);
+ try
+ {
+ final ByteArrayOutputStream out = new
ByteArrayOutputStream();
+ ObjectOutputStream oos = null;
+ try
+ {
+ oos = new CheckerObjectOutputStream(out);
+ oos.writeObject(applicationKey);
+ oos.writeObject(object);
+ }
+ finally
+ {
+ try
+ {
+ IOUtils.close(oos);
+ }
+ finally
+ {
+ out.close();
+ }
+ }
+ return out.toByteArray();
+ }
+ catch (Exception e)
+ {
+ log.error("Error serializing object " +
object.getClass() + " [object=" + object + "]",
+ e);
+ }
+ return null;
}
public Object deserialize(final byte[] data)
{
- return WicketObjects.byteArrayToObject(data);
+ ThreadContext old = ThreadContext.get(false);
+ try
+ {
+ final ByteArrayInputStream in = new
ByteArrayInputStream(data);
+ ObjectInputStream ois = null;
+ try
+ {
+ ois = new ClassResolverObjectInputStream(in);
+ String applicationName =
(String)ois.readObject();
+ if (applicationName != null &&
!Application.exists())
+ {
+ Application app =
Application.get(applicationName);
+ if (app != null)
+ {
+
ThreadContext.setApplication(app);
+ }
+ }
+ return ois.readObject();
+ }
+ finally
+ {
+ try
+ {
+ IOUtils.close(ois);
+ }
+ finally
+ {
+ in.close();
+ }
+ }
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new RuntimeException("Could not deserialize
object using JavaSerializer", e);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Could not deserialize
object using JavaSerializer", e);
+ }
+ finally
+ {
+ ThreadContext.restore(old);
+ }
}
+ /**
+ * Extend {@link ObjectInputStream} to add framework class resolution
logic.
+ */
+ private static class ClassResolverObjectInputStream extends
ObjectInputStream
+ {
+ public ClassResolverObjectInputStream(InputStream in) throws
IOException
+ {
+ super(in);
+ }
+
+ // This override is required to resolve classes inside in
different bundle, i.e.
+ // The classes can be resolved by OSGI classresolver
implementation
+ @Override
+ protected Class<?> resolveClass(ObjectStreamClass desc) throws
IOException,
+ ClassNotFoundException
+ {
+ String className = desc.getName();
+
+ try
+ {
+ return super.resolveClass(desc);
+ }
+ catch (ClassNotFoundException ex1)
+ {
+ // ignore this exception.
+ log.debug("Class not found by the object
outputstream itself, trying the IClassResolver");
+ }
+
+
+ Class<?> candidate = null;
+ try
+ {
+ // Can the application always be taken??
+ // Should be if serialization happened in
thread with application set
+ // (WICKET-2195)
+ Application application = Application.get();
+ IApplicationSettings applicationSettings =
application.getApplicationSettings();
+ IClassResolver classResolver =
applicationSettings.getClassResolver();
+
+ candidate =
classResolver.resolveClass(className);
+ if (candidate == null)
+ {
+ candidate = super.resolveClass(desc);
+ }
+ }
+ catch (WicketRuntimeException ex)
+ {
+ if (ex.getCause() instanceof
ClassNotFoundException)
+ {
+ throw
(ClassNotFoundException)ex.getCause();
+ }
+ }
+ return candidate;
+ }
+ }
+ /**
+ * Write objects to the wrapped output stream and log a meaningful
message for serialization
+ * problems
+ */
+ private static class CheckerObjectOutputStream extends
ObjectOutputStream
+ {
+ public CheckerObjectOutputStream(OutputStream out) throws
IOException
+ {
+ super(out);
+ }
+
+ @Override
+ protected final void writeObjectOverride(final Object obj)
throws IOException
+ {
+ try
+ {
+ super.writeObject(obj);
+ }
+ catch (IOException e)
+ {
+ if (SerializableChecker.isAvailable())
+ {
+ // trigger serialization again, but
this time gather
+ // some more info
+ new
SerializableChecker((NotSerializableException)e).writeObject(obj);
+ // if we get here, we didn't fail,
while we
+ // should;
+ throw e;
+ }
+ throw e;
+ }
+ catch (RuntimeException e)
+ {
+ log.error("error writing object " + obj + ": "
+ e.getMessage(), e);
+ throw e;
+ }
+ }
+
+ @Override
+ public void flush() throws IOException
+ {
+ super.flush();
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ super.close();
+ }
+ }
}
Modified:
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/util/lang/WicketObjects.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/util/lang/WicketObjects.java?rev=1133952&r1=1133951&r2=1133952&view=diff
==============================================================================
---
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/util/lang/WicketObjects.java
(original)
+++
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/util/lang/WicketObjects.java
Thu Jun 9 15:50:28 2011
@@ -29,14 +29,10 @@ import java.util.HashMap;
import org.apache.wicket.Application;
import org.apache.wicket.Component;
-import org.apache.wicket.ThreadContext;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.application.IClassResolver;
import org.apache.wicket.settings.IApplicationSettings;
import org.apache.wicket.util.io.ByteCountingOutputStream;
-import org.apache.wicket.util.io.IOUtils;
-import org.apache.wicket.util.io.IObjectStreamFactory;
-import
org.apache.wicket.util.io.IObjectStreamFactory.DefaultObjectStreamFactory;
import org.apache.wicket.util.string.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -237,62 +233,6 @@ public class WicketObjects
}
/**
- * De-serializes an object from a byte array.
- *
- * @param data
- * The serialized object
- * @return The object
- */
- public static Object byteArrayToObject(final byte[] data)
- {
- ThreadContext old = ThreadContext.get(false);
- try
- {
- final ByteArrayInputStream in = new
ByteArrayInputStream(data);
- ObjectInputStream ois = null;
- try
- {
- ois =
objectStreamFactory.newObjectInputStream(in);
- String applicationName =
(String)ois.readObject();
- if (applicationName != null &&
!Application.exists())
- {
- Application app =
Application.get(applicationName);
- if (app != null)
- {
-
ThreadContext.setApplication(app);
- }
- }
- return ois.readObject();
- }
- finally
- {
- try
- {
- IOUtils.close(ois);
- }
- finally
- {
- in.close();
- }
- }
- }
- catch (ClassNotFoundException e)
- {
- throw new RuntimeException("Could not deserialize
object using `" +
- objectStreamFactory.getClass().getName() + "`
object factory", e);
- }
- catch (IOException e)
- {
- throw new RuntimeException("Could not deserialize
object using `" +
- objectStreamFactory.getClass().getName() + "`
object factory", e);
- }
- finally
- {
- ThreadContext.restore(old);
- }
- }
-
- /**
* Makes a deep clone of an object by serializing and deserializing it.
The object must be fully
* serializable to be cloned. This method will not clone wicket
Components, it will just reuse
* those instances so that the complete component tree is not copied
over only the model data.
@@ -331,13 +271,6 @@ public class WicketObjects
}
/**
- * The default object stream factory to use. Keep this as a static here
opposed to in
- * Application, as the Application most likely isn't available in the
threads we'll be using
- * this with.
- */
- private static IObjectStreamFactory objectStreamFactory = new
IObjectStreamFactory.DefaultObjectStreamFactory();
-
- /**
* Strategy for calculating sizes of objects. Note: I didn't make this
an application setting as
* we have enough of those already, and the typical way this probably
would be used is that
* install a different one according to the JDK version used, so
varying them between
@@ -452,98 +385,6 @@ public class WicketObjects
}
/**
- * Serializes an object into a byte array.
- *
- * @param object
- * The object
- *
- * @param applicationName
- * The name of application - required when serialization and
deserialisation happen
- * outside thread in which application thread local is set
- *
- * @return The serialized object
- */
- public static byte[] objectToByteArray(final Object object, String
applicationName)
- {
- try
- {
- final ByteArrayOutputStream out = new
ByteArrayOutputStream();
- ObjectOutputStream oos = null;
- try
- {
- oos =
objectStreamFactory.newObjectOutputStream(out);
- oos.writeObject(applicationName);
- oos.writeObject(object);
- }
- finally
- {
- try
- {
- IOUtils.close(oos);
- }
- finally
- {
- out.close();
- }
- }
- return out.toByteArray();
- }
- catch (Exception e)
- {
- log.error("Error serializing object " +
object.getClass() + " [object=" + object + "]",
- e);
- }
- return null;
- }
-
- /**
- * Serializes an object into a byte array.
- *
- * @param object
- * The object
- * @return The serialized object
- */
- public static byte[] objectToByteArray(final Object object)
- {
- try
- {
- final ByteArrayOutputStream out = new
ByteArrayOutputStream();
- ObjectOutputStream oos = null;
- try
- {
- oos =
objectStreamFactory.newObjectOutputStream(out);
- if (Application.exists())
- {
-
oos.writeObject(Application.get().getApplicationKey());
- }
- else
- {
- oos.writeObject(null);
- }
- oos.writeObject(object);
- }
- finally
- {
- try
- {
- IOUtils.close(oos);
- }
- finally
- {
- out.close();
- }
- }
- return out.toByteArray();
- }
- catch (Exception e)
- {
- log.error("Error serializing object " +
object.getClass() + " [object=" + object + "]",
- e);
- }
- return null;
- }
-
- /**
* Sets the strategy for determining the sizes of objects.
*
* @param objectSizeOfStrategy
@@ -563,27 +404,6 @@ public class WicketObjects
}
/**
- * Configure this utility class to use the provided {@link
IObjectStreamFactory} instance.
- *
- * @param objectStreamFactory
- * The factory instance to use. If you pass in null, the
- * {@link DefaultObjectStreamFactory default} will be set
(again). Pass null to reset
- * to the default.
- */
- public static void setObjectStreamFactory(IObjectStreamFactory
objectStreamFactory)
- {
- if (objectStreamFactory == null)
- {
- WicketObjects.objectStreamFactory = new
IObjectStreamFactory.DefaultObjectStreamFactory();
- }
- else
- {
- WicketObjects.objectStreamFactory = objectStreamFactory;
- }
- log.info("using " + WicketObjects.objectStreamFactory + " for
creating object streams");
- }
-
- /**
* Computes the size of an object. Note that this is an estimation,
never an absolute accurate
* size.
*
Modified:
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/page/PersistentPageManagerTest.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/test/java/org/apache/wicket/page/PersistentPageManagerTest.java?rev=1133952&r1=1133951&r2=1133952&view=diff
==============================================================================
---
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/page/PersistentPageManagerTest.java
(original)
+++
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/page/PersistentPageManagerTest.java
Thu Jun 9 15:50:28 2011
@@ -18,7 +18,6 @@ package org.apache.wicket.page;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -31,8 +30,8 @@ import org.apache.wicket.pageStore.IData
import org.apache.wicket.pageStore.IPageStore;
import org.apache.wicket.pageStore.memory.DummyPageManagerContext;
import org.apache.wicket.serialize.java.JavaSerializer;
-import org.apache.wicket.util.lang.WicketObjects;
import org.apache.wicket.versioning.InMemoryPageStore;
+import org.junit.Assert;
import org.junit.Test;
/**
@@ -40,6 +39,8 @@ import org.junit.Test;
*/
public class PersistentPageManagerTest
{
+ private static final String APP_NAME = "test_app";
+
/**
* WICKET-3470
*
@@ -53,7 +54,7 @@ public class PersistentPageManagerTest
public void serializationOutsideWicketLifecyle() throws IOException,
ClassNotFoundException
{
// create IPageManager (with IPageStore) and store a page
instance
- IPageManager pageManager = newPersistentPageManager("test_app");
+ IPageManager pageManager = newPersistentPageManager(APP_NAME);
TestPage toSerializePage = new TestPage();
pageManager.touchPage(toSerializePage);
pageManager.commitRequest();
@@ -65,7 +66,7 @@ public class PersistentPageManagerTest
pageManager.destroy();
// simulate persisting of the http sessions initiated by the
web container
- byte[] serializedSessionEntry =
WicketObjects.objectToByteArray(sessionEntry);
+ byte[] serializedSessionEntry = new
JavaSerializer(APP_NAME).serialize(sessionEntry);
assertNotNull("Wicket needs to be able to serialize the session
entry",
serializedSessionEntry);
@@ -75,11 +76,10 @@ public class PersistentPageManagerTest
serializedSessionEntry));
// WicketFilter is not initialized so there is no Application
available yet
- if (Application.exists())
- {
- System.err.println("==================DEBUG
==========" + Application.get().getName());
- }
- assertNull("Worker thread should be unaware of Wicket
application", in.readObject());
+ Assert.assertFalse("Worker thread should be unaware of Wicket
application",
+ Application.exists());
+
+ assertEquals(APP_NAME, in.readObject());
// without available IPageStore the read SessionEntry holds
// the IManageablePage itself, not SerializedPage
@@ -90,7 +90,7 @@ public class PersistentPageManagerTest
// provide new IPageStore which will read IManageablePage's or
SerializedPage's
// from the SessionEntry's
- IPageManager newPageManager =
newPersistentPageManager("test_app");
+ IPageManager newPageManager =
newPersistentPageManager(APP_NAME);
newPageManager.getContext().setSessionAttribute(null,
loadedSessionEntry);
TestPage deserializedPage =
(TestPage)newPageManager.getPage(toSerializePage.getPageId());