View Javadoc

1   /*
2    * Copyright 2007 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.ksb.messaging.serviceproxies;
17  
18  import java.io.Serializable;
19  import java.lang.reflect.Method;
20  import java.lang.reflect.Proxy;
21  import java.util.List;
22  
23  import org.apache.log4j.Logger;
24  import org.kuali.rice.core.exception.RiceRuntimeException;
25  import org.kuali.rice.core.proxy.BaseInvocationHandler;
26  import org.kuali.rice.core.proxy.TargetedInvocationHandler;
27  import org.kuali.rice.core.resourceloader.ContextClassLoaderProxy;
28  import org.kuali.rice.core.util.ClassLoaderUtils;
29  import org.kuali.rice.ksb.messaging.AsynchronousCall;
30  import org.kuali.rice.ksb.messaging.AsynchronousCallback;
31  import org.kuali.rice.ksb.messaging.PersistedMessage;
32  import org.kuali.rice.ksb.messaging.RemotedServiceHolder;
33  import org.kuali.rice.ksb.messaging.ServiceHolder;
34  import org.kuali.rice.ksb.messaging.ServiceInfo;
35  import org.kuali.rice.ksb.service.KSBServiceLocator;
36  import org.kuali.rice.ksb.util.KSBConstants;
37  
38  
39  /**
40   * Standard default proxy used to call services asynchronously. Persists the method call to the db so call is never lost and
41   * only sent when transaction is committed.
42   * 
43   * @author Kuali Rice Team (rice.collab@kuali.org)
44   * 
45   */
46  public class AsynchronousServiceCallProxy extends BaseInvocationHandler implements TargetedInvocationHandler {
47      
48      private static final Logger LOG = Logger.getLogger(AsynchronousServiceCallProxy.class);
49  
50      private AsynchronousCallback callback;
51  
52      private List<RemotedServiceHolder> serviceDefs;
53  
54      private Serializable context;
55  
56      private String value1;
57  
58      private String value2;
59  
60      protected AsynchronousServiceCallProxy(List<RemotedServiceHolder> serviceDefs, AsynchronousCallback callback,
61  	    Serializable context, String value1, String value2) {
62  	this.serviceDefs = serviceDefs;
63  	this.callback = callback;
64  	this.context = context;
65  	this.value1 = value1;
66  	this.value2 = value2;
67      }
68  
69      public static Object createInstance(List<RemotedServiceHolder> serviceDefs, AsynchronousCallback callback,
70  	    Serializable context, String value1, String value2) {
71  	if (serviceDefs == null || serviceDefs.isEmpty()) {
72  	    throw new RuntimeException("Cannot create service proxy, no service(s) passed in.");
73  	}
74  	try {
75  	    return Proxy.newProxyInstance(ClassLoaderUtils.getDefaultClassLoader(), ContextClassLoaderProxy
76  		    .getInterfacesToProxyIncludeSpring(serviceDefs.get(0).getService()), new AsynchronousServiceCallProxy(
77  		    serviceDefs, callback, context, value1, value2));
78  	} catch (Exception e) {
79  	    throw new RiceRuntimeException(e);
80  	}
81      }
82  
83      @Override
84      protected Object invokeInternal(Object proxy, Method method, Object[] arguments) throws Throwable {
85  
86  	if (LOG.isDebugEnabled()) {
87  	    LOG.debug("creating messages for method invocation: " + method.getName());
88  	}
89  	// there are multiple service calls to make in the case of topics.
90  	AsynchronousCall methodCall = null;
91  	PersistedMessage message = null;
92  	synchronized (this) {
93  	    // consider moving all this topic invocation stuff to the service
94  	    // invoker for speed reasons
95  	    for (ServiceHolder remotedServiceHolder : this.serviceDefs) {
96  		ServiceInfo serviceInfo = remotedServiceHolder.getServiceInfo();
97  		methodCall = new AsynchronousCall(method.getParameterTypes(), arguments, serviceInfo, method.getName(),
98  			this.callback, this.context);
99  		message = KSBServiceLocator.getRouteQueueService().getMessage(serviceInfo, methodCall);
100 		message.setValue1(this.value1);
101 		message.setValue2(this.value2);
102 		saveMessage(message);
103 		executeMessage(message);
104 		// only do one iteration if this is a queue. The load balancing
105 		// will be handled when the service is
106 		// fetched by the MessageServiceInvoker through the GRL (and
107 		// then through the RemoteResourceServiceLocatorImpl)
108 		if (serviceInfo.getServiceDefinition().getQueue()) {
109 		    break;
110 		}
111 	    }
112 	}
113 	if (LOG.isDebugEnabled()) {
114 	    LOG.debug("finished creating messages for method invocation: " + method.getName());
115 	}
116 	return null;
117     }
118 
119     protected void saveMessage(PersistedMessage message) {
120 	message.setQueueStatus(KSBConstants.ROUTE_QUEUE_ROUTING);
121 	KSBServiceLocator.getRouteQueueService().save(message);
122     }
123 
124     protected void executeMessage(PersistedMessage message) throws Exception {
125 	MessageSender.sendMessage(message);
126     }
127 
128     /**
129          * Returns the List<RemotedServiceHolder> of asynchronous services which will be invoked by calls to this proxy.
130          * This is a List because, in the case of Topics, there can be more than one service invoked.
131          */
132     public Object getTarget() {
133 	return this.serviceDefs;
134     }
135 
136     public AsynchronousCallback getCallback() {
137 	return this.callback;
138     }
139 
140     public void setCallback(AsynchronousCallback callback) {
141 	this.callback = callback;
142     }
143 
144     public List<RemotedServiceHolder> getServiceDefs() {
145 	return this.serviceDefs;
146     }
147 
148     public void setServiceDefs(List<RemotedServiceHolder> serviceDefs) {
149 	this.serviceDefs = serviceDefs;
150     }
151 }