[SOLVED] Overriding Module Fragments in other modules

Is there a design approach or methodology for overriding module pages and fragments within the reference application & 1.11.x?

I am thinking along the following lines - so please advise:

  1. Example of Override of Login Page (RA) - if there is a way of checking a context value to forward to with the default fall back to the RA one. Maybe defined via JSON the same way apps are configured

  2. Filters to be extended to provide context values in the webApplicationContext.xml - not sure about class loading issues here

  3. Global Properties are overkill and would clutter the namespace

  4. Can I provide configuration for a fragment in a custom module that overrides one provided by a core module.

Thanks in advance

I built a mechanism that could handle this into the UI Framework long ago. I don’t know if it has ever been used, but it should work.

In your module, you would implement this interface a @Component:

There is no equivalent mechanism for overriding fragment requests, but I think it would be straightforward for you to add this to the uiframework module following the pattern that is there for page request mapper.

How can I use this to override a request to another page?

Say for example login.htm goes to "forward:/referenceapplication/login.page"

I suggest trying to just do the override such that if the request is for provider=referenceapplication and page=login then you override with your custom page.

(I haven’t tried this, but I assume it should work with a forward: as well.)

Let me try that out.

I have gotten my mapper up and running called on login.htm, but have no idea when it is invoked to step through to find out what may be wrong

Try putting a breakpoint here, in the UI Framework module:

On successfully overidding the mapping the exception I ran into is having two controllers mapped to the same url in this case login.htm for both the Ref App Login page controller and my controller see gist:

This is a Spring-related error, i.e. Spring won’t allow you to bind two controllers to the same address (/login.htm).

If your module is an add-on on top of the reference application, then you don’t need to use @Controller to map that url, but rather let the reference application module map that url to /referenceapplication/login.page, and then use the override mechanism to override that page with one of your own.

If you need your module to capture this url either with our without the reference application module loaded, then you’ll have to add something new to cover that case.

Thanks a bunch this works like a charm…

I am working on adding support for overriding fragments using a FragmentRequestMapper via

however I need help on where to add the RequestMapper to the FragmentFactory or PageFactory as I have very little knowledge of the internal mechanics of the framework and I am not yet well setup to walk through an OpenMRS request using a debugger

from a very quick glance at the code I think you’ll need to make changes to FragmentFactory.process (or maybe processThisFragment)

Thanks works like a charm…

@darius I have run into an interesting challenge, I have two different page request mappers in 2 custom modules - however it seems that only one of the mappers is active at any time.

It looks like the request mapper definitions are being overwritten across modules unlike what is expected by the core spring functionality which collects all beans of a specific interface. Any ideas on how to deal with this?

@ssmusoke do you mean 2 request mappers in different modules for the same page or different pages?

@wyclif different Request mappers for different pages. Thanks to @dkayiwa who found that I have both request mappers returning true all the time so only one was executing in the chain. I will update the wiki documentation to reflect this gotcha

I would assume that if the mappers are for different pages, then they shouldn’t affect each other and if they do I would think that’s a bug regardless of if they return true

An example is below, which breaks the chain randomly wherever this mapper appears in the chain, since a true value stops the processing of the chain

`public boolean mapRequest(PageRequest request) {
	if (request.getProviderName().equals("reportingui")) {
		if (request.getPageName().equals("reportsapp/home")) {
			request.setProviderNameOverride("mymodule");
			request.setPageNameOverride("reportsHome");
			log.info(request.toString());
		}
	}
	return true;
}`

This method below returns true only when the override is mapped by the specific request mapper

`public boolean mapRequest(PageRequest request) {
	if (request.getProviderName().equals("reportingui")) {
		if (request.getPageName().equals("reportsapp/home")) {
			request.setProviderNameOverride("mymodule");
			request.setPageNameOverride("reportsHome");
			log.info(request.toString());
			return true;
		}
	}
	return false;
}`

Ah! I see what you’re saying, so you only need to return true when you actually do the override

@wyclif oh yes that is what happened to me and I spent hours chasing down the bug