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