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 */ 017 package javax.util.concurrent; 018 019 import java.util.Map; 020 021 /** 022 * The ContextService provides methods for creating <i>contextual dynamic proxy</i> 023 * objects. 024 * <p> 025 * 026 * The proxy objects follow the same rules as defined for the 027 * {@link java.lang.reflect.Proxy} class with the following additions: 028 * <ul> 029 * <li>The proxy instance will retain the context of the application 030 * container's thread (creator's context). 031 * <li>The proxy instance will implement all of the interfaces specified on the 032 * <code>createContextObject</code> methods. 033 * <li>All interface method invocations on a proxy instance run in the 034 * creator's context. 035 * <li>Invocation of the <code>hashCode</code>, <code>equals</code>, and 036 * <code>toString</code> methods declared in <code>java.lang.Object</code> 037 * on a sproxy instance will not run in the creator's context. 038 * <li>The proxy instance must implement <code>java.io.Serializable</code>. 039 * <li>The proxied object instance must implement 040 * <code>java.io.Serializable</code> if the proxy instance is serialized. 041 * <li>Context properties can be stored with the proxy instance. Custom 042 * property keys must not begin with "ctxsvc.". 043 * <li>Context properties are to be used for controlling how various contextual 044 * information is retreived and applied to the thread. Although application 045 * components can store arbitrary property keys and values, it is not 046 * recommended. Java EE product providers may impose limits to the size of the 047 * keys and values. 048 * <li>Context property keys and values must all be of type 049 * <code>java.lang.String</code>. Use of the <code>put</code> and 050 * <code>putAll</code> methods on the <code>java.util.Hashtable</code> 051 * superclass are discouraged. 052 * </ul> 053 * 054 */ 055 public interface ContextService { 056 /** 057 * A contextual object property that disables the normal transaction 058 * suspension and UserTransaction access from the proxied methods. 059 * <p> 060 * 061 * If "false" (the default if unspecified), any transaction that is 062 * currently active on the thread will be suspended and a UserTransaction 063 * (accessible in the local JNDI namespace as "java:comp/UserTransaction") 064 * will be available. When the proxied method returns the original 065 * transaction is restored. 066 * <p> 067 * 068 * If "true", the proxied method will run within the transaction (if any) of 069 * the current thread. A UserTransaction will only be available if the the 070 * container thread (for example, a Servlet or Bean Managed Transaction 071 * EJB). 072 */ 073 public String USE_PARENT_TRANSACTION = "ctxsvc.useparenttran"; 074 075 /** 076 * Creates a new contextual object proxy for the input object instance. 077 * <p> 078 * 079 * Each method invocation will have the context of the application component 080 * instance that created the context object. 081 * <p> 082 * 083 * The contextual object is useful when developing or using Java SE 084 * threading mechanisms spraying events to other component instances or 085 * communicating with component instances on different Java processes. 086 * <p> 087 * 088 * If the application component that created the proxy is started or 089 * deployed, all methods on reflected interfaces will throw a 090 * <code>java.lang.IllegalState</code> exception. 091 * <p> 092 * 093 * For example, to call a normal Runnable with the correct context using a 094 * Java™ ExecutorService: 095 * <P> 096 * 097 * <pre> 098 * public class MyRunnable implements Runnable { 099 * public void run() { 100 * System.out.println("MyRunnable.run with J2EE Context available."); 101 * } 102 * } 103 * 104 * InitialContext ctx = new InitialContext(); 105 * 106 * ThreadFactory threadFactory = (ThreadFactory) ctx 107 * .lookup("java:comp/env/concurrent/ThreadFactory"); 108 * 109 * ContextService ctxService = (ContextService) ctx 110 * .lookup("java:comp/env/concurrent/ContextService"); 111 * 112 * Object rProxy = ctxService.createContextObject(myRunnableInstance, 113 * new Class[] { Runnable.class }); 114 * 115 * ExecutorService exSvc = Executors.newThreadPool(10, threadFactory); 116 * 117 * Future f = exSvc.submit((Runnable) rProxy); 118 * </pre> 119 * 120 * @param instance 121 * the instance of the object to proxy. 122 * @param interfaces 123 * the interfaces that the proxy should implement. 124 * @return a proxy for the input object that implements all of the specified 125 * interfaces. 126 * @throws IllegalArgumentException 127 * if the Class does not have an interface or there is not an 128 * accessible default constructor. 129 */ 130 public Object createContextObject(Object instance, Class<?>[] interfaces); 131 132 /** 133 * Creates a new contextual object proxy for the input object instance. 134 * <p> 135 * 136 * The contextual object is useful when developing or using Java SE 137 * threading mechanisms spraying events to other component instances or 138 * communicating with component instances on different Java processes. 139 * <p> 140 * 141 * If the application component that created the proxy is started or 142 * deployed, all methods on reflected interfaces will throw a 143 * <code>java.lang.IllegalState</code> exception. 144 * <p> 145 * 146 * This method accepts a {@link Properties} object which allows the 147 * contextual object creator to define what contexts or behaviors to capture 148 * when creating the contextual object. The specified properties will remain 149 * with the contextual object until the properties are updated or removed 150 * using the {@link #setProperties(Object, Properties)} method. 151 * <p> 152 * 153 * For example, to call a Message Driven Bean (MDB) with the sender's 154 * context, but within the MDB's transaction: 155 * <P> 156 * 157 * <pre> 158 * public class MyServlet ... { 159 * public void doPost() throws NamingException, JMSException { 160 * InitialContext ctx = new InitialContext(); 161 * 162 * // Get the ContextService that only propagates 163 * // security context. 164 * ContextService ctxSvc = (ContextService) 165 * ctx.lookup("java:comp/env/SecurityContext"); 166 * 167 * // Set any custom context data. 168 * Properties ctxProps = new Properties(); 169 * ctxProps.setProperty("vendor_a.security.tokenexpiration", "15000"); 170 * 171 * ProcessMessage msgProcessor = 172 * (ProcessMessage) ctxSvc.createContextObject(new MessageProcessor(), 173 * new Class[]{ProcessMessage.class}, 174 * ctxProps); 175 * 176 * ConnectionFactory cf = (ConnectionFactory) 177 * ctx.lookup("java:comp/env/MyTopicConnectionFactory"); 178 * Destination dest = (Destination) ctx.lookup("java:comp/env/MyTopic"); 179 * Connection con = cf.createConnection(); 180 * 181 * Session session = con.createSession(true, Session.AUTO_ACKNOWLEDGE); 182 * MessageProducer producer = session.createProducer(dest); 183 * 184 * Message msg = session.createObjectMessage((Serializable)msgProcessor); 185 * producer.send(dest, msg); 186 * ... 187 * 188 * } 189 * 190 * public class MyMDB ... { 191 * public void onMessage(Message msg) { 192 * // Get the ProcessMessage context object from the message. 193 * ObjectMessage omsg = (ObjectMessage)msg; 194 * ProcessMessage msgProcessor = (ProcessMessage)omsg.getObject(); 195 * 196 * // Update the context object and verify that the processMessage() 197 * // method runs inside the current transaction. If we have a failure, 198 * // we don't want to consume the message. 199 * InitialContext ctx = new InitialContext(); 200 * ContextService ctxSvc = (ContextService) 201 * ctx.lookup("java:comp/env/SecurityContext"); 202 * Properties ctxProps = ctxSvc.getProperties(msgProcessor); 203 * ctxProps.setProperty(ContextService.USE_PARENT_TRANSACTION, "true"); 204 * ctxSvc.setProperties(msgProcessor, ctxProps); 205 * 206 * // Process the message in the specified context. 207 * msgProcessor.processMessage(msg); 208 * } 209 * } 210 * 211 * public interface ProcessMessage { 212 * public void processMessage(Message msg); 213 * } 214 * 215 * public class MessageProcessor implements ProcessMessage, Serializable { 216 * public void processMessage(Message msg) { 217 * // Process the message with the application container 218 * // context that sent the message. 219 * 220 * } 221 * } 222 * </pre> 223 * 224 * @param instance 225 * the instance of the object to proxy. 226 * @param interfaces 227 * the interfaces that the proxy should implement. 228 * @param contextProperties 229 * the properties to use when creating and running the context 230 * object. 231 * @return a proxy for the input object that implements all of the specified 232 * interfaces. 233 * @throws IllegalArgumentException 234 * if the Class does not have an interface or there is not an 235 * accessible default constructor. 236 * @throws ClassCastException 237 * thrown if one of the keys or values in the specified 238 * Properties object are not of type String. 239 */ 240 public Object createContextObject(Object instance, Class<?>[] interfaces, 241 Map<String, String> contextProperties); 242 243 /** 244 * Sets the properties on the context proxy instance. 245 * <p> 246 * 247 * All property keys and values must be strings. Storing other class types 248 * may result in a <code>java.lang.ClassCastException</code>. 249 * 250 * @param contextObject 251 * the contextual proxy instance to set the properties. 252 * @param contextProperties 253 * the properties to use when running the context object. Specify 254 * an empty Properties object to erase all current properties. 255 * @throws IllegalArgumentException 256 * thrown if the input contextObject is not a valid contextual 257 * object proxy created with the 258 * <code>createContextObject</code> method. 259 * @throws ClassCastException 260 * thrown if one of the keys or values in the specified 261 * Properties object are not of type String. 262 */ 263 public void setProperties(Object contextObject, Map<String, String> contextProperties); 264 265 /** 266 * Gets the current properties on the context proxy instance. 267 * 268 * @param contextObject 269 * the contextual proxy instance to set the properties. 270 * @return the current context object properties 271 * @throws IllegalArgumentException 272 * thrown if the input contextObject is not a valid contextual 273 * object proxy created with the 274 * <code>createContextObject</code> method. 275 */ 276 public Map<String, String> getProperties(Object contextObject); 277 }