Masquerade - AppMenu.openItem()

Can I get some more information on the AppMenu.openItem() methods? The documentation on them is sparse. When trying to open a screen with the openItem() method, my results show that the framework is trying to find this element span[contains(@class, 'v-menubar-menuitem') and @cuba-id="operations"]} but I am using a SideMenu which would not have the v-menubar-menuitem CSS class. How can I configure it to look for a side menu?

Or rather, is there a built-in way to do so without writing my own implementation of the AppMenu interface?

This component works only for horizontal menu. AFAIK there is no Masquerade component for SideMenu.

It appears that you are correct that there is no Masquerade component for the SideMenu. It does appear, though, that I would be able to define my own components and use them.

In Components.java, I find this:

ComponentConfig defaultConfig = new DefaultComponentConfig();
components.putAll(defaultConfig.getComponents());

// import implementations from project
ServiceLoader<ComponentConfig> configs = ServiceLoader.load(ComponentConfig.class);
for (ComponentConfig componentConfig : configs) {
    LoggerFactory.getLogger(Components.class)
            .info("Loading components from {}", componentConfig.getClass());
    components.putAll(componentConfig.getComponents());
}

This leads me to think I can

  1. Define some new Masquerade components, 2. Create a new implementation of ComponentConfig that returns a map of my custom components and 3. Those components will be made available as part of the components map above and can therefore be used in my tests. But I haven’t managed to get that to work.

Attached are my SideAppMenu interface, my SideAppMenu implementation, and my ComponentConfig implementation. I tried to replicate the AppMenu component and all I was able to find were those three files. When I try to use my SideAppMenu form a test (SideAppMenu sideMenu = _$(SideAppMenu.class);) I get

java.lang.RuntimeException: Unable to instantiate composite com.company.deiproductconfig2.composite.customComponents.SideAppMenu
	at com.haulmont.masquerade.Components.wireClassBy(Components.java:145)
	at com.haulmont.masquerade.Components.wire(Components.java:78)
	at com.haulmont.masquerade.Components._$(Components.java:98)

This leads me to believe that my component is not being added to the components map correctly. Am I doing something wrong here?

I am on 6.10.13

DEIComponentConfig.java (562 Bytes) SideAppMenu.java (1.0 KB) SideAppMenuImpl.java (2.1 KB)

You should register you custom config using Java ServiceLoader rules: https://docs.oracle.com/javase/9/docs/api/java/util/ServiceLoader.html

Deploying service providers on the class path

A service provider that is packaged as a JAR file for the class path is identified by placing a provider-configuration file in the resource directory META-INF/services . The name of the provider-configuration file is the fully qualified binary name of the service. The provider-configuration file contains a list of fully qualified binary names of service providers, one per line.

For example, suppose the service provider com.example.impl.StandardCodecs is packaged in a JAR file for the class path. The JAR file will contain a provider-configuration file named:

META-INF/services/com.example.CodecFactory

Here you should use filename equal to FQN of ComponentConfig class.

that contains the line:

com.example.impl.StandardCodecs # Standard codecs

And here you need to use FQN of your custom config.

Excellent information. I was not aware of this requirement (however, now I know it is stated in the ComponentConfig.java docs).

I’ve been playing with this but I still haven’t cracked it. When I open the modules/web/web/META-INF/services/com.haulmont.masquerade.config.ComponentConfig file in the Studio, it tells me this:
image
The link you shared above states something about the Service Implementation coming from a JAR. Do I have to bundle my custom components into a separate JAR? That seems too complicated so I’m inclined to think that there has to be a simpler way. It is obvious that the team at Haulmont (may they live long and prosper) designed the Masquerade framework to be extensible as evidenced by the notes in the ComponentConfig interface. Could we get either an example project here or an addition to the Masquerade demo project illustrating how to include and use a custom component into the Masquerade framework?

I have so far found the need to implement a SideMenu component and a TokenList component. If I can make this work I’ll glad share the source to my components.

Note: I renamed my ComponentConfig implementation to SideAppMenuComponentConfig, just so that isn’t pointed out as the issue.

Hi,
You should place service declaration to the source root of the module which has compile dependency from the masquerade. Place it to the src/META-INF/services folder, not to the “web/META-INF/…” folder which is not a source root.

This is screenshot how the service file is placed in my tests project:
image

Note that UI tests can be located in an independent project. It gives you more flexibility, e.g. you can give QA automation engineers the access to the tests project but not to the main source code.

1 Like

I just want to add that if you write tests right in web module, you should add file to modules/web/test/META-INF/services, otherwise the file will be packed to your production JAR.

That’s what I was missing. I am, in fact, running tests from the web module, mostly because I was replicating the demo project. I was putting the services folder in the modules/web/META-INF folder. I didn’t even think of creating a modules/web/test/META-INF folder.