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.ioc.internal.util.CollectionFactory.newConcurrentMap;
018
019import java.util.Map;
020
021import org.apache.tapestry5.ioc.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
064    /**
065     * The map will be extended periodically as new ASOs, not in the configuration, are encountered.
066     * Thut is is thread
067     * safe.
068     */
069    private final Map<Class, ApplicationStateAdapter> classToAdapter = newConcurrentMap();
070
071    private final ApplicationStatePersistenceStrategySource source;
072
073    private final ObjectLocator locator;
074
075    @SuppressWarnings("unchecked")
076    public ApplicationStateManagerImpl(Map<Class, ApplicationStateContribution> configuration,
077            ApplicationStatePersistenceStrategySource source, ObjectLocator locator)
078    {
079        this.source = source;
080        this.locator = locator;
081
082        for (Class asoClass : configuration.keySet())
083        {
084            ApplicationStateContribution contribution = configuration.get(asoClass);
085
086            ApplicationStateAdapter adapter = newAdapter(asoClass, contribution.getStrategy(),
087                    contribution.getCreator());
088
089            classToAdapter.put(asoClass, adapter);
090        }
091
092    }
093
094    @SuppressWarnings("unchecked")
095    private <T> ApplicationStateAdapter<T> newAdapter(final Class<T> ssoClass, String strategyName,
096            ApplicationStateCreator<T> creator)
097    {
098        if (creator == null)
099        {
100            creator = new ApplicationStateCreator<T>()
101            {
102                public T create()
103                {
104                    return locator.autobuild("Instantiating instance of SSO class "
105                            + ssoClass.getName(), ssoClass);
106                }
107            };
108        }
109
110        ApplicationStatePersistenceStrategy strategy = source.get(strategyName);
111
112        return new ApplicationStateAdapter(ssoClass, strategy, creator);
113    }
114
115    @SuppressWarnings("unchecked")
116    private <T> ApplicationStateAdapter<T> getAdapter(Class<T> ssoClass)
117    {
118        ApplicationStateAdapter<T> result = classToAdapter.get(ssoClass);
119
120        // Not found is completely OK, we'll define it on the fly.
121
122        if (result == null)
123        {
124            result = newAdapter(ssoClass, DEFAULT_STRATEGY, null);
125            classToAdapter.put(ssoClass, result);
126        }
127
128        return result;
129    }
130
131    public <T> T get(Class<T> ssoClass)
132    {
133        return getAdapter(ssoClass).getOrCreate();
134    }
135
136    public <T> T getIfExists(Class<T> ssoClass)
137    {
138        ApplicationStateAdapter<T> adapter = getAdapter(ssoClass);
139
140        return adapter.exists() ? adapter.getOrCreate() : null;
141    }
142
143    public <T> void set(Class<T> ssoClass, T sso)
144    {
145        getAdapter(ssoClass).set(sso);
146    }
147
148    public <T> boolean exists(Class<T> ssoClass)
149    {
150        return getAdapter(ssoClass).exists();
151    }
152
153}