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}