    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.ioc.ObjectCreator;
    018import org.apache.tapestry5.ioc.internal.EagerLoadServiceProxy;
    019import org.apache.tapestry5.ioc.internal.ServiceActivityTracker;
    020import 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 */
    028public 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    @Override
    052    public T createObject()
    053    {
    054        if (object == null)
    055            obtainObjectFromCreator();
    056
    057        return object;
    058    }
    059
    060    private synchronized void obtainObjectFromCreator()
    061    {
    062        if (object != null)
    063            return;
    064
    065        try
    066        {
    067            object = creator.createObject();
    068
    069            // And if that's successful ...
    070
    071            tracker.setStatus(serviceId, Status.REAL);
    072
    073            creator = null;
    074        } catch (RuntimeException ex)
    075        {
    076            throw new RuntimeException(ServiceMessages.serviceBuildFailure(serviceId, ex), ex);
    077        }
    078    }
    079
    080    /**
    081     * Invokes {@link #createObject()} to force the creation of the underlying service.
    082     */
    083    @Override
    084    public void eagerLoadService()
    085    {
    086        // Force object creation now
    087
    088        createObject();
    089    }
    090
    091    /**
    092     * Invoked when the Registry is shutdown; deletes the instantiated object (if it exists) and replaces
    093     * the ObjectCreator with one that throws an IllegalStateException.
    094     */
    095    @Override
    096    public synchronized void run()
    097    {
    098        creator = new ObjectCreator<T>()
    099        {
    100            @Override
    101            public T createObject()
    102            {
    103                throw new IllegalStateException(ServiceMessages.registryShutdown(serviceId));
    104            }
    105        };
    106
    107        object = null;
    108    }
    109
    110}