001// Copyright 2007, 2008, 2010 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry5.internal.services;
016
017import static org.apache.tapestry5.commons.util.CollectionFactory.newConcurrentMap;
018
019import java.util.Map;
020
021import org.apache.tapestry5.commons.ObjectLocator;
022import org.apache.tapestry5.services.ApplicationStateContribution;
023import org.apache.tapestry5.services.ApplicationStateCreator;
024import org.apache.tapestry5.services.ApplicationStateManager;
025import org.apache.tapestry5.services.ApplicationStatePersistenceStrategy;
026import org.apache.tapestry5.services.ApplicationStatePersistenceStrategySource;
027
028public class ApplicationStateManagerImpl implements ApplicationStateManager
029{
030    static final String DEFAULT_STRATEGY = "session";
031
032    static class ApplicationStateAdapter<T>
033    {
034        private final Class<T> ssoClass;
035
036        private final ApplicationStatePersistenceStrategy strategy;
037
038        private final ApplicationStateCreator<T> creator;
039
040        ApplicationStateAdapter(Class<T> ssoClass, ApplicationStatePersistenceStrategy strategy,
041                ApplicationStateCreator<T> creator)
042        {
043            this.ssoClass = ssoClass;
044            this.strategy = strategy;
045            this.creator = creator;
046        }
047
048        T getOrCreate()
049        {
050            return strategy.get(ssoClass, creator);
051        }
052
053        void set(T sso)
054        {
055            strategy.set(ssoClass, sso);
056        }
057
058        boolean exists()
059        {
060            return strategy.exists(ssoClass);
061        }
062
063        T getIfExists()
064        {
065            return strategy.getIfExists(ssoClass);
066        }
067    }
068
069    /**
070     * The map will be extended periodically as new ASOs, not in the configuration, are encountered.
071     * Thut is is thread
072     * safe.
073     */
074    private final Map<Class, ApplicationStateAdapter> classToAdapter = newConcurrentMap();
075
076    private final ApplicationStatePersistenceStrategySource source;
077
078    private final ObjectLocator locator;
079
080    @SuppressWarnings("unchecked")
081    public ApplicationStateManagerImpl(Map<Class, ApplicationStateContribution> configuration,
082            ApplicationStatePersistenceStrategySource source, ObjectLocator locator)
083    {
084        this.source = source;
085        this.locator = locator;
086
087        for (Class asoClass : configuration.keySet())
088        {
089            ApplicationStateContribution contribution = configuration.get(asoClass);
090
091            ApplicationStateAdapter adapter = newAdapter(asoClass, contribution.getStrategy(),
092                    contribution.getCreator());
093
094            classToAdapter.put(asoClass, adapter);
095        }
096
097    }
098
099    @SuppressWarnings("unchecked")
100    private <T> ApplicationStateAdapter<T> newAdapter(final Class<T> ssoClass, String strategyName,
101            ApplicationStateCreator<T> creator)
102    {
103        if (creator == null)
104        {
105            creator = new ApplicationStateCreator<T>()
106            {
107                public T create()
108                {
109                    return locator.autobuild("Instantiating instance of SSO class "
110                            + ssoClass.getName(), ssoClass);
111                }
112            };
113        }
114
115        ApplicationStatePersistenceStrategy strategy = source.get(strategyName);
116
117        return new ApplicationStateAdapter(ssoClass, strategy, creator);
118    }
119
120    @SuppressWarnings("unchecked")
121    private <T> ApplicationStateAdapter<T> getAdapter(Class<T> ssoClass)
122    {
123        ApplicationStateAdapter<T> result = classToAdapter.get(ssoClass);
124
125        // Not found is completely OK, we'll define it on the fly.
126
127        if (result == null)
128        {
129            result = newAdapter(ssoClass, DEFAULT_STRATEGY, null);
130            classToAdapter.put(ssoClass, result);
131        }
132
133        return result;
134    }
135
136    public <T> T get(Class<T> ssoClass)
137    {
138        return getAdapter(ssoClass).getOrCreate();
139    }
140
141    public <T> T getIfExists(Class<T> ssoClass)
142    {
143        return getAdapter(ssoClass).getIfExists();
144    }
145
146    public <T> void set(Class<T> ssoClass, T sso)
147    {
148        getAdapter(ssoClass).set(sso);
149    }
150
151    public <T> boolean exists(Class<T> ssoClass)
152    {
153        return getAdapter(ssoClass).exists();
154    }
155
156}