    001    // Copyright 2007, 2009, 2011 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.ioc.internal.services;
    016
    017    import org.apache.tapestry5.ioc.ObjectCreator;
    018    import org.apache.tapestry5.ioc.internal.EagerLoadServiceProxy;
    019    import org.apache.tapestry5.ioc.internal.ServiceActivityTracker;
    020    import org.apache.tapestry5.ioc.services.Status;
    021
    022    /**
    023     * Invoked from a fabricated service delegate to get or realize (instantiate and configure) the service implementation.
    024     * This includes synchronization logic, to prevent multiple threads from attempting to realize the same service at the
    025     * same time (a service should be realized only once). The additional interfaces implemented by this class support eager
    026     * loading of services (at application startup), and orderly shutdown of proxies.
    027     */
    028    public class JustInTimeObjectCreator<T> implements ObjectCreator<T>, EagerLoadServiceProxy, Runnable
    029    {
    030        private final ServiceActivityTracker tracker;
    031
    032        private ObjectCreator<T> creator;
    033
    034        private volatile T object;
    035
    036        private final String serviceId;
    037
    038        public JustInTimeObjectCreator(ServiceActivityTracker tracker, ObjectCreator<T> creator, String serviceId)
    039        {
    040            this.tracker = tracker;
    041            this.creator = creator;
    042            this.serviceId = serviceId;
    043        }
    044
    045        /**
    046         * Checks to see if the proxy has been shutdown, then invokes {@link ObjectCreator#createObject()} if it has not
    047         * already done so.
    048         *
    049         * @throws IllegalStateException if the registry has been shutdown
    050         */
    051        public T createObject()
    052        {
    053            if (object == null)
    054                obtainObjectFromCreator();
    055
    056            return object;
    057        }
    058
    059        private synchronized void obtainObjectFromCreator()
    060        {
    061            if (object != null)
    062                return;
    063
    064            try
    065            {
    066                object = creator.createObject();
    067
    068                // And if that's successful ...
    069
    070                tracker.setStatus(serviceId, Status.REAL);
    071
    072                creator = null;
    073            } catch (RuntimeException ex)
    074            {
    075                throw new RuntimeException(ServiceMessages.serviceBuildFailure(serviceId, ex), ex);
    076            }
    077        }
    078
    079        /**
    080         * Invokes {@link #createObject()} to force the creation of the underlying service.
    081         */
    082        public void eagerLoadService()
    083        {
    084            // Force object creation now
    085
    086            createObject();
    087        }
    088
    089        /**
    090         * Invoked when the Registry is shutdown; deletes the instantiated object (if it exists) and replaces
    091         * the ObjectCreator with one that throws an IllegalStateException.
    092         */
    093        public synchronized void run()
    094        {
    095            creator = new ObjectCreator<T>()
    096            {
    097                public T createObject()
    098                {
    099                    throw new IllegalStateException(ServiceMessages.registryShutdown(serviceId));
    100                }
    101            };
    102
    103            object = null;
    104        }
    105
    106    }