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        @Override
056        public String getServiceId()
057        {
058            return serviceDef.getServiceId();
059        }
060
061        @Override
062        public Class getServiceInterface()
063        {
064            return serviceDef.getServiceInterface();
065        }
066
067        @Override
068        public String getScope()
069        {
070            return serviceDef.getServiceScope();
071        }
072
073        @Override
074        public Set<Class> getMarkers()
075        {
076            return serviceDef.getMarkers();
077        }
078
079        // Mutable properties must be synchronized
080
081        @Override
082        public synchronized Status getStatus()
083        {
084            if (perThreadStatus != null) {
085                if (!perThreadStatus.exists()) perThreadStatus.set(status);
086                return perThreadStatus.get();
087            }
088            else return status;
089        }
090
091        synchronized void setStatus(Status status)
092        {
093            if (perThreadStatus != null) perThreadStatus.set(status);
094            else this.status = status;
095        }
096    }
097
098    private final PerthreadManager perthreadManager;
099
100    public ServiceActivityTrackerImpl(PerthreadManager perthreadManager) {
101        this.perthreadManager = perthreadManager;
102    }
103
104    /**
105     * Tree map keeps everything in order by key (serviceId).
106     */
107    private final Map<String, MutableServiceActivity> serviceIdToServiceStatus = new TreeMap<String, MutableServiceActivity>();
108
109    @Override
110    public synchronized List<ServiceActivity> getServiceActivity()
111    {
112        // Need to wrap the values in a new list because
113        // a) we don't want people arbitrarily changing the internal state of
114        // _serviceIdtoServiceStatus
115        // b) values() is Collection and we want to return List
116
117        // Note: ugly code here to keep Sun compiler happy.
118
119        List<ServiceActivity> result = CollectionFactory.newList();
120
121        result.addAll(serviceIdToServiceStatus.values());
122
123        return result;
124    }
125
126    void startup()
127    {
128        // Does nothing, first pass does not use a worker thread
129    }
130
131    void shutdown()
132    {
133        // Does nothing, first pass does not use a worker thread
134    }
135
136    @Override
137    public synchronized void define(ServiceDef serviceDef, Status initialStatus)
138    {
139        serviceIdToServiceStatus.put(serviceDef.getServiceId(), new MutableServiceActivity(
140                serviceDef, perthreadManager, initialStatus));
141    }
142
143    @Override
144    public synchronized void setStatus(String serviceId, Status status)
145    {
146        serviceIdToServiceStatus.get(serviceId).setStatus(status);
147    }
148
149}