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&trade; ExecutorService:
095         * <P>
096         *
097         * <pre>
098         * public class MyRunnable implements Runnable {
099         *     public void run() {
100         *         System.out.println(&quot;MyRunnable.run with J2EE Context available.&quot;);
101         *     }
102         * }
103         *
104         * InitialContext ctx = new InitialContext();
105         *
106         * ThreadFactory threadFactory = (ThreadFactory) ctx
107         *         .lookup(&quot;java:comp/env/concurrent/ThreadFactory&quot;);
108         *
109         * ContextService ctxService = (ContextService) ctx
110         *         .lookup(&quot;java:comp/env/concurrent/ContextService&quot;);
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(&quot;java:comp/env/SecurityContext&quot;);
166         *
167         *            // Set any custom context data.
168         *            Properties ctxProps = new Properties();
169         *            ctxProps.setProperty(&quot;vendor_a.security.tokenexpiration&quot;, &quot;15000&quot;);
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(&quot;java:comp/env/MyTopicConnectionFactory&quot;);
178         *            Destination dest = (Destination) ctx.lookup(&quot;java:comp/env/MyTopic&quot;);
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(&quot;java:comp/env/SecurityContext&quot;);
202         *            Properties ctxProps = ctxSvc.getProperties(msgProcessor);
203         *            ctxProps.setProperty(ContextService.USE_PARENT_TRANSACTION, &quot;true&quot;);
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    }