001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.cdi; 018 019import java.util.Collections; 020import java.util.Map; 021import java.util.WeakHashMap; 022 023import javax.annotation.PostConstruct; 024import javax.annotation.PreDestroy; 025import javax.enterprise.context.spi.CreationalContext; 026import javax.enterprise.inject.spi.AnnotatedType; 027import javax.enterprise.inject.spi.BeanManager; 028import javax.enterprise.inject.spi.InjectionTarget; 029 030import org.apache.wicket.util.collections.ClassMetaCache; 031 032/** 033 * Manages lifecycle of non-contextual (non-CDI-managed) objects 034 * 035 * @param <T> 036 * @author igor 037 */ 038public class NonContextual<T> 039{ 040 private static final Object lock = new Object(); 041 private static volatile Map<BeanManager, ClassMetaCache<NonContextual<?>>> cache = Collections 042 .emptyMap(); 043 044 final InjectionTarget<T> it; 045 046 /** 047 * Undeploys the looked up bean manager from cache 048 */ 049 public static void undeploy() 050 { 051 if (cache.containsKey(BeanManagerLookup.lookup())) 052 { 053 synchronized (lock) 054 { 055 // copy-on-write the cache 056 Map<BeanManager, ClassMetaCache<NonContextual<?>>> newCache = new WeakHashMap<BeanManager, ClassMetaCache<NonContextual<?>>>( 057 cache); 058 newCache.remove(BeanManagerLookup.lookup()); 059 cache = Collections.unmodifiableMap(newCache); 060 } 061 } 062 } 063 064 /** 065 * Convenience factory method for an instance, see {@link #of(Class)}. 066 * 067 * @param <T> 068 * @param t 069 * @return The NonContextual for the instance's class 070 */ 071 @SuppressWarnings("unchecked") 072 public static <T> NonContextual<T> of(T t) { 073 // cast is necessary for Eclipse compiler :/ 074 return (NonContextual<T>)of(t.getClass()); 075 } 076 077 /** 078 * Factory method for creating non-contextual instances 079 * 080 * @param <T> 081 * @param clazz 082 * @return The NonContextual for the given class 083 */ 084 public static <T> NonContextual<T> of(Class<? extends T> clazz) 085 { 086 ClassMetaCache<NonContextual<?>> meta = getCache(); 087 088 @SuppressWarnings("unchecked") 089 NonContextual<T> nc = (NonContextual<T>)meta.get(clazz); 090 091 if (nc == null) 092 { 093 nc = new NonContextual<T>(clazz); 094 meta.put(clazz, nc); 095 } 096 return nc; 097 } 098 099 private static ClassMetaCache<NonContextual<?>> getCache() 100 { 101 ClassMetaCache<NonContextual<?>> meta = cache.get(BeanManagerLookup.lookup()); 102 if (meta == null) 103 { 104 synchronized (lock) 105 { 106 BeanManager manager = BeanManagerLookup.lookup(); 107 meta = cache.get(manager); 108 if (meta == null) 109 { 110 meta = new ClassMetaCache<NonContextual<?>>(); 111 112 // copy-on-write the cache 113 Map<BeanManager, ClassMetaCache<NonContextual<?>>> newCache = new WeakHashMap<BeanManager, ClassMetaCache<NonContextual<?>>>( 114 cache); 115 newCache.put(manager, meta); 116 cache = Collections.unmodifiableMap(newCache); 117 } 118 } 119 } 120 return meta; 121 } 122 123 @SuppressWarnings("unchecked") 124 private NonContextual(Class<? extends T> clazz) 125 { 126 BeanManager manager = BeanManagerLookup.lookup(); 127 AnnotatedType<? extends T> type = manager.createAnnotatedType(clazz); 128 this.it = (InjectionTarget<T>) manager.getInjectionTargetFactory(type) 129 .createInjectionTarget(null); 130 } 131 132 /** 133 * Injects the instance and calls any {@link PostConstruct} methods 134 * 135 * @param instance 136 */ 137 public void postConstruct(T instance) 138 { 139 CreationalContext<T> cc = BeanManagerLookup.lookup().createCreationalContext(null); 140 it.inject(instance, cc); 141 it.postConstruct(instance); 142 } 143 144 /** 145 * Injects the instance 146 * 147 * @param instance 148 */ 149 public void inject(T instance) 150 { 151 CreationalContext<T> cc = BeanManagerLookup.lookup().createCreationalContext(null); 152 it.inject(instance, cc); 153 } 154 155 /** 156 * Calls any {@link PreDestroy} methods and destroys any injected 157 * dependencies that need to be destroyed. 158 * 159 * @param instance 160 */ 161 public void preDestroy(T instance) 162 { 163 it.preDestroy(instance); 164 } 165}