Author: ehillenius
Date: Wed Feb 7 23:13:43 2007
New Revision: 504808
URL: http://svn.apache.org/viewvc?view=rev&rev=504808
Log:
WICKET-265
Added:
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/util/io/DebuggingObjectOutputStream.java
Modified:
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/protocol/http/FilePageStore.java
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/protocol/http/HttpSessionStore.java
Modified:
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/protocol/http/FilePageStore.java
URL:
http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/protocol/http/FilePageStore.java?view=diff&rev=504808&r1=504807&r2=504808
==============================================================================
---
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/protocol/http/FilePageStore.java
(original)
+++
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/protocol/http/FilePageStore.java
Wed Feb 7 23:13:43 2007
@@ -30,8 +30,10 @@
import wicket.Application;
import wicket.Page;
+import wicket.WicketRuntimeException;
import wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore;
import wicket.util.concurrent.ConcurrentHashMap;
+import wicket.util.io.DebuggingObjectOutputStream;
import wicket.util.lang.Objects;
/**
@@ -49,9 +51,9 @@
protected static Log log = LogFactory.getLog(FilePageStore.class);
private final File defaultWorkDir;
-
+
private final ConcurrentHashMap storePageMap;
-
+
private final PageSavingThread thread;
private final String appName;
@@ -61,13 +63,15 @@
*/
public FilePageStore()
{
-
this((File)((WebApplication)Application.get()).getServletContext()
- .getAttribute("javax.servlet.context.tempdir"));
+
this((File)((WebApplication)Application.get()).getServletContext().getAttribute(
+ "javax.servlet.context.tempdir"));
}
/**
* Construct.
- * @param dir The directory to save to.
+ *
+ * @param dir
+ * The directory to save to.
*/
public FilePageStore(File dir)
{
@@ -75,10 +79,10 @@
storePageMap = new ConcurrentHashMap();
thread = new PageSavingThread();
appName = Application.get().getApplicationKey();
- Thread t = new Thread(thread,"FilePageStoreThread-" +appName);
+ Thread t = new Thread(thread, "FilePageStoreThread-" + appName);
t.setDaemon(true);
t.start();
-
+
}
/**
@@ -118,9 +122,11 @@
if (page != null &&
log.isDebugEnabled())
{
long t3 =
System.currentTimeMillis();
- log.debug("restoring page " +
page.getClass() + "[" + page.getNumericId() + ","
- +
page.getCurrentVersionNumber() + "] size: " + pageData.length + " for session
" + sessionId + " took "
- + (t2 - t1) + "
miliseconds to read in and " + (t3-t2) + " miliseconds to deserialize");
+ log.debug("restoring page " +
page.getClass() + "[" + page.getNumericId()
+ + "," +
page.getCurrentVersionNumber() + "] size: "
+ +
pageData.length + " for session " + sessionId + " took "
+ + (t2 - t1) + "
miliseconds to read in and " + (t3 - t2)
+ + " miliseconds
to deserialize");
}
return page;
@@ -157,7 +163,8 @@
{
synchronized (storePageMap)
{
- storePageMap.put(new
SessionPageKey(sessionId,page.getNumericId(),page.getCurrentVersionNumber(),true),
page);
+ storePageMap.put(new SessionPageKey(sessionId,
page.getNumericId(), page
+ .getCurrentVersionNumber(), true),
page);
storePageMap.notifyAll();
}
}
@@ -170,13 +177,15 @@
{
synchronized (storePageMap)
{
- storePageMap.put(new
SessionPageKey(sessionId,page.getNumericId(),page.getCurrentVersionNumber()),
page);
+ storePageMap.put(new SessionPageKey(sessionId,
page.getNumericId(), page
+ .getCurrentVersionNumber()), page);
storePageMap.notifyAll();
}
}
/**
- * @see
wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore#pageAccessed(java.lang.String,
wicket.Page)
+ * @see
wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore#pageAccessed(java.lang.String,
+ * wicket.Page)
*/
public void pageAccessed(String sessionId, Page page)
{
@@ -192,24 +201,26 @@
thread.stop();
}
- private void testMap(String sessionId, int id , int versionNumber)
+ private void testMap(String sessionId, int id, int versionNumber)
{
- SessionPageKey curentKey = new
SessionPageKey(sessionId,id,versionNumber);
+ SessionPageKey curentKey = new SessionPageKey(sessionId, id,
versionNumber);
Object key = storePageMap.get(curentKey);
while (key != null)
{
- if( log.isDebugEnabled())
+ if (log.isDebugEnabled())
{
- log.debug("The page " + id + ":" +
versionNumber+" for session " + sessionId +
- " wasn't saved yet. blocking
for 200ms");
+ log.debug("The page " + id + ":" +
versionNumber + " for session " + sessionId
+ + " wasn't saved yet. blocking
for 200ms");
}
synchronized (key)
{
try
{
// for now i just wait 200ms and then
try again.
- // i could use synchronized() and then
notifyAll in the saving thread.
- // But maybe it is really busy and we
should just block for 200ms
+ // i could use synchronized() and then
notifyAll in the
+ // saving thread.
+ // But maybe it is really busy and we
should just block for
+ // 200ms
key.wait(200);
}
catch (InterruptedException ex)
@@ -229,7 +240,7 @@
{
synchronized (storePageMap)
{
- SessionPageKey key = new
SessionPageKey(sessionId,-1,-1,true);
+ SessionPageKey key = new SessionPageKey(sessionId, -1,
-1, true);
storePageMap.put(key, key);
storePageMap.notifyAll();
}
@@ -255,8 +266,7 @@
*/
private File getPageFile(int id, int versionNumber, File sessionDir)
{
- return new File(sessionDir, appName + "-page-" + id
- + "-version-" + versionNumber);
+ return new File(sessionDir, appName + "-page-" + id +
"-version-" + versionNumber);
}
private class SessionPageKey
@@ -270,7 +280,7 @@
{
this(sessionId, id, versionNumber, false);
}
-
+
SessionPageKey(String sessionId, int id, int versionNumber,
boolean remove)
{
this.sessionId = sessionId;
@@ -278,7 +288,7 @@
this.versionNumber = versionNumber;
this.remove = remove;
}
-
+
/**
* @see java.lang.Object#hashCode()
*/
@@ -286,7 +296,7 @@
{
return sessionId.hashCode() + id + versionNumber;
}
-
+
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@@ -295,17 +305,17 @@
if (obj instanceof SessionPageKey)
{
SessionPageKey key = (SessionPageKey)obj;
- return id == key.id && versionNumber ==
key.versionNumber &&
- sessionId.equals(key.sessionId) &&
remove == key.remove;
+ return id == key.id && versionNumber ==
key.versionNumber
+ &&
sessionId.equals(key.sessionId) && remove == key.remove;
}
return false;
}
}
-
+
private class PageSavingThread implements Runnable
{
private volatile boolean stop = false;
-
+
/**
* Stops this thread.
*/
@@ -317,12 +327,13 @@
storePageMap.notifyAll();
}
}
+
/**
* @see java.lang.Runnable#run()
*/
public void run()
{
- while(!stop)
+ while (!stop)
{
Iterator iterator = null;
try
@@ -332,29 +343,33 @@
{
synchronized (storePageMap)
{
- if(stop) return;
+ if (stop)
+ return;
storePageMap.wait();
}
continue;
}
- while(iterator.hasNext())
+ while (iterator.hasNext())
{
SessionPageKey key =
(SessionPageKey)iterator.next();
Object value =
storePageMap.get(key);
- if (value == null) continue;
- if(key.remove)
+ if (value == null)
+ continue;
+ if (key.remove)
{
if (key.id == -1)
{
removeSession(key.sessionId);
- // now remove
any other pending save for that page.
+ // now remove
any other pending save for that
+ // page.
removeSessionFromPendingMap(key.sessionId);
}
else
{
removePage(key.sessionId, key.id, key.versionNumber);
- // now remove
any other pending save for that page.
-
removePageFromPendingMap(key.sessionId,key.id);
+ // now remove
any other pending save for that
+ // page.
+
removePageFromPendingMap(key.sessionId, key.id);
}
}
else
@@ -363,16 +378,17 @@
}
iterator.remove();
}
- }
+ }
catch (Exception e)
{
log.error("Error in page save thread",
e);
// removing the one that did fail...
- if(iterator != null) iterator.remove();
+ if (iterator != null)
+ iterator.remove();
}
}
}
-
+
/**
* @param sessionId
* @param id
@@ -380,10 +396,10 @@
private void removePageFromPendingMap(String sessionId, int id)
{
Iterator iterator = storePageMap.keySet().iterator();
- while(iterator.hasNext())
+ while (iterator.hasNext())
{
SessionPageKey key =
(SessionPageKey)iterator.next();
- if(key.sessionId == sessionId && key.id == id)
+ if (key.sessionId == sessionId && key.id == id)
{
iterator.remove();
}
@@ -393,23 +409,24 @@
private void removeSessionFromPendingMap(String sessionId)
{
Iterator iterator = storePageMap.keySet().iterator();
- while(iterator.hasNext())
+ while (iterator.hasNext())
{
SessionPageKey key =
(SessionPageKey)iterator.next();
- if(key.sessionId == sessionId)
+ if (key.sessionId == sessionId)
{
iterator.remove();
}
}
}
+
private void removePage(String sessionId, int id, int
currentVersionNumber)
{
File sessionDir = new File(getWorkDir(), sessionId);
if (sessionDir.exists())
{
- while(currentVersionNumber >= 0)
+ while (currentVersionNumber >= 0)
{
- File pageFile =
getPageFile(id,currentVersionNumber,sessionDir);
+ File pageFile = getPageFile(id,
currentVersionNumber, sessionDir);
if (pageFile.exists())
{
pageFile.delete();
@@ -419,7 +436,7 @@
}
}
-
+
private void removeSession(String sessionId)
{
File sessionDir = new File(getWorkDir(), sessionId);
@@ -439,7 +456,7 @@
}
}
}
-
+
/**
* @param sessionId
* @param page
@@ -448,7 +465,8 @@
{
File sessionDir = new File(getWorkDir(), sessionId);
sessionDir.mkdirs();
- File pageFile = getPageFile(page.getNumericId(),
page.getCurrentVersionNumber(), sessionDir);
+ File pageFile = getPageFile(page.getNumericId(),
page.getCurrentVersionNumber(),
+ sessionDir);
FileOutputStream fos = null;
long t1 = System.currentTimeMillis();
@@ -474,8 +492,17 @@
}
catch (Exception e)
{
- log.error("Error saving page " +
page.getClass() + "["+ page.getId() + "," + page.getCurrentVersionNumber()
- + "] for the sessionid " +
sessionId, e);
+ // trigger serialization again, but this time
gather some more info
+ try
+ {
+ new
DebuggingObjectOutputStream().writeObject(page);
+ }
+ catch (Exception e1)
+ {
+ log.error("Error saving page " +
page.getClass() + "[" + page.getId() + ","
+ +
page.getCurrentVersionNumber() + "] for the sessionid " + sessionId
+ + ": " +
e1.getMessage(), e1);
+ }
}
finally
{
@@ -494,9 +521,10 @@
if (log.isDebugEnabled())
{
long t3 = System.currentTimeMillis();
- log.debug("storing page " + page.getClass() +
"["+ page.getNumericId() + ","
- +
page.getCurrentVersionNumber() + "] size: " + length + " for session " +
sessionId + " took "
- + (t2 - t1) + " miliseconds to
serialize and " + (t3-t2) + " miliseconds to save");
+ log.debug("storing page " + page.getClass() +
"[" + page.getNumericId() + ","
+ +
page.getCurrentVersionNumber() + "] size: " + length + " for session "
+ + sessionId + " took " + (t2 -
t1) + " miliseconds to serialize and "
+ + (t3 - t2) + " miliseconds to
save");
}
}
}
Modified:
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/protocol/http/HttpSessionStore.java
URL:
http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/protocol/http/HttpSessionStore.java?view=diff&rev=504808&r1=504807&r2=504808
==============================================================================
---
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/protocol/http/HttpSessionStore.java
(original)
+++
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/protocol/http/HttpSessionStore.java
Wed Feb 7 23:13:43 2007
@@ -17,6 +17,7 @@
package wicket.protocol.http;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
@@ -30,6 +31,7 @@
import wicket.Request;
import wicket.Session;
import wicket.WicketRuntimeException;
+import wicket.util.io.DebuggingObjectOutputStream;
import wicket.util.lang.Bytes;
/**
@@ -139,9 +141,20 @@
}
catch (Exception e)
{
+ // trigger serialization again, but this time
gather some more info
+ try
+ {
+ new
DebuggingObjectOutputStream().writeObject(value);
+ }
+ catch (IOException e1)
+ {
+ throw new RuntimeException(e1);
+ }
+ // this should never happen
throw new WicketRuntimeException(
- "Internal error cloning object.
Make sure all dependent objects implement Serializable. Class="
- + valueTypeName
+ ",attribute=" + name + ", value=" + value, e);
+ "first pass of serialization
failed, but the second one "
+ + "(that should
gather extended information) passed? Please "
+ + "report this
error to the Wicket team", e);
}
}
Added:
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/util/io/DebuggingObjectOutputStream.java
URL:
http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/util/io/DebuggingObjectOutputStream.java?view=auto&rev=504808
==============================================================================
---
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/util/io/DebuggingObjectOutputStream.java
(added)
+++
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/util/io/DebuggingObjectOutputStream.java
Wed Feb 7 23:13:43 2007
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package wicket.util.io;
+
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.HashSet;
+import java.util.LinkedList;
+
+import wicket.Component;
+import wicket.WicketRuntimeException;
+
+/**
+ * Captures information about what it is trying to stream with the sole purpose
+ * of finding out what the object hierarchy looks like of an object that can't
+ * be serialized.
+ * <p>
+ * If you have an object you want to analyze for this, call:
+ * <code>new DebuggingObjectOutputStream().writeObject(value);</code> and
+ * catch the [EMAIL PROTECTED] WicketRuntimeException}.
+ * </p>
+ * <p>
+ * There's no point using this class if you are not trying to diagnose a
+ * serialization issue.
+ * </p>
+ *
+ * @author Al Maw
+ */
+public class DebuggingObjectOutputStream extends ObjectOutputStream
+{
+ private static final long serialVersionUID = 1L;
+
+ /** stack for string representations of objects that are handled. */
+ private final LinkedList stack = new LinkedList();
+
+ /** set for checking circular references. */
+ private final HashSet set = new HashSet();
+
+ /**
+ * Creates an ObjectOutputStream. Doesn't write anywhere
+ *
+ * @throws IOException
+ * IOException if an I/O error occurs while writing stream
+ * header
+ */
+ public DebuggingObjectOutputStream() throws IOException
+ {
+ super();
+ }
+
+ /**
+ * Dump with identation.
+ *
+ * @param type
+ * the type that couldn't be serialized
+ * @return A very pretty dump
+ */
+ private String getPrettyPrintedStack(String type)
+ {
+ set.clear();
+ StringBuffer result = new StringBuffer();
+ StringBuffer spaces = new StringBuffer();
+ result.append("Unable to serialize class: ");
+ result.append(type);
+ result.append("\nField hierarchy is:");
+ while (!stack.isEmpty())
+ {
+ spaces.append(" ");
+
result.append("\n").append(spaces).append(stack.removeFirst());
+ }
+ result.append(" <----- field that is not serializable");
+ return result.toString();
+ }
+
+ /**
+ * @see java.io.ObjectOutputStream#writeObjectOverride(java.lang.Object)
+ * @throws IOException
+ * never actually happens
+ * @throws WicketRuntimeException
+ * on a serialization exception
+ */
+ protected final void writeObjectOverride(Object obj) throws IOException
+ {
+ if (obj == null)
+ {
+ return;
+ }
+ // Check for circular reference.
+ if (set.contains(obj))
+ {
+ return;
+ }
+ if (stack.isEmpty())
+ {
+ stack.add("Class " + obj.getClass().getName());
+ }
+ set.add(obj);
+ Field[] fields = obj.getClass().getDeclaredFields();
+ for (int i = 0; i < fields.length; i++)
+ {
+ fields[i].setAccessible(true);
+ StringBuffer buffer = new StringBuffer();
+ Field f = fields[i];
+ int m = f.getModifiers();
+ if (fields[i].getType().isPrimitive() ||
Modifier.isTransient(m)
+ || Modifier.isStatic(m))
+ {
+ continue;
+ }
+
+ if (Modifier.isPrivate(m))
+ {
+ buffer.append("private ");
+ }
+ if (Modifier.isProtected(m))
+ {
+ buffer.append("protected ");
+ }
+ if (Modifier.isPublic(m))
+ {
+ buffer.append("public ");
+ }
+ if (Modifier.isAbstract(m))
+ {
+ buffer.append("abstract ");
+ }
+ if (Modifier.isFinal(m))
+ {
+ buffer.append("final ");
+ }
+ if (Modifier.isStatic(m))
+ {
+ buffer.append("static ");
+ }
+ if (Modifier.isVolatile(m))
+ {
+ buffer.append("volatile ");
+ }
+ buffer.append(f.getType().getName()).append("");
+ buffer.append(" ").append(f.getName()).append(" => ");
+
+ // now that we have the reference, try to get the
actual value
+ try
+ {
+ Object val = f.get(obj);
+ if (val != null)
+ {
+ buffer.append(val.getClass().getName());
+ if (val instanceof Component)
+ {
+ buffer.append("
[path=").append(((Component)val).getPath()).append("]");
+ }
+ }
+ else
+ {
+ buffer.append(" null");
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ buffer.append("?
(").append(e.getMessage()).append(")");
+ }
+ catch (IllegalAccessException e)
+ {
+ buffer.append("?
(").append(e.getMessage()).append(")");
+ }
+
+ stack.add(buffer.toString());
+ if
(Serializable.class.isAssignableFrom(fields[i].getType()))
+ {
+ try
+ {
+ writeObjectOverride(fields[i].get(obj));
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new
WicketRuntimeException(getPrettyPrintedStack(fields[i].getType()
+ .getName()), e);
+ }
+ }
+ else
+ {
+ throw new
WicketRuntimeException(getPrettyPrintedStack(
+
fields[i].getType().getName()).toString(), new NotSerializableException(
+ fields[i].getType().getName()));
+ }
+ stack.removeLast();
+ }
+ if (stack.size() == 1)
+ {
+ set.clear();
+ stack.removeLast();
+ }
+ }
+}
\ No newline at end of file