Downloads Documentation Community Contribute Demo






Show Sidebar
Login | Register

root/openmrs/trunk/src/api/org/openmrs/api/context/ServiceContext.java

Revision 4358, 18.5 kB (checked in by bwolfe, 3 months ago)

Merging api-refactoring to trunk [3595]:[4355]

  • Property svn:eol-style set to CRLF
Line 
1 /**
2  * The contents of this file are subject to the OpenMRS Public License
3  * Version 1.0 (the "License"); you may not use this file except in
4  * compliance with the License. You may obtain a copy of the License at
5  * http://license.openmrs.org
6  *
7  * Software distributed under the License is distributed on an "AS IS"
8  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
9  * License for the specific language governing rights and limitations
10  * under the License.
11  *
12  * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
13  */
14 package org.openmrs.api.context;
15
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19
20 import org.aopalliance.aop.Advice;
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.openmrs.api.APIException;
24 import org.openmrs.api.AdministrationService;
25 import org.openmrs.api.CohortService;
26 import org.openmrs.api.ConceptService;
27 import org.openmrs.api.DataSetService;
28 import org.openmrs.api.EncounterService;
29 import org.openmrs.api.FormService;
30 import org.openmrs.api.LocationService;
31 import org.openmrs.api.ObsService;
32 import org.openmrs.api.OrderService;
33 import org.openmrs.api.PatientService;
34 import org.openmrs.api.PatientSetService;
35 import org.openmrs.api.PersonService;
36 import org.openmrs.api.ProgramWorkflowService;
37 import org.openmrs.api.ReportService;
38 import org.openmrs.api.UserService;
39 import org.openmrs.arden.ArdenService;
40 import org.openmrs.hl7.HL7Service;
41 import org.openmrs.logic.LogicService;
42 import org.openmrs.notification.AlertService;
43 import org.openmrs.notification.MessageService;
44 import org.openmrs.reporting.ReportObjectService;
45 import org.openmrs.scheduler.SchedulerService;
46 import org.openmrs.util.OpenmrsClassLoader;
47 import org.springframework.aop.Advisor;
48 import org.springframework.aop.framework.ProxyFactory;
49
50 /**
51  * Represents an OpenMRS <code>Service Context</code>, which returns the
52  * services represented throughout the system. 
53  *
54  * This class should not be access directly, but rather used through the
55  * <code>Context</code> class.
56  *
57  * This class is essentially static and only one instance is kept because
58  * this is fairly heavy-weight. Spring takes care of filling in the actual
59  * service implementations via dependency injection.  See the
60  * /metadata/api/spring/applicationContext-service.xml file.
61  *
62  * Module services are also accessed through this class.  See
63  * {@link #getService(Class)}
64  *
65  * @see org.openmrs.api.context.Context
66  */
67 public class ServiceContext {
68
69         private static final Log log = LogFactory.getLog(ServiceContext.class);
70        
71         private static ServiceContext instance;
72         private Boolean refreshingContext = new Boolean(false);
73        
74         /**
75          * Static variable holding whether or not to use the system classloader.
76          * By default this is false so the openmrs classloader is used instead
77          */
78         private boolean useSystemClassLoader = false;
79        
80         // proxy factories used for programatically adding spring AOP 
81         @SuppressWarnings("unchecked")
82     Map<Class, ProxyFactory> proxyFactories = new HashMap<Class, ProxyFactory>();
83
84         /**
85          * The default constructor is private so as to keep only one instance
86          * per java vm.
87          *
88          * @see ServiceContext#getInstance()
89          */
90         private ServiceContext() {
91                 log.debug("Instantiating service context");
92         }
93        
94         /**
95          * There should only be one ServiceContext per openmrs (java virtual machine).
96          *
97          * This method should be used when wanting to fetch the service context
98          *
99          * Note: The ServiceContext shouldn't be used independently.  All calls
100          * should go through the Context
101          *
102          * @return This VM's current ServiceContext.
103          *
104          * @see org.openmrs.api.context.Context
105          */
106         public static ServiceContext getInstance() {
107                 if (instance == null)
108                         instance = new ServiceContext();
109                
110                 return instance;
111         }
112        
113         /**
114          * Null out the current instance of the ServiceContext.  This should be used
115          * when modules are refreshing (being added/removed) and/or openmrs is shutting down
116          */
117         @SuppressWarnings("unchecked")
118     public static void destroyInstance() {
119                 if (instance != null && instance.proxyFactories != null) {
120                         if (log.isDebugEnabled()) {
121                                 for (Map.Entry<Class, ProxyFactory> entry : instance.proxyFactories.entrySet()) {
122                                         log.debug("Class:ProxyFactory - " + entry.getKey().getName() + ":" + entry.getValue());
123                                 }
124                         }
125                        
126                         if (instance.proxyFactories != null)
127                                 instance.proxyFactories.clear();
128                        
129                         instance.proxyFactories = null;
130                 }
131                
132                 if (log.isDebugEnabled())
133                         log.debug("Destroying ServiceContext instance: " + instance);
134                
135                 instance = null;
136         }
137
138         /**
139          * @return encounter-related services
140          */
141         public EncounterService getEncounterService() {
142                 return (EncounterService)getService(EncounterService.class);
143         }
144        
145         /**
146          * @return location services
147          */
148         public LocationService getLocationService() {
149                 return (LocationService)getService(LocationService.class);
150         }
151
152         /**
153          * @return observation services
154          */
155         public ObsService getObsService() {
156                 return (ObsService)getService(ObsService.class);
157         }
158
159         /**
160          * @return patientset-related services
161          */
162         public PatientSetService getPatientSetService() {
163                 return (PatientSetService)getService(PatientSetService.class);
164         }
165        
166         /**
167          * @return cohort related service
168          */
169         public CohortService getCohortService() {
170                 return (CohortService) getService(CohortService.class);
171         }
172        
173         /**
174          * @param cohort related service
175          */
176         public void setCohortService(CohortService cs) {
177                 setService(CohortService.class, cs);
178         }
179
180         /**
181          * @return order service
182          */
183         public OrderService getOrderService() {
184                 return (OrderService)getService(OrderService.class);
185         }
186
187         /**
188          * @return form service
189          */
190         public FormService getFormService() {
191                 return (FormService)getService(FormService.class);
192         }
193
194         /**
195          * @return report object service
196          */
197         public ReportObjectService getReportObjectService() {
198                 return (ReportObjectService)getService(ReportObjectService.class);
199         }
200        
201         /**
202          * @return report service
203          */
204         public ReportService getReportService() {
205                 return (ReportService) getService(ReportService.class);
206         }
207
208         /**
209          * @return admin-related services
210          */
211         public AdministrationService getAdministrationService() {
212                 return (AdministrationService)getService(AdministrationService.class);
213         }
214        
215
216         /**
217          * @return programWorkflowService
218          */
219         public ProgramWorkflowService getProgramWorkflowService() {
220                 return (ProgramWorkflowService)getService(ProgramWorkflowService.class);
221         }
222        
223         /**
224          * @return ardenService
225          */
226         public ArdenService getArdenService() {
227                 return (ArdenService)getService(ArdenService.class);
228         }
229        
230         /**
231          * @return logicService
232          */
233         public LogicService getLogicService() {
234                 return (LogicService)getService(LogicService.class);
235         }
236
237         /**
238          * @return scheduler service
239          */
240         public SchedulerService getSchedulerService() {
241                 return (SchedulerService)getService(SchedulerService.class);
242         }
243
244         /**
245          * Set the scheduler service.
246          *
247          * @param service
248          */
249         public void setSchedulerService(SchedulerService schedulerService) {
250                 setService(SchedulerService.class, schedulerService);
251         }       
252
253         /**
254          * @return alert service
255          */
256         public AlertService getAlertService() {
257                 return (AlertService)getService(AlertService.class);
258         }
259
260         /**
261          * @param alertService
262          */
263         public void setAlertService(AlertService alertService) {
264                 setService(AlertService.class, alertService);
265         }
266
267         /**
268          * @param programWorkflowService
269          */
270         public void setProgramWorkflowService(ProgramWorkflowService programWorkflowService) {
271                 setService(ProgramWorkflowService.class, programWorkflowService);
272         }
273        
274         /**
275          * @param ardenService
276          */
277         public void setArdenService(ArdenService ardenService) {
278                 setService(ArdenService.class, ardenService);
279         }
280        
281         /**
282          * @param logicService
283          */
284         public void setLogicService(LogicService logicService) {
285                 setService(LogicService.class, logicService);
286         }
287
288        
289         /**
290          * @return message service
291          */
292         public MessageService getMessageService() {
293                 return (MessageService)getService(MessageService.class);
294         }
295        
296         /**
297          * Sets the message service.
298          *
299          * @param service
300          */
301         public void setMessageService(MessageService messageService) {
302                 setService(MessageService.class, messageService);
303         }
304
305         /**
306          * @return the hl7Service
307          */
308         public HL7Service getHL7Service() {
309                 return (HL7Service)getService(HL7Service.class);
310         }
311
312         /**
313          * @param hl7Service the hl7Service to set
314          */
315         // TODO spring is demanding that this be hl7Service:setHl7Service and not hL7Service:setHL7Service. why?
316         public void setHl7Service(HL7Service hl7Service) {
317                 setService(HL7Service.class, hl7Service);
318         }
319
320         /**
321          * @param administrationService the administrationService to set
322          */
323         public void setAdministrationService(AdministrationService administrationService) {
324                 setService(AdministrationService.class, administrationService);
325         }
326
327         /**
328          * @param encounterService the encounterService to set
329          */
330         public void setEncounterService(EncounterService encounterService) {
331                 setService(EncounterService.class, encounterService);
332         }
333
334         /**
335          * @param locationService the LocationService to set
336          */
337         public void setLocationService(LocationService locationService) {
338                 setService(LocationService.class, locationService);
339         }
340        
341         /**
342          * @param formService the formService to set
343          */
344         public void setFormService(FormService formService) {
345                 setService(FormService.class, formService);
346         }
347
348         /**
349          * @param obsService the obsService to set
350          */
351         public void setObsService(ObsService obsService) {
352                 setService(ObsService.class, obsService);
353         }
354
355         /**
356          * @param orderService the orderService to set
357          */
358         public void setOrderService(OrderService orderService) {
359                 setService(OrderService.class, orderService);
360         }
361
362         /**
363          * @param patientSetService the patientSetService to set
364          */
365         public void setPatientSetService(PatientSetService patientSetService) {
366                 setService(PatientSetService.class, patientSetService);
367         }
368
369         /**
370          * @param reportObjectService the reportObjectService to set
371          */
372         public void setReportObjectService(ReportObjectService reportObjectService) {
373                 setService(ReportObjectService.class, reportObjectService);
374         }
375        
376         /**
377          * @param reportService
378          */
379         public void setReportService(ReportService reportService) {
380                 setService(ReportService.class, reportService);
381         }
382        
383         /**
384          * @param dataSetService
385          */
386         public void setDataSetService(DataSetService dataSetService) {
387                 setService(DataSetService.class, dataSetService);
388         }
389
390         /**
391          * @return
392          */
393         public DataSetService getDataSetService() {
394                 return (DataSetService) getService(DataSetService.class);
395         }
396
397         /**
398          * @return patient related services
399          */
400         public PatientService getPatientService() {
401                 return (PatientService)getService(PatientService.class);
402         }
403        
404         /**
405          * @param patientService the patientService to set
406          */
407         public void setPatientService(PatientService patientService) {
408                 setService(PatientService.class, patientService);
409         }
410        
411         /**
412          * @return person related services
413          */
414         public PersonService getPersonService() {
415                 return (PersonService)getService(PersonService.class);
416         }
417        
418         /**
419          * @param personService the personService to set
420          */
421         public void setPersonService(PersonService personService) {
422                 setService(PersonService.class, personService);
423         }
424        
425         /**
426          * @return concept related services
427          */
428         public ConceptService getConceptService() {
429                 return (ConceptService)getService(ConceptService.class);
430         }
431        
432         /**
433          * @param conceptService the conceptService to set
434          */
435         public void setConceptService(ConceptService conceptService) {
436                 setService(ConceptService.class, conceptService);
437         }
438        
439         /**
440          * @return user-related services
441          */
442         public UserService getUserService() {
443                 return (UserService)getService(UserService.class);
444         }
445        
446         /**
447          * @param userService the userService to set
448          */
449         public void setUserService(UserService userService) {
450                 setService(UserService.class, userService);
451         }
452        
453         /**
454          * Get the proxy factory object for the given Class
455          * @param cls
456          * @return
457          */
458         @SuppressWarnings("unchecked")
459     private ProxyFactory getFactory(Class cls) {
460                 ProxyFactory factory = proxyFactories.get(cls);
461                 if (factory == null)
462                         throw new APIException("A proxy factory for: '" + cls + "' doesn't exist");
463                 return factory;
464         }
465        
466         /**
467          *
468          * @param cls
469          * @param advisor
470          */
471         @SuppressWarnings("unchecked")
472     public void addAdvisor(Class cls, Advisor advisor) {
473                 ProxyFactory factory = getFactory(cls);
474                 factory.addAdvisor(advisor);
475         }
476        
477         /**
478          *
479          * @param cls
480          * @param advice
481          */
482         @SuppressWarnings("unchecked")
483     public void addAdvice(Class cls, Advice advice) {
484                 ProxyFactory factory = getFactory(cls);
485                 factory.addAdvice(advice);
486         }
487        
488         /**
489          *
490          * @param cls
491          * @param advisor
492          */
493         @SuppressWarnings("unchecked")
494     public void removeAdvisor(Class cls, Advisor advisor) {
495                 ProxyFactory factory = getFactory(cls);
496                 factory.removeAdvisor(advisor);
497         }
498        
499         /**
500          *
501          * @param cls
502          * @param advice
503          */
504         @SuppressWarnings("unchecked")
505     public void removeAdvice(Class cls, Advice advice) {
506                 ProxyFactory factory = getFactory(cls);
507                 factory.removeAdvice(advice);
508         }
509        
510         /**
511          * Returns the current proxy that is stored for the
512          * Class <code>cls</code>
513          *
514          * @param cls
515          * @return Object that is a proxy for the <code>cls</code> class
516          */
517         @SuppressWarnings("unchecked")
518     public Object getService(Class cls) {
519                 if (log.isTraceEnabled())
520                         log.trace("Getting service: " + cls);
521                
522                 // if the context is refreshing, wait until it is
523                 // done -- otherwise a null service might be returned
524                 synchronized (refreshingContext) {
525                         if (refreshingContext.booleanValue())
526                                 try {
527                                         log.warn("Waiting to get service: " + cls + " while the context is being refreshed");
528                                         refreshingContext.wait();
529                                         log.warn("Finished waiting to get service " + cls + " while the context was being refreshed");
530                                 }
531                                 catch (InterruptedException e) {
532                                         log.warn("Refresh lock was interrupted", e);
533                                 }
534                 }
535                
536                 ProxyFactory factory = proxyFactories.get(cls);
537                 if (factory == null)
538                         throw new APIException("Service not found: " + cls);
539                
540                 return factory.getProxy(OpenmrsClassLoader.getInstance());
541         }
542
543         /**
544          * Allow other services to be added to our service layer
545          *
546          * @param cls Interface to proxy
547          * @param classInstance the actual instance of the <code>cls</code> interface
548          */
549         @SuppressWarnings("unchecked")
550     public void setService(Class cls, Object classInstance) {
551                
552                 log.debug("Setting service: " + cls);
553                
554                 if (cls != null && classInstance != null) {
555                         try {
556                                 Class[] interfaces = {cls};
557                                 ProxyFactory factory = new ProxyFactory(interfaces);
558                                 factory.setTarget(classInstance);
559                                 proxyFactories.put(cls, factory);
560                                 log.debug("Service: " + cls + " set successfully");
561                         }
562                         catch (Exception e) {
563                                 throw new APIException("Unable to create proxy factory for: " + classInstance.getClass().getName(), e);
564                         }
565                        
566                 }
567         }
568        
569         /**
570          * Allow other services to be added to our service layer
571          *
572          * Classes will be found/loaded with the ModuleClassLoader
573          *
574          * <code>params</code>[0] = string representing the service interface
575          * <code>params</code>[1] = service instance
576          *
577          * @param list list of parameters
578          */
579         @SuppressWarnings("unchecked")
580     public void setModuleService(List<Object> params) {
581                 String classString = (String)params.get(0);
582                 Object classInstance = params.get(1);
583                
584                 if (classString == null || classInstance == null) {
585                         throw new APIException("Unable to find classString or classInstance in params");
586                 }
587                
588                 Class cls = null;
589                
590                 // load the given 'classString' class from either the openmrs class
591                 // loader or the system class loader depending on if we're in a testing
592                 // environment or not (system == testing, openmrs == normal)
593                 try {
594                         if (useSystemClassLoader == false) {
595                                 cls = OpenmrsClassLoader.getInstance().loadClass(classString);
596                        
597                                 if (cls != null && log.isDebugEnabled()) {
598                                         try {
599                                                 log.debug("cls classloader: " + cls.getClass().getClassLoader() + " uid: " + cls.getClass().getClassLoader().hashCode());
600                                         }
601                                         catch (Exception e) { /*pass*/ }
602                                 }
603                         }
604                         else if (useSystemClassLoader == true) {
605                                 try {
606                                         cls = Class.forName(classString);
607                                         if (log.isDebugEnabled()) {
608                                                 log.debug("cls2 classloader: " + cls.getClass().getClassLoader() + " uid: " + cls.getClass().getClassLoader().hashCode());
609                                                 log.debug("cls==cls2: " + String.valueOf(cls == cls));
610                                         }
611                                 }
612                                 catch (Exception e) { /*pass*/ }
613                         }
614                 }
615                 catch (ClassNotFoundException e) {
616                         throw new APIException("Unable to set module service: " + classString, e);
617                 }
618                
619                 // add this module service to the normal list of services
620                 setService(cls, classInstance);
621         }
622        
623         /**
624          * Set this service context to use the system class loader if the
625          * <code>useSystemClassLoader</code> is set to true.  If false, the openmrs
626          * class loader is used to load module services
627          *
628          * @param useSystemClassLoader true/false whether to use the system class loader
629          */
630         public void setUseSystemClassLoader(boolean useSystemClassLoader) {
631                 this.useSystemClassLoader = useSystemClassLoader;
632         }
633        
634         /**
635          * Should be called <b>right before</b> any spring context refresh
636          *
637          * This forces all calls to getService to wait until
638          * <code>doneRefreshingContext</code> is called
639          */
640         public void startRefreshingContext() {
641                 synchronized (refreshingContext) {
642                         refreshingContext = true;
643                 }
644         }
645        
646         /**
647          * Should be called <b>right after</b> any spring context refresh
648          *
649          * This wakes up all calls to getService that were waiting
650          * because <code>startRefreshingContext</code> was called
651          */     
652         public void doneRefreshingContext() {
653                 synchronized(refreshingContext) {
654                         refreshingContext.notifyAll();
655                         refreshingContext = false;
656                 }
657         }
658        
659         /**
660          * Returns true/false whether startRefreshingContext() has been called
661          * without a subsequent call to doneRefreshingContext() yet.  All methods
662          * involved in starting/stopping a module should call this if a service
663          * method is needed -- otherwise a deadlock will occur.
664          *
665          * @return true/false whether the services are currently blocking waiting
666          *                      for a call to doneRefreshingContext()
667          */
668         public boolean isRefreshingContext() {
669                 return refreshingContext.booleanValue();
670         }
671        
672 }
Note: See TracBrowser for help on using the browser.