001: /*
002: * Copyright 2007 The Kuali Foundation
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package edu.iu.uis.eden.messaging.serviceproxies;
017:
018: import java.io.Serializable;
019: import java.lang.reflect.Method;
020: import java.lang.reflect.Proxy;
021: import java.util.List;
022:
023: import javax.transaction.Status;
024:
025: import org.apache.log4j.Logger;
026: import org.kuali.bus.services.KSBServiceLocator;
027: import org.kuali.rice.RiceConstants;
028: import org.kuali.rice.core.Core;
029: import org.kuali.rice.proxy.BaseInvocationHandler;
030: import org.kuali.rice.proxy.TargetedInvocationHandler;
031: import org.kuali.rice.resourceloader.ContextClassLoaderProxy;
032: import org.kuali.rice.util.ClassLoaderUtils;
033:
034: import edu.iu.uis.eden.messaging.AsynchronousCall;
035: import edu.iu.uis.eden.messaging.AsynchronousCallback;
036: import edu.iu.uis.eden.messaging.MessageServiceInvoker;
037: import edu.iu.uis.eden.messaging.PersistedMessage;
038: import edu.iu.uis.eden.messaging.RemotedServiceHolder;
039: import edu.iu.uis.eden.messaging.ServiceInfo;
040:
041: /**
042: * Standard default proxy used to call services asynchronously. Persists the method call to the db so call is never lost and
043: * only sent when transaction is committed.
044: *
045: * @author Kuali Rice Team (kuali-rice@googlegroups.com)
046: *
047: */
048: public class AsynchronousServiceCallProxy extends BaseInvocationHandler
049: implements TargetedInvocationHandler {
050:
051: private static final Logger LOG = Logger
052: .getLogger(AsynchronousServiceCallProxy.class);
053:
054: private AsynchronousCallback callback;
055:
056: private List<RemotedServiceHolder> serviceDefs;
057:
058: private Serializable context;
059:
060: private String value1;
061: private String value2;
062:
063: protected AsynchronousServiceCallProxy(
064: List<RemotedServiceHolder> serviceDefs,
065: AsynchronousCallback callback, Serializable context,
066: String value1, String value2) {
067: this .serviceDefs = serviceDefs;
068: this .callback = callback;
069: this .context = context;
070: this .value1 = value1;
071: this .value2 = value2;
072: }
073:
074: public static Object createInstance(
075: List<RemotedServiceHolder> serviceDefs,
076: AsynchronousCallback callback, Serializable context,
077: String value1, String value2) {
078: if (serviceDefs == null || serviceDefs.isEmpty()) {
079: throw new RuntimeException(
080: "Cannot create service proxy, no service(s) passed in.");
081: }
082: return Proxy.newProxyInstance(ClassLoaderUtils
083: .getDefaultClassLoader(), ContextClassLoaderProxy
084: .getInterfacesToProxyIncludeSpring(serviceDefs.get(0)
085: .getService()),
086: new AsynchronousServiceCallProxy(serviceDefs, callback,
087: context, value1, value2));
088: }
089:
090: @Override
091: protected Object invokeInternal(Object proxy, Method method,
092: Object[] arguments) throws Throwable {
093: // there are multiple service calls to make in the case of topics.
094: AsynchronousCall methodCall = null;
095: PersistedMessage message = null;
096: synchronized (this ) {
097: // consider moving all this topic invocation stuff to the service
098: // invoker for speed reasons
099: for (RemotedServiceHolder remotedServiceHolder : this .serviceDefs) {
100: ServiceInfo serviceInfo = remotedServiceHolder
101: .getServiceInfo();
102: methodCall = new AsynchronousCall(method
103: .getParameterTypes(), arguments, serviceInfo,
104: method.getName(), this .callback, this .context);
105: message = KSBServiceLocator.getRouteQueueService()
106: .getMessage(serviceInfo, methodCall);
107: message.setValue1(this .value1);
108: message.setValue2(this .value2);
109: saveMessage(message);
110: executeMessage(message);
111: // only do one iteration if this is a queue. The load balancing
112: // will be handled when the service is
113: // fetched by the MessageServiceInvoker through the GRL (and
114: // then through the RemoteResourceServiceLocatorImpl)
115: if (serviceInfo.getServiceDefinition().getQueue()) {
116: break;
117: }
118: }
119: }
120: return null;
121: }
122:
123: protected void saveMessage(PersistedMessage message) {
124: if (new Boolean(Core.getCurrentContextConfig().getProperty(
125: RiceConstants.MESSAGE_PERSISTENCE))) {
126: if (LOG.isDebugEnabled()) {
127: LOG.debug("Persisting Message " + message);
128: }
129: message.setQueueStatus(RiceConstants.ROUTE_QUEUE_ROUTING);
130: KSBServiceLocator.getRouteQueueService().save(message);
131: }
132: }
133:
134: protected void executeMessage(PersistedMessage message)
135: throws Exception {
136: if (!new Boolean(Core.getCurrentContextConfig().getProperty(
137: RiceConstants.MESSAGING_OFF))) {
138:
139: if (KSBServiceLocator.getJtaTransactionManager()
140: .getStatus() == Status.STATUS_ACTIVE) {
141: KSBServiceLocator.getJtaTransactionManager()
142: .getTransaction().registerSynchronization(
143: new AsynchronousMessageCaller(message));
144: } else {
145: KSBServiceLocator.getThreadPool().execute(
146: new MessageServiceInvoker(message));
147: }
148: }
149: }
150:
151: /**
152: * Returns the List<RemotedServiceHolder> of asynchronous services which will be invoked by calls to this proxy.
153: * This is a List because, in the case of Topics, there can be more than one service invoked.
154: */
155: public Object getTarget() {
156: return this .serviceDefs;
157: }
158:
159: public AsynchronousCallback getCallback() {
160: return this .callback;
161: }
162:
163: public void setCallback(AsynchronousCallback callback) {
164: this .callback = callback;
165: }
166:
167: public List<RemotedServiceHolder> getServiceDefs() {
168: return this .serviceDefs;
169: }
170:
171: public void setServiceDefs(List<RemotedServiceHolder> serviceDefs) {
172: this.serviceDefs = serviceDefs;
173: }
174: }
|