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}