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    
015    package org.apache.tapestry5.internal.services;
016    
017    import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newConcurrentMap;
018    
019    import java.util.Map;
020    
021    import org.apache.tapestry5.ioc.ObjectLocator;
022    import org.apache.tapestry5.services.ApplicationStateContribution;
023    import org.apache.tapestry5.services.ApplicationStateCreator;
024    import org.apache.tapestry5.services.ApplicationStateManager;
025    import org.apache.tapestry5.services.ApplicationStatePersistenceStrategy;
026    import org.apache.tapestry5.services.ApplicationStatePersistenceStrategySource;
027    
028    public 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    }