001// Copyright 2007 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.ioc.internal;
016
017import org.apache.tapestry5.ioc.def.ServiceDef;
018import org.apache.tapestry5.ioc.services.ServiceActivity;
019import org.apache.tapestry5.ioc.services.ServiceActivityScoreboard;
020import org.apache.tapestry5.ioc.services.Status;
021
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025import java.util.TreeMap;
026
027import org.apache.tapestry5.commons.util.CollectionFactory;
028import org.apache.tapestry5.ioc.ScopeConstants;
029import org.apache.tapestry5.ioc.services.PerThreadValue;
030import org.apache.tapestry5.ioc.services.PerthreadManager;
031
032public class ServiceActivityTrackerImpl implements ServiceActivityScoreboard,
033        ServiceActivityTracker
034{
035    public static class MutableServiceActivity implements ServiceActivity
036    {
037        private final ServiceDef serviceDef;
038
039        private Status status;
040
041        private final PerThreadValue<Status> perThreadStatus;
042
043        public MutableServiceActivity(ServiceDef serviceDef, PerthreadManager perthreadManager, Status status)
044        {
045            this.serviceDef = serviceDef;
046            if (serviceDef.getServiceScope().equals(ScopeConstants.PERTHREAD)) {
047                perThreadStatus = perthreadManager.createValue();
048                perThreadStatus.set(status);
049                this.status = status; // this is now the default status
050            } else {
051                perThreadStatus = null;
052                this.status = status;
053            }
054        }
055
056        @Override
057        public String getServiceId()
058        {
059            return serviceDef.getServiceId();
060        }
061
062        @Override
063        public Class getServiceInterface()
064        {
065            return serviceDef.getServiceInterface();
066        }
067
068        @Override
069        public String getScope()
070        {
071            return serviceDef.getServiceScope();
072        }
073
074        @Override
075        public Set<Class> getMarkers()
076        {
077            return serviceDef.getMarkers();
078        }
079
080        // Mutable properties must be synchronized
081
082        @Override
083        public synchronized Status getStatus()
084        {
085            if (perThreadStatus != null) {
086                if (!perThreadStatus.exists()) perThreadStatus.set(status);
087                return perThreadStatus.get();
088            }
089            else return status;
090        }
091
092        synchronized void setStatus(Status status)
093        {
094            if (perThreadStatus != null) perThreadStatus.set(status);
095            else this.status = status;
096        }
097    }
098
099    private final PerthreadManager perthreadManager;
100
101    public ServiceActivityTrackerImpl(PerthreadManager perthreadManager) {
102        this.perthreadManager = perthreadManager;
103    }
104
105    /**
106     * Tree map keeps everything in order by key (serviceId).
107     */
108    private final Map<String, MutableServiceActivity> serviceIdToServiceStatus = new TreeMap<String, MutableServiceActivity>();
109
110    @Override
111    public synchronized List<ServiceActivity> getServiceActivity()
112    {
113        // Need to wrap the values in a new list because
114        // a) we don't want people arbitrarily changing the internal state of
115        // _serviceIdtoServiceStatus
116        // b) values() is Collection and we want to return List
117
118        // Note: ugly code here to keep Sun compiler happy.
119
120        List<ServiceActivity> result = CollectionFactory.newList();
121
122        result.addAll(serviceIdToServiceStatus.values());
123
124        return result;
125    }
126
127    void startup()
128    {
129        // Does nothing, first pass does not use a worker thread
130    }
131
132    void shutdown()
133    {
134        // Does nothing, first pass does not use a worker thread
135    }
136
137    @Override
138    public synchronized void define(ServiceDef serviceDef, Status initialStatus)
139    {
140        serviceIdToServiceStatus.put(serviceDef.getServiceId(), new MutableServiceActivity(
141                serviceDef, perthreadManager, initialStatus));
142    }
143
144    @Override
145    public synchronized void setStatus(String serviceId, Status status)
146    {
147        serviceIdToServiceStatus.get(serviceId).setStatus(status);
148    }
149
150}