001    // Copyright 2007, 2008 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 org.apache.tapestry5.ioc.ObjectLocator;
018    import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newConcurrentMap;
019    import org.apache.tapestry5.services.*;
020    
021    import java.util.Map;
022    
023    public class ApplicationStateManagerImpl implements ApplicationStateManager
024    {
025        static final String DEFAULT_STRATEGY = "session";
026    
027        static class ApplicationStateAdapter<T>
028        {
029            private final Class<T> ssoClass;
030    
031            private final ApplicationStatePersistenceStrategy strategy;
032    
033            private final ApplicationStateCreator<T> creator;
034    
035            ApplicationStateAdapter(Class<T> ssoClass, ApplicationStatePersistenceStrategy strategy,
036                                    ApplicationStateCreator<T> creator)
037            {
038                this.ssoClass = ssoClass;
039                this.strategy = strategy;
040                this.creator = creator;
041            }
042    
043            T getOrCreate()
044            {
045                return strategy.get(ssoClass, creator);
046            }
047    
048            void set(T sso)
049            {
050                strategy.set(ssoClass, sso);
051            }
052    
053            boolean exists()
054            {
055                return strategy.exists(ssoClass);
056            }
057        }
058    
059        /**
060         * The map will be extended periodically as new ASOs, not in the configuration, are encountered. Thut is is thread
061         * safe.
062         */
063        private final Map<Class, ApplicationStateAdapter> classToAdapter = newConcurrentMap();
064    
065        private final ApplicationStatePersistenceStrategySource source;
066    
067        private final ObjectLocator locator;
068    
069        @SuppressWarnings("unchecked")
070        public ApplicationStateManagerImpl(Map<Class, ApplicationStateContribution> configuration,
071                                           ApplicationStatePersistenceStrategySource source, ObjectLocator locator)
072        {
073            this.source = source;
074            this.locator = locator;
075    
076            for (Class asoClass : configuration.keySet())
077            {
078                ApplicationStateContribution contribution = configuration.get(asoClass);
079    
080                ApplicationStateAdapter adapter = newAdapter(asoClass, contribution.getStrategy(),
081                                                             contribution.getCreator());
082    
083                classToAdapter.put(asoClass, adapter);
084            }
085    
086        }
087    
088        @SuppressWarnings("unchecked")
089        private <T> ApplicationStateAdapter<T> newAdapter(final Class<T> ssoClass, String strategyName,
090                                                          ApplicationStateCreator<T> creator)
091        {
092            if (creator == null)
093            {
094                creator = new ApplicationStateCreator<T>()
095                {
096                    public T create()
097                    {
098                        return locator.autobuild(ssoClass);
099                    }
100                };
101            }
102    
103            ApplicationStatePersistenceStrategy strategy = source.get(strategyName);
104    
105            return new ApplicationStateAdapter(ssoClass, strategy, creator);
106        }
107    
108        @SuppressWarnings("unchecked")
109        private <T> ApplicationStateAdapter<T> getAdapter(Class<T> ssoClass)
110        {
111            ApplicationStateAdapter<T> result = classToAdapter.get(ssoClass);
112    
113            // Not found is completely OK, we'll define it on the fly.
114    
115            if (result == null)
116            {
117                result = newAdapter(ssoClass, DEFAULT_STRATEGY, null);
118                classToAdapter.put(ssoClass, result);
119            }
120    
121            return result;
122        }
123    
124        public <T> T get(Class<T> ssoClass)
125        {
126            return getAdapter(ssoClass).getOrCreate();
127        }
128    
129        public <T> T getIfExists(Class<T> ssoClass)
130        {
131            ApplicationStateAdapter<T> adapter = getAdapter(ssoClass);
132    
133            return adapter.exists() ? adapter.getOrCreate() : null;
134        }
135    
136        public <T> void set(Class<T> ssoClass, T sso)
137        {
138            getAdapter(ssoClass).set(sso);
139        }
140    
141        public <T> boolean exists(Class<T> ssoClass)
142        {
143            return getAdapter(ssoClass).exists();
144        }
145    
146    }