View Javadoc

1   /*
2    * Copyright 2005-2009 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License"); you may not use this file except in
5    * compliance with the License. You may obtain a copy of the License at
6    * 
7    * http://www.opensource.org/licenses/ecl2.php
8    * 
9    * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS
10   * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
11   * language governing permissions and limitations under the License.
12   */
13  package org.kuali.rice.kns.service.impl;
14  
15  import java.util.ArrayList;
16  import java.util.HashMap;
17  import java.util.List;
18  
19  import javax.xml.namespace.QName;
20  
21  import org.kuali.rice.core.resourceloader.GlobalResourceLoader;
22  import org.kuali.rice.core.util.MaxAgeSoftReference;
23  import org.kuali.rice.kns.bo.Namespace;
24  import org.kuali.rice.kns.bo.ParameterDetailType;
25  import org.kuali.rice.kns.datadictionary.AttributeDefinition;
26  import org.kuali.rice.kns.service.KNSServiceLocator;
27  import org.kuali.rice.kns.service.NamespaceService;
28  import org.kuali.rice.kns.service.RiceApplicationConfigurationMediationService;
29  import org.kuali.rice.kns.service.RiceApplicationConfigurationService;
30  import org.kuali.rice.ksb.messaging.RemoteResourceServiceLocator;
31  import org.kuali.rice.ksb.messaging.resourceloader.KSBResourceLoaderFactory;
32  
33  //@Transactional
34  public class RiceApplicationConfigurationMediationServiceImpl implements RiceApplicationConfigurationMediationService {
35      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RiceApplicationConfigurationMediationServiceImpl.class);
36       
37   // Max age defined in seconds
38      protected int configurationParameterCacheMaxSize = 200;
39      protected int configurationParameterCacheMaxAgeSeconds = 3600;
40      protected int nonDatabaseComponentsCacheMaxSize = 50;
41      protected int nonDatabaseComponentsCacheMaxAgeSeconds = 3600;
42  
43      protected HashMap<String,MaxAgeSoftReference<String>> configurationParameterCache = new HashMap<String,MaxAgeSoftReference<String>>( configurationParameterCacheMaxSize );
44      protected HashMap<String,MaxAgeSoftReference<List<ParameterDetailType>>> nonDatabaseComponentsCache = new HashMap<String,MaxAgeSoftReference<List<ParameterDetailType>>>( nonDatabaseComponentsCacheMaxSize );
45      protected HashMap<String,MaxAgeSoftReference<RiceApplicationConfigurationService>> responsibleServiceByPackageClass = new HashMap<String,MaxAgeSoftReference<RiceApplicationConfigurationService>>( configurationParameterCacheMaxSize );
46      
47      public String getConfigurationParameter( String namespaceCode, String parameterName ){
48      	
49      	String parameterValue = null;
50      	if ( namespaceCode != null ) {
51      	    String parameterKey = (new StringBuffer(namespaceCode).append("|").append(parameterName)).toString();
52      	    parameterValue = getParameterValueFromConfigurationParameterCache( parameterKey );
53      	    if ( parameterValue != null ) {
54                  return parameterValue;
55              }
56      	    NamespaceService nsService = KNSServiceLocator.getNamespaceService();
57      	    String applicationNamespaceCode = null;
58      	    Namespace namespace = nsService.getNamespace(namespaceCode);
59      	    if (namespace != null) {
60      	        applicationNamespaceCode = namespace.getApplicationNamespaceCode();
61      	    } else {
62      	        applicationNamespaceCode = namespaceCode;
63      	    }
64  			if (applicationNamespaceCode != null) {
65  				RiceApplicationConfigurationService rac = findRiceApplicationConfigurationService(applicationNamespaceCode);
66  				if (rac != null) {
67  					parameterValue = rac.getConfigurationParameter(parameterName);
68  				}
69  			}
70  			if (parameterValue != null){
71  				synchronized (configurationParameterCache) {
72  				    configurationParameterCache.put( parameterKey, new MaxAgeSoftReference<String>( configurationParameterCacheMaxAgeSeconds, parameterValue ) );
73  				}
74  			}
75  		}
76      	return parameterValue;
77      }
78      
79  
80      protected String getParameterValueFromConfigurationParameterCache(String parameterKey) {
81          if (configurationParameterCache == null) {
82              configurationParameterCache = new HashMap<String,MaxAgeSoftReference<String>>( configurationParameterCacheMaxSize );
83          }
84          MaxAgeSoftReference<String> parameterValue = configurationParameterCache.get( parameterKey );
85          if ( parameterValue != null ) {
86              return parameterValue.get();
87          }
88          return null;
89      }
90      
91      protected List<ParameterDetailType> getComponentListFromNonDatabaseComponentsCache(String nonDatabaseServiceNameKey) {
92          if (nonDatabaseComponentsCache == null) {
93              nonDatabaseComponentsCache =  new HashMap<String,MaxAgeSoftReference<List<ParameterDetailType>>>( nonDatabaseComponentsCacheMaxSize );
94          }
95          MaxAgeSoftReference<List<ParameterDetailType>> nonDatabaseComponent = nonDatabaseComponentsCache.get( nonDatabaseServiceNameKey );
96          if ( nonDatabaseComponent != null ) {
97              return nonDatabaseComponent.get();
98          }
99          return null;
100     }
101 
102     public List<ParameterDetailType> getNonDatabaseComponents() {
103     	
104 		// TODO I think the code that's below here will actually pull in more than
105 		// one reference to a particular application's config service if it is deployed
106 		// in a cluster, it needs to only pull a single RiceApplicationConfigurationService
107 		// implementation per service namespace.  Also, may want to consider load balancing
108 		// and failover in those cases?  It might be best to try and utilize the client-side
109 		// KSB proxies that handle a lot of this stuff for us
110     	
111 
112     	RemoteResourceServiceLocator remoteResourceServiceLocator = KSBResourceLoaderFactory.getRemoteResourceLocator();
113     	List<QName> serviceNames = remoteResourceServiceLocator.getServiceNamesForUnqualifiedName(KNSServiceLocator.RICE_APPLICATION_CONFIGURATION_SERVICE);
114 		
115 		List<ParameterDetailType> nonDatabaseComponents = new ArrayList<ParameterDetailType>();
116 		//add cache per serviceName
117 		for ( QName serviceName : serviceNames ) {
118 		    List<ParameterDetailType> nonDatabaseComponentFromCache = this.getComponentListFromNonDatabaseComponentsCache(serviceName.toString());
119 	        if (nonDatabaseComponentFromCache != null) {
120 	            nonDatabaseComponents.addAll(nonDatabaseComponentFromCache);
121 	        } else {
122     			RiceApplicationConfigurationService rac = findRiceApplicationConfigurationService(serviceName);
123     			try {
124         			if (rac != null) {
125         				nonDatabaseComponents.addAll(rac.getNonDatabaseComponents());
126         				synchronized (nonDatabaseComponentsCache) {
127             	            nonDatabaseComponentsCache.put(serviceName.toString(), new MaxAgeSoftReference<List<ParameterDetailType>>( nonDatabaseComponentsCacheMaxAgeSeconds, rac.getNonDatabaseComponents() ));
128     					}
129         			}
130     			} catch (Exception e) {
131     			    //TODO : Need a better way to catch if service is not active (404 error)
132     			    LOG.warn("Invalid RiceApplicationConfigurationService with name: " + serviceName + ".  ");
133     			}
134 	        }
135 			
136 		}
137 		
138 		return nonDatabaseComponents;
139     }
140     
141     protected RiceApplicationConfigurationService findRiceApplicationConfigurationService(QName serviceName) {
142     	try {
143     		return (RiceApplicationConfigurationService)GlobalResourceLoader.getService(serviceName);
144     	} catch (Exception e) {
145     		// if the service doesn't exist an exception is thrown
146     		LOG.warn("Failed to locate RiceApplicationConfigurationService with name: " + serviceName,e);
147     	}
148     	return null;
149     }
150     
151     protected RiceApplicationConfigurationService findRiceApplicationConfigurationService(String namespace) {
152     	try {
153     		return (RiceApplicationConfigurationService)GlobalResourceLoader.getService(new QName(namespace, KNSServiceLocator.RICE_APPLICATION_CONFIGURATION_SERVICE));
154     	} catch (Exception e) {
155     		// if the service doesn't exist an exception is thrown
156     		LOG.warn("Failed to locate RiceApplicationConfigurationService with namespace: " + namespace,e);
157     	}
158     	return null;
159     }
160 
161 
162     public void setConfigurationParameterCacheMaxSize(
163             int configurationParameterCacheMaxSize) {
164         this.configurationParameterCacheMaxSize = configurationParameterCacheMaxSize;
165     }
166 
167 
168     public void setConfigurationParameterCacheMaxAgeSeconds(
169             int configurationParameterCacheMaxAgeSeconds) {
170         this.configurationParameterCacheMaxAgeSeconds = configurationParameterCacheMaxAgeSeconds;
171     }
172 
173 
174     public void setNonDatabaseComponentsCacheMaxSize(
175             int nonDatabaseComponentsCacheMaxSize) {
176         this.nonDatabaseComponentsCacheMaxSize = nonDatabaseComponentsCacheMaxSize;
177     }
178 
179 
180     public void setNonDatabaseComponentsCacheMaxAgeSeconds(
181             int nonDatabaseComponentsCacheMaxAgeSeconds) {
182         this.nonDatabaseComponentsCacheMaxAgeSeconds = nonDatabaseComponentsCacheMaxAgeSeconds;
183     }
184     
185     /**
186      * Call each available service to see if it's responsible for the given package.  When found, cache the result
187      * to prevent need for future service lookups for the same package.
188      */
189     protected RiceApplicationConfigurationService findServiceResponsibleForPackageOrClass( String packageOrClassName ) {
190     	if ( LOG.isDebugEnabled() ) {
191     		LOG.debug( "Checking for app config service responsible for: " + packageOrClassName );
192     	}
193     	RiceApplicationConfigurationService racService = null;
194     	MaxAgeSoftReference<RiceApplicationConfigurationService> ref = responsibleServiceByPackageClass.get(packageOrClassName);
195     	if ( ref != null ) {
196     		racService = ref.get();
197     		if ( racService != null ) {
198             	if ( LOG.isDebugEnabled() ) {
199             		LOG.debug( "Service found in cache: " + racService.getClass().getName() );
200             	}    		    			
201     		}
202     	}
203     	if ( racService == null ) {
204 	    	RemoteResourceServiceLocator remoteResourceServiceLocator = KSBResourceLoaderFactory.getRemoteResourceLocator();
205 	    	List<QName> serviceNames = remoteResourceServiceLocator.getServiceNamesForUnqualifiedName(KNSServiceLocator.RICE_APPLICATION_CONFIGURATION_SERVICE);
206 			for ( QName serviceName : serviceNames ) {
207 				racService = findRiceApplicationConfigurationService(serviceName);
208 				if ( racService != null ) {
209 				
210 					try {
211 						if ( racService.isResponsibleForPackage(packageOrClassName) ) {
212 				        	if ( LOG.isDebugEnabled() ) {
213 				        		LOG.debug( "Found responsible class on bus with name: " + serviceName );
214 				        	}    		
215 							responsibleServiceByPackageClass.put(packageOrClassName, new MaxAgeSoftReference<RiceApplicationConfigurationService>( configurationParameterCacheMaxAgeSeconds, racService) );
216 							break;
217 						} else {
218 							racService = null; // null it out in case this is the last iteration
219 						}
220 					} catch (Exception e) {
221 						LOG.warn( "Assuming this racService is not responsible for the package or class.  racService: "  +
222 								racService.toString() + " ;  packageOrClassName: " + packageOrClassName);
223 					}
224 				}
225 			}
226     	}
227     	if ( racService == null ) {
228     		LOG.warn( "Unable to find service which handles package/class: " + packageOrClassName + " -- returning null." );
229     	}
230 		return racService;
231     }
232     
233     /**
234      * @see org.kuali.rice.kns.service.RiceApplicationConfigurationMediationService#getBaseInquiryUrl(java.lang.String)
235      */
236     public String getBaseInquiryUrl(String businessObjectClassName) {
237     	RiceApplicationConfigurationService racService = findServiceResponsibleForPackageOrClass(businessObjectClassName);
238     	if ( racService != null ) {
239     		return racService.getBaseInquiryUrl(businessObjectClassName);
240     	}
241     	return null;
242     }
243 
244     /**
245      * @see org.kuali.rice.kns.service.RiceApplicationConfigurationMediationService#getBaseLookupUrl(java.lang.String)
246      */
247     public String getBaseLookupUrl(String businessObjectClassName) {
248     	RiceApplicationConfigurationService racService = findServiceResponsibleForPackageOrClass(businessObjectClassName);
249     	if ( racService != null ) {
250     		return racService.getBaseLookupUrl(businessObjectClassName);
251     	}
252     	return null;
253     }
254     
255     /**
256      * @see org.kuali.rice.kns.service.RiceApplicationConfigurationMediationService#getBaseHelpUrl(java.lang.String)
257      */
258     public String getBaseHelpUrl(String businessObjectClassName) {
259     	RiceApplicationConfigurationService racService = findServiceResponsibleForPackageOrClass(businessObjectClassName);
260     	if ( racService != null ) {
261     		return racService.getBaseHelpUrl(businessObjectClassName);
262     	}
263     	return null;
264     }
265     
266     /**
267      * @see org.kuali.rice.kns.service.RiceApplicationConfigurationMediationService#getBusinessObjectAttributeDefinition(java.lang.String, java.lang.String)
268      */
269     public AttributeDefinition getBusinessObjectAttributeDefinition(String businessObjectClassName, String attributeName) {
270     	if ( LOG.isDebugEnabled() ) {
271     		LOG.debug( "Querying for an AttributeDefinition for: " + businessObjectClassName + " / " + attributeName );
272     	}
273     	RiceApplicationConfigurationService racService = findServiceResponsibleForPackageOrClass(businessObjectClassName);
274     	if ( racService != null ) {
275     		return racService.getBusinessObjectAttributeDefinition(businessObjectClassName, attributeName);
276     	}
277     	return null;
278     }
279     
280 }