How to disable serialization in Wicket 1.5?

I want to disable serialization in my Wicket app and save all page / session information in RAM. There are very few users in my application (usually 1); I do not need to deploy a cluster; and I need to cache some non-serializable data between requests.

Is there a way that Wicket will not automatically attempt to serialize my pages / session? I tried using the HttpSessionDataStore in https://cwiki.apache.org/confluence/display/WICKET/Page+Storage , but that did not affect it. I still get stack traces:

SEVERE: Error serializing object class com.prosc.safetynet.Administer [object=[Page class = com.prosc.safetynet.Administer, id = 0, render count = 1]]
org.apache.wicket.util.io.SerializableChecker$WicketNotSerializableException: Unable to serialize class: com.prosc.safetynet.SafetyNetSession$1
Field hierarchy is:
  0 [class=com.prosc.safetynet.Administer, path=0]
    java.lang.Object org.apache.wicket.Component.data [class=org.apache.wicket.model.CompoundPropertyModel]
      private java.lang.Object org.apache.wicket.model.CompoundPropertyModel.target [class=com.prosc.safetynet.SafetyNetSession$2]
        final com.prosc.safetynet.SafetyNetSession com.prosc.safetynet.SafetyNetSession$2.this$0 [class=com.prosc.safetynet.SafetyNetSession]
          private java.lang.Object com.prosc.safetynet.SafetyNetSession.tryAndSerializeMeBitch [class=com.prosc.safetynet.SafetyNetSession$1] <----- field that is not serializable
    at org.apache.wicket.util.io.SerializableChecker.internalCheck(SerializableChecker.java:395)
    at org.apache.wicket.util.io.SerializableChecker.check(SerializableChecker.java:374)
    at org.apache.wicket.util.io.SerializableChecker.checkFields(SerializableChecker.java:655)
    at org.apache.wicket.util.io.SerializableChecker.internalCheck(SerializableChecker.java:578)
    at org.apache.wicket.util.io.SerializableChecker.check(SerializableChecker.java:374)
    at org.apache.wicket.util.io.SerializableChecker.checkFields(SerializableChecker.java:655)
    at org.apache.wicket.util.io.SerializableChecker.internalCheck(SerializableChecker.java:578)
    at org.apache.wicket.util.io.SerializableChecker.check(SerializableChecker.java:374)
    at org.apache.wicket.util.io.SerializableChecker.checkFields(SerializableChecker.java:655)
    at org.apache.wicket.util.io.SerializableChecker.internalCheck(SerializableChecker.java:578)
    at org.apache.wicket.util.io.SerializableChecker.check(SerializableChecker.java:374)
    at org.apache.wicket.util.io.SerializableChecker.checkFields(SerializableChecker.java:655)
    at org.apache.wicket.util.io.SerializableChecker.internalCheck(SerializableChecker.java:578)
    at org.apache.wicket.util.io.SerializableChecker.check(SerializableChecker.java:374)
    at org.apache.wicket.util.io.SerializableChecker.writeObjectOverride(SerializableChecker.java:724)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
    at org.apache.wicket.serialize.java.JavaSerializer$CheckerObjectOutputStream.writeObjectOverride(JavaSerializer.java:258)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
    at org.apache.wicket.serialize.java.JavaSerializer.serialize(JavaSerializer.java:77)
    at org.apache.wicket.pageStore.DefaultPageStore.serializePage(DefaultPageStore.java:368)
    at org.apache.wicket.pageStore.DefaultPageStore.storePage(DefaultPageStore.java:146)
    at org.apache.wicket.page.PageStoreManager$PersistentRequestAdapter.storeTouchedPages(PageStoreManager.java:383)
    at org.apache.wicket.page.RequestAdapter.commitRequest(RequestAdapter.java:171)
    at org.apache.wicket.page.AbstractPageManager.commitRequest(AbstractPageManager.java:94)
    at org.apache.wicket.page.PageManagerDecorator.commitRequest(PageManagerDecorator.java:68)
    at org.apache.wicket.page.PageAccessSynchronizer$2.commitRequest(PageAccessSynchronizer.java:281)
    at org.apache.wicket.Application$2.onDetach(Application.java:1598)
    at org.apache.wicket.request.cycle.RequestCycleListenerCollection$3.notify(RequestCycleListenerCollection.java:99)
    at org.apache.wicket.request.cycle.RequestCycleListenerCollection$3.notify(RequestCycleListenerCollection.java:97)
    at org.apache.wicket.util.listener.ListenerCollection$1.notify(ListenerCollection.java:119)
    at org.apache.wicket.util.listener.ListenerCollection.reversedNotify(ListenerCollection.java:143)
    at org.apache.wicket.util.listener.ListenerCollection.reversedNotifyIgnoringExceptions(ListenerCollection.java:113)
    at org.apache.wicket.request.cycle.RequestCycleListenerCollection.onDetach(RequestCycleListenerCollection.java:95)
    at org.apache.wicket.request.cycle.RequestCycle.onDetach(RequestCycle.java:603)
    at org.apache.wicket.request.cycle.RequestCycle.detach(RequestCycle.java:542)
    at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:287)
    at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:188)
    at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:244)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:210)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:174)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:151)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:870)
    at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
    at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
    at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
    at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:685)
    at java.lang.Thread.run(Thread.java:680)
+5
source share
4 answers

IPageStore, .

+5

- Wicket, , , Http Session Serializable ( , , node). -, Serializable , , . , - , (, , , , Wicket ).

, , /, , .

, ? :

public class SessionCache {
    private static final Map<String, Map<String, Object>> CACHE = Collections.synchronizedMap(new HashMap<String, Map<String, Object>>());

    public static Object getAttribute(String sessionId, String attribName) {
        Map<String, Object> attribs = CACHE.get(sessionId);
        if (attribs != null) {
            synchronized(attribs) {
                return attribs.get(attribName);
            }
        }

        return null;
    }

    public static void setAttribute(String sessionId, String attribName, Object attribValue) {
        Map<String, Object> attribs = CACHE.get(sessionId);
        if (attribs == null) {
            attribs = new HashMap<String, Object>();
            CACHE.put(sessionId, attribs);
        }

        synchronized(attribs) {
            attribs.put(attribName, attribValue);
        }
    }

    public static void destroySession(String sessionId) {
        CACHE.remove(sessionId);
    }

    public static void createSession(String sessionId, boolean force) {
        if (force || ! CACHE.containsKey(sessionId)) {
            CACHE.put(sessionId, new HashMap<String, Object>());
        }
    }
}

, Wicket, . . , , registerUnboundListener() HttpSessionStore.

+1

, , svenmeier. , 100% , :

package com.prosc.wicket;

import org.apache.wicket.Application;
import org.apache.wicket.DefaultPageManagerProvider;
import org.apache.wicket.page.IManageablePage;
import org.apache.wicket.page.IPageManagerContext;
import org.apache.wicket.pageStore.IDataStore;
import org.apache.wicket.pageStore.IPageStore;
import org.apache.wicket.pageStore.memory.HttpSessionDataStore;
import org.apache.wicket.pageStore.memory.PageNumberEvictionStrategy;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * This class disables Wicket serialization behavior, while still retaining session and page data in memory (so back button will work).
 * This will run out of memory under heavy load; but it very convenient for low volume web applications.
 * To disable serialization in your application, call this code:
 * <pre>
 *     setPageManagerProvider( new NoSerializePageManagerProvider( this, getPageManagerContext() ) );
 * </pre>
 */
public class NoSerializePageManagerProvider extends DefaultPageManagerProvider {
    private IPageManagerContext pageManagerContext;

    public NoSerializePageManagerProvider( Application application, IPageManagerContext pageManagerContext ) {
        super( application );
        this.pageManagerContext = pageManagerContext;
    }

    @Override
    protected IDataStore newDataStore() {
        return new HttpSessionDataStore( pageManagerContext, new PageNumberEvictionStrategy( 20 ) );
    }

    @Override
    protected IPageStore newPageStore( IDataStore dataStore ) {
        return new IPageStore() {
            Map<String,Map<Integer,IManageablePage>> cache = new HashMap<String, Map<Integer, IManageablePage>>();

            public void destroy() {
                cache = null;
            }

            public IManageablePage getPage( String sessionId, int pageId ) {
                Map<Integer, IManageablePage> sessionCache = getSessionCache( sessionId, false );
                IManageablePage page = sessionCache.get( pageId );
                if( page == null ) {
                    throw new IllegalArgumentException( "Found this session, but there is no page with id " + pageId );
                }
                return page;
            }

            public void removePage( String sessionId, int pageId ) {
                getSessionCache( sessionId, false ).remove( pageId );
            }

            public void storePage( String sessionId, IManageablePage page ) {
                getSessionCache( sessionId, true ).put( page.getPageId(), page );
            }

            public void unbind( String sessionId ) {
                cache.remove( sessionId );
            }

            public Serializable prepareForSerialization( String sessionId, Object page ) {
                return null;
            }

            public Object restoreAfterSerialization( Serializable serializable ) {
                return null;
            }

            public IManageablePage convertToPage( Object page ) {
                return (IManageablePage)page;
            }

            private Map<Integer, IManageablePage> getSessionCache( String sessionId, boolean create ) {
                Map<Integer, IManageablePage> sessionCache = cache.get( sessionId );
                if( sessionCache == null ) {
                    if( create ) {
                        sessionCache = new HashMap<Integer, IManageablePage>();
                        cache.put( sessionId, sessionCache );
                    } else {
                        throw new IllegalArgumentException( "There are no pages stored for session id " + sessionId );
                    }
                }
                return sessionCache;
            }
        };
    }
}
+1

I want to improve Jesse's answer. The following is a thread-safe implementation of IPageStore with an internal least-recently inserted cache (no more than 5 recently viewed pages are stored with state-saving per session):

public class CustomPageStore implements IPageStore {

private static final Logger logger = LoggerFactory.getLogger(CustomPageStore.class);

private static final int MEDIAN_OF_NUMBER_OF_SESSIONS = 6000;

private ConcurrentMap<String, CustomLinkedHashMap<Integer, IManageablePage>> cache = new ConcurrentHashMap<>(MEDIAN_OF_NUMBER_OF_SESSIONS);

@Override
public void destroy() {
    cache.clear();
}

@Override
public IManageablePage getPage(final String sessionId, int pageId) {
    final Map<Integer, IManageablePage> sessionCache = getSessionCache(sessionId);
    final RequestCycle requestCycle = RequestCycle.get();
    if (sessionCache == null) {
        logger.warn("Missing cache. SessionId: {}, pageId: {}, URL: {}", sessionId, pageId, requestCycle == null ? StringUtils.EMPTY : requestCycle.getRequest().getUrl());
        return null;
    }

    final IManageablePage page;
    //noinspection SynchronizationOnLocalVariableOrMethodParameter
    synchronized (sessionCache) {
        page = sessionCache.get(pageId);
    }

    if (page == null && logger.isDebugEnabled()) {
        logger.debug("Missed page. SessionId: {}, pageId: {}, URL: {}", sessionId, pageId, requestCycle == null ? StringUtils.EMPTY : requestCycle.getRequest().getUrl());
    }

    return page;
}

@Override
public void removePage(final String sessionId, int pageId) {
    final Map<Integer, IManageablePage> sessionCache = getSessionCache(sessionId);
    if (sessionCache != null) {
        //noinspection SynchronizationOnLocalVariableOrMethodParameter
        synchronized (sessionCache) {
            sessionCache.remove(pageId);
        }
    }
}

@Override
public void storePage(final String sessionId, IManageablePage page) {
    final LinkedHashMap<Integer, IManageablePage> sessionCache = getOrCreateSessionCache(sessionId);
    final int pageId = page.getPageId();
    //noinspection SynchronizationOnLocalVariableOrMethodParameter
    synchronized (sessionCache) {
        if (sessionCache.containsKey(pageId)) {
            // do this to change insertion order and update least inserted entry
            sessionCache.remove(pageId);
            sessionCache.put(pageId, page);
        } else {
            sessionCache.put(pageId, page);
        }
    }
}

@Override
public void unbind(final String sessionId) {
    cache.remove(sessionId);
}

@Override
public Serializable prepareForSerialization(String sessionId, Object page) {
    return null;
}

@Override
public Object restoreAfterSerialization(Serializable serializable) {
    return null;
}

@Override
public IManageablePage convertToPage(final Object page) {
    return (IManageablePage) page;
}

@Nullable
private Map<Integer, IManageablePage> getSessionCache(final String sessionId) {
    return cache.get(sessionId);
}

@Nonnull
private CustomLinkedHashMap<Integer, IManageablePage> getOrCreateSessionCache(final String sessionId) {
    return cache.computeIfAbsent(sessionId, s -> new CustomLinkedHashMap<>());
}

/** Mimics "least recently inserted" cache */
private static class CustomLinkedHashMap<K, V> extends LinkedHashMap<K, V> {

    /** use this parameter to control memory consumption and frequency of appearance of PageExpiredException */
    private static final int MAX_PAGES_PER_SESSION = 5;

    @Override
    protected boolean removeEldestEntry(final Map.Entry<K, V> eldest) {
        return size() > MAX_PAGES_PER_SESSION;
    }
}
}
+1
source

All Articles