Package org.apache.myfaces.application.viewstate

Source Code of org.apache.myfaces.application.viewstate.SerializedViewCollection

/*
* 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 org.apache.myfaces.application.viewstate;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.context.FacesContext;
import org.apache.commons.collections.map.LRUMap;
import org.apache.myfaces.shared.util.WebConfigParamUtils;
import org.apache.myfaces.spi.ViewScopeProvider;

/**
*
*/
class SerializedViewCollection implements Serializable
{
    private static final Logger log = Logger.getLogger(SerializedViewCollection.class.getName());

    private static final Object[] EMPTY_STATES = new Object[]{null, null};

    private static final long serialVersionUID = -3734849062185115847L;
    private final List<SerializedViewKey> _keys =
        new ArrayList<SerializedViewKey>(
            ServerSideStateCacheImpl.DEFAULT_NUMBER_OF_VIEWS_IN_SESSION);
    private final Map<SerializedViewKey, Object> _serializedViews =
        new HashMap<SerializedViewKey, Object>();
    /**
     * The viewScopeIds can be shared between multiple entries of the same
     * view. To store it into session, the best is use two maps, one to
     * associate the view key with the view scope id and other to keep track
     * of the number of times the id is used. In that way it is possible to
     * know when a view scope id has been discarded and destroy the view scope
     * in the right time.
     */
    private HashMap<SerializedViewKey, String> _viewScopeIds = null;
    private HashMap<String, Integer> _viewScopeIdCounts = null;

    private final Map<SerializedViewKey, SerializedViewKey> _precedence =
        new HashMap<SerializedViewKey, SerializedViewKey>();
    private Map<String, SerializedViewKey> _lastWindowKeys = null;

    public void put(FacesContext context, Object state,
        SerializedViewKey key, SerializedViewKey previousRestoredKey)
    {
        put(context, state, key, previousRestoredKey, null, null);
    }
   
    public synchronized void put(FacesContext context, Object state,
        SerializedViewKey key, SerializedViewKey previousRestoredKey,
        ViewScopeProvider viewScopeProvider, String viewScopeId)
    {
        if (state == null)
        {
            state = EMPTY_STATES;
        }
        else if (state instanceof Object[] &&
            ((Object[])state).length == 2 &&
            ((Object[])state)[0] == null &&
            ((Object[])state)[1] == null)
        {
            // The generated state can be considered zero, set it as null
            // into the map.
            state = null;
        }

        if (_serializedViews.containsKey(key))
        {
            // Update the state, the viewScopeId does not change.
            _serializedViews.put(key, state);
            return;
        }

        Integer maxCount = getNumberOfSequentialViewsInSession(context);
        if (maxCount != null)
        {
            if (previousRestoredKey != null)
            {
                if (!_serializedViews.isEmpty())
                {
                    _precedence.put((SerializedViewKey) key, previousRestoredKey);
                }
                else
                {
                    // Note when the session is invalidated, _serializedViews map is empty,
                    // but we could have a not null previousRestoredKey (the last one before
                    // invalidate the session), so we need to check that condition before
                    // set the precence. In that way, we ensure the precedence map will always
                    // have valid keys.
                    previousRestoredKey = null;
                }
            }
        }
        _serializedViews.put(key, state);
       
        if (viewScopeProvider != null && viewScopeId != null)
        {
            if (_viewScopeIds == null)
            {
                _viewScopeIds = new HashMap<SerializedViewKey, String>();
            }
            _viewScopeIds.put(key, viewScopeId);
            if (_viewScopeIdCounts == null)
            {
                _viewScopeIdCounts = new HashMap<String, Integer>();
            }
            Integer vscount = _viewScopeIdCounts.get(viewScopeId);
            vscount = (vscount == null) ? 1 : vscount + 1;
            _viewScopeIdCounts.put(viewScopeId, vscount);
        }

        while (_keys.remove(key))
        {
            // do nothing
        }
        _keys.add(key);

        if (previousRestoredKey != null && maxCount != null && maxCount > 0)
        {
            int count = 0;
            SerializedViewKey previousKey = (SerializedViewKey) key;
            do
            {
                previousKey = _precedence.get(previousKey);
                count++;
            }
            while (previousKey != null && count < maxCount);

            if (previousKey != null)
            {
                SerializedViewKey keyToRemove = (SerializedViewKey) previousKey;
                // In theory it should be only one key but just to be sure
                // do it in a loop, but in this case if cache old views is on,
                // put on that map.
                do
                {
                    while (_keys.remove(keyToRemove))
                    {
                        // do nothing
                    }

                    _serializedViews.remove(keyToRemove);
                   
                    if (viewScopeProvider != null && _viewScopeIds != null)
                    {
                        String oldViewScopeId = _viewScopeIds.remove(keyToRemove);
                        if (oldViewScopeId != null)
                        {
                            Integer vscount = _viewScopeIdCounts.get(oldViewScopeId);
                            vscount = vscount - 1;
                            if (vscount != null && vscount.intValue() < 1)
                            {
                                _viewScopeIdCounts.remove(oldViewScopeId);
                                viewScopeProvider.destroyViewScopeMap(context, oldViewScopeId);
                            }
                            else
                            {
                                _viewScopeIdCounts.put(oldViewScopeId, vscount);
                            }
                        }
                    }

                    keyToRemove = _precedence.remove(keyToRemove);
                }
                while (keyToRemove != null);
            }
        }
        int views = getNumberOfViewsInSession(context);
        while (_keys.size() > views)
        {
            key = _keys.remove(0);
            if (maxCount != null && maxCount > 0)
            {
                SerializedViewKey keyToRemove = (SerializedViewKey) key;
                // Note in this case the key to delete is the oldest one,
                // so it could be at least one precedence, but to be safe
                // do it with a loop.
                do
                {
                    keyToRemove = _precedence.remove(keyToRemove);
                }
                while (keyToRemove != null);
            }

            _serializedViews.remove(key);
           
            if (viewScopeProvider != null && _viewScopeIds != null)
            {
                String oldViewScopeId = _viewScopeIds.remove(key);
                if (oldViewScopeId != null)
                {
                    Integer vscount = _viewScopeIdCounts.get(oldViewScopeId);
                    vscount = vscount - 1;
                    if (vscount != null && vscount.intValue() < 1)
                    {
                        _viewScopeIdCounts.remove(oldViewScopeId);
                        viewScopeProvider.destroyViewScopeMap(context, oldViewScopeId);
                    }
                    else
                    {
                        _viewScopeIdCounts.put(oldViewScopeId, vscount);
                    }
                }
            }
        }
    }

    protected Integer getNumberOfSequentialViewsInSession(FacesContext context)
    {
        return WebConfigParamUtils.getIntegerInitParameter( context.getExternalContext(),
                ServerSideStateCacheImpl.NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
    }

    /**
     * Reads the amount (default = 20) of views to be stored in session.
     * @see ServerSideStateCacheImpl#NUMBER_OF_VIEWS_IN_SESSION_PARAM
     * @param context FacesContext for the current request, we are processing
     * @return Number vf views stored in the session
     */
    protected int getNumberOfViewsInSession(FacesContext context)
    {
        String value = context.getExternalContext().getInitParameter(
                ServerSideStateCacheImpl.NUMBER_OF_VIEWS_IN_SESSION_PARAM);
        int views = ServerSideStateCacheImpl.DEFAULT_NUMBER_OF_VIEWS_IN_SESSION;
        if (value != null)
        {
            try
            {
                views = Integer.parseInt(value);
                if (views <= 0)
                {
                    log.severe("Configured value for " + ServerSideStateCacheImpl.NUMBER_OF_VIEWS_IN_SESSION_PARAM
                              + " is not valid, must be an value > 0, using default value ("
                              + ServerSideStateCacheImpl.DEFAULT_NUMBER_OF_VIEWS_IN_SESSION);
                    views = ServerSideStateCacheImpl.DEFAULT_NUMBER_OF_VIEWS_IN_SESSION;
                }
            }
            catch (Throwable e)
            {
                log.log( Level.SEVERE, "Error determining the value for "
                       + ServerSideStateCacheImpl.NUMBER_OF_VIEWS_IN_SESSION_PARAM
                       + ", expected an integer value > 0, using default value ("
                       + ServerSideStateCacheImpl.DEFAULT_NUMBER_OF_VIEWS_IN_SESSION + "): " + e.getMessage(), e);
            }
        }
        return views;
    }

    public synchronized void putLastWindowKey(FacesContext context, String id, SerializedViewKey key)
    {
        if (_lastWindowKeys == null)
        {
            Integer i = getNumberOfSequentialViewsInSession(context);
            int j = getNumberOfViewsInSession(context);
            if (i != null && i.intValue() > 0)
            {
                _lastWindowKeys = new LRUMap((j / i.intValue()) + 1);
            }
            else
            {
                _lastWindowKeys = new LRUMap(j + 1);
            }
        }
        _lastWindowKeys.put(id, key);
    }

    public SerializedViewKey getLastWindowKey(FacesContext context, String id)
    {
        if (_lastWindowKeys != null)
        {
            return _lastWindowKeys.get(id);
        }
        return null;
    }

    public Object get(SerializedViewKey key)
    {
        Object value = _serializedViews.get(key);
        if (value == null)
        {
            if (_serializedViews.containsKey(key))
            {
                return EMPTY_STATES;
            }
        }
        else if (value instanceof Object[] &&
            ((Object[])value).length == 2 &&
            ((Object[])value)[0] == null &&
            ((Object[])value)[1] == null)
        {
            // Remember inside the state map null is stored as an empty array.
            return null;
        }
        return value;
    }
}
TOP

Related Classes of org.apache.myfaces.application.viewstate.SerializedViewCollection

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.