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