Adding Settings

#1

Pretty new to Ignition Development
I want to add a settings page to my module, I have created an registered a PersistentRecord but it doesn’t show up anywhere in the settings page.
What am I missing?
Here’s my current PersistentClass

package com.jnjdodev.ignition.modules.websocket;

import com.inductiveautomation.ignition.gateway.localdb.persistence.Category;
import com.inductiveautomation.ignition.gateway.localdb.persistence.IdentityField;
import com.inductiveautomation.ignition.gateway.localdb.persistence.IntField;
import com.inductiveautomation.ignition.gateway.localdb.persistence.PersistentRecord;
import com.inductiveautomation.ignition.gateway.localdb.persistence.RecordMeta;


import simpleorm.dataset.SFieldFlags;

public class WebSocketsRecord extends PersistentRecord {

	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public static final RecordMeta<WebSocketsRecord> META = new RecordMeta<>(
			WebSocketsRecord.class, "WebSocketsRecord").setNounKey("WebSocketsRecord.Noun")
            .setNounPluralKey("WebSocketsRecord.Noun.Plural");

	public static final IdentityField Id = new IdentityField(META);
	
	
	 public static final IntField WebSocketPort = new IntField(META, "WebSocketPort",
	            SFieldFlags.SMANDATORY).setDefault(23333);
	@Override
	public RecordMeta<?> getMeta() {
		// TODO Auto-generated method stub
		return META;

	}
	

	public void setPort(int port)
	{
		this.setInt(WebSocketPort, port);
	}
	
	public int getPort()
	{
		return this.getInt(WebSocketPort);
	}

	static final Category SeeqServerConfiguration =
            new Category("WebSocketsRecord.Category.Configuration", 1000)
                    .include(WebSocketPort);
}

and my GatewayHook Setup

public void setup(GatewayContext context) {
		// TODO Auto-generated method stub
		this.context = context; 
		try {
			this.context.getSchemaUpdater().updatePersistentRecords(WebSocketsRecord.META);
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
0 Likes

#2

You have to construct one or more configuration pages to be shown, and override the gateway hook’s getConfigPages() method. Welcome to Wicket!

1 Like

#3

Fortunately this is pretty easy because you just extend RecordEditForm:

public class SettingsPage extends RecordEditForm {

    public SettingsPage(final IConfigPage configPage) {
        super(configPage, null, new LenientResourceModel("xopc.config.settings.paneltitle"),
            ((GatewayContext) Application.get()).getPersistenceInterface().find(
                XOPCSettingsRecord.META, 0L));
    }

    @Override
    public Pair<String, String> getMenuLocation() {
        return Pair.of(XOPCGatewayHook.OPCUA_CATEGORY.getName(), "settings");
    }

}

This is the UA module’s server settings page. There’s only ever one instance of this settings record, so it doesn’t even need to have a record passed in to the constructor.

1 Like

#4

There doesn’t appear to be a getConfigPages() in my current Hook
I’m on version 8.0.1
There appears to be a getConfigPanels()
Is this what I want?

0 Likes

#5

Ah, it changed a bit in 8.0.

Check out this example: https://github.com/inductiveautomation/ignition-sdk-examples/tree/master/gateway-webpage

0 Likes

#6

My mistake. My own v8 module I looked at overrides getConfigPanels(). And it was true for v7.9 as well.

1 Like

#7

Thanks @Kevin.Herron
Trying to follow that example I have the following now
In Hook:

@Override
    public List<ConfigCategory> getConfigCategories() {
        return Collections.singletonList(CONFIG_CATEGORY);
    }
	
	public static final ConfigCategory CONFIG_CATEGORY =
	        new ConfigCategory("WebSocket", "WebSocketHeader", 700);

	 public static final IConfigTab HCE_CONFIG_ENTRY = DefaultConfigTab.builder()
	            .category(CONFIG_CATEGORY)
	            .name("WebScocketSettings")
	            .i18n("WebSocketSettings")
	            .page(SettingsPage.class)
	            .build();
	
	 @Override
	    public List<? extends IConfigTab> getConfigPanels() {
		 return Collections.singletonList(
		            HCE_CONFIG_ENTRY
		        );
	 }

Along with the SettingsPage similar to what you suggested

public class SettingsPage extends RecordEditForm {

    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public SettingsPage(final IConfigPage configPage) {
        super(configPage, null, new LenientResourceModel("xopc.config.settings.paneltitle"),
            ((GatewayContext) Application.get()).getPersistenceInterface().find(
            		WebSocketsRecord.META, 1L));
    }

    @Override
    public Pair<String, String> getMenuLocation() {
        return Pair.of("WebSocket", "WebScocketSettings");
    }

}

And I am getting this which is progress!
image

But clicking on it just yields : Internal error

With the log having the following

Exception
org.apache.wicket.WicketRuntimeException: Can't instantiate page using constructor 'public com.inductiveautomation.ignition.gateway.web.pages.Config(org.apache.wicket.request.mapper.parameter.PageParameters)' and argument 'path=[WebSocket.WebScocketSettings]'. Might be it doesn't exist, may be it is not visible (public).

at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:193)

at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:98)

at org.apache.wicket.DefaultMapperContext.newPageInstance(DefaultMapperContext.java:137)

at org.apache.wicket.core.request.handler.PageProvider.resolvePageInstance(PageProvider.java:278)

at org.apache.wicket.core.request.handler.PageProvider.getPageInstance(PageProvider.java:166)

at org.apache.wicket.request.handler.render.PageRenderer.getPage(PageRenderer.java:78)

at org.apache.wicket.request.handler.render.WebPageRenderer.renderPage(WebPageRenderer.java:94)

at org.apache.wicket.request.handler.render.WebPageRenderer.respond(WebPageRenderer.java:244)

at org.apache.wicket.core.request.handler.RenderPageRequestHandler.respond(RenderPageRequestHandler.java:165)

at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:814)

at org.apache.wicket.request.RequestHandlerStack.execute(RequestHandlerStack.java:64)

at org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:253)

at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:210)

at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:281)

at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:188)

at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:245)

at com.inductiveautomation.ignition.gateway.bootstrap.GatewayFilter.doFilter(GatewayFilter.java:74)

at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1629)

at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)

at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)

at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)

at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)

at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:190)

at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595)

at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)

at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1253)

at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)

at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)

at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564)

at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)

at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1155)

at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)

at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:61)

at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)

at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:335)

at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:61)

at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:126)

at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)

at org.eclipse.jetty.server.Server.handle(Server.java:530)

at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:347)

at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:256)

at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)

at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)

at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)

at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:247)

at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:140)

at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)

at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:382)

at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:708)

at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:626)

at java.base/java.lang.Thread.run(Unknown Source)

Caused by: java.lang.reflect.InvocationTargetException: null

at jdk.internal.reflect.GeneratedConstructorAccessor62.newInstance(Unknown Source)

at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)

at java.base/java.lang.reflect.Constructor.newInstance(Unknown Source)

at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:170)

... 50 common frames omitted

Caused by: java.lang.RuntimeException: Unable to create config panel WebSocket.WebScocketSettings

at com.inductiveautomation.ignition.gateway.web.models.DefaultConfigTab.getPanel(DefaultConfigTab.java:99)

at com.inductiveautomation.ignition.gateway.web.pages.Config.(Config.java:109)

... 54 common frames omitted

Caused by: java.lang.reflect.InvocationTargetException: null

at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)

at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)

at java.base/java.lang.reflect.Constructor.newInstance(Unknown Source)

at com.inductiveautomation.ignition.gateway.web.models.DefaultConfigTab.getPanel(DefaultConfigTab.java:91)

... 55 common frames omitted

Caused by: java.lang.ClassCastException: class com.inductiveautomation.ignition.gateway.web.IgnitionWebAppImpl cannot be cast to class com.inductiveautomation.ignition.gateway.model.GatewayContext (com.inductiveautomation.ignition.gateway.web.IgnitionWebAppImpl and com.inductiveautomation.ignition.gateway.model.GatewayContext are in unnamed module of loader 'app')

at com.jnjdodev.ignition.modules.websocket.SettingsPage.(SettingsPage.java:20)

... 60 common frames omitted

Any suggestions as to what I’m doing wrong? I’m trying to follow that example but I can’t seem to get past this point.

Thanks!

0 Likes

#8

Correction, I see the error is that it wants IgnitionWebApp instead of GateWayContext which I’ve corrected.

New Error:

Exception
org.apache.wicket.WicketRuntimeException: Can't instantiate page using constructor 'public com.inductiveautomation.ignition.gateway.web.pages.Config(org.apache.wicket.request.mapper.parameter.PageParameters)' and argument 'path=[WebSocket.WebScocketSettings]'. Might be it doesn't exist, may be it is not visible (public).

at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:193)

at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:98)

at org.apache.wicket.DefaultMapperContext.newPageInstance(DefaultMapperContext.java:137)

at org.apache.wicket.core.request.handler.PageProvider.resolvePageInstance(PageProvider.java:278)

at org.apache.wicket.core.request.handler.PageProvider.getPageInstance(PageProvider.java:166)

at org.apache.wicket.request.handler.render.PageRenderer.getPage(PageRenderer.java:78)

at org.apache.wicket.request.handler.render.WebPageRenderer.renderPage(WebPageRenderer.java:94)

at org.apache.wicket.request.handler.render.WebPageRenderer.respond(WebPageRenderer.java:244)

at org.apache.wicket.core.request.handler.RenderPageRequestHandler.respond(RenderPageRequestHandler.java:165)

at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:814)

at org.apache.wicket.request.RequestHandlerStack.execute(RequestHandlerStack.java:64)

at org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:253)

at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:210)

at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:281)

at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:188)

at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:245)

at com.inductiveautomation.ignition.gateway.bootstrap.GatewayFilter.doFilter(GatewayFilter.java:74)

at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1629)

at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)

at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)

at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)

at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)

at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:190)

at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595)

at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)

at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1253)

at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)

at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)

at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564)

at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)

at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1155)

at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)

at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:61)

at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)

at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:335)

at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:61)

at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:126)

at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)

at org.eclipse.jetty.server.Server.handle(Server.java:530)

at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:347)

at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:256)

at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)

at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)

at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)

at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:247)

at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:140)

at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)

at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:382)

at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:708)

at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:626)

at java.base/java.lang.Thread.run(Unknown Source)

Caused by: java.lang.reflect.InvocationTargetException: null

at jdk.internal.reflect.GeneratedConstructorAccessor62.newInstance(Unknown Source)

at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)

at java.base/java.lang.reflect.Constructor.newInstance(Unknown Source)

at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:170)

... 50 common frames omitted

Caused by: java.lang.RuntimeException: Unable to create config panel WebSocket.WebScocketSettings

at com.inductiveautomation.ignition.gateway.web.models.DefaultConfigTab.getPanel(DefaultConfigTab.java:99)

at com.inductiveautomation.ignition.gateway.web.pages.Config.(Config.java:109)

... 54 common frames omitted

Caused by: java.lang.reflect.InvocationTargetException: null

at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)

at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)

at java.base/java.lang.reflect.Constructor.newInstance(Unknown Source)

at com.inductiveautomation.ignition.gateway.web.models.DefaultConfigTab.getPanel(DefaultConfigTab.java:91)

... 55 common frames omitted

Caused by: java.lang.NullPointerException: null

at com.inductiveautomation.ignition.gateway.web.models.DirectRecordListModel.(DirectRecordListModel.java:46)

at com.inductiveautomation.ignition.gateway.web.models.CompoundRecordModel.(CompoundRecordModel.java:48)

at com.inductiveautomation.ignition.gateway.web.models.CompoundRecordModel.(CompoundRecordModel.java:41)

at com.inductiveautomation.ignition.gateway.web.components.RecordEditForm.(RecordEditForm.java:65)

at com.jnjdodev.ignition.modules.websocket.SettingsPage.(SettingsPage.java:21)

... 60 common frames omitted

Still investigating

0 Likes

#9

The root cause is this:

Caused by: java.lang.ClassCastException: class com.inductiveautomation.ignition.gateway.web.IgnitionWebAppImpl cannot be cast to class com.inductiveautomation.ignition.gateway.model.GatewayContext (com.inductiveautomation.ignition.gateway.web.IgnitionWebAppImpl and com.inductiveautomation.ignition.gateway.model.GatewayContext are in unnamed module of loader 'app')

Copy the page from the example rather than the one I posted, which came from 7.9.

1 Like

#10

So now it’s having a hard time with my “Path” “WebSocket.WebScocketSettings”

org.apache.wicket.WicketRuntimeException: Can't instantiate page using constructor 'public com.inductiveautomation.ignition.gateway.web.pages.Config(org.apache.wicket.request.mapper.parameter.PageParameters)' and argument 'path=[WebSocket.WebScocketSettings]'. Might be it doesn't exist, may be it is not visible (public).

I see that’s what I’m passing to CONFIG_CATEGORY

	public static final ConfigCategory CONFIG_CATEGORY =
	        new ConfigCategory("WebSocket", "WebScocketSettings", 700);

And then I’m using that in my CONFIG_ENTRY

public static final IConfigTab HCE_CONFIG_ENTRY = DefaultConfigTab.builder()
	            .category(CONFIG_CATEGORY)
	            .name("WebScocketSettings")
	            .i18n("WebScocketSettings")
	            .page(SettingsPage.class)
	            .build();

It seems to be taking issue with that (some how) but I’m not sure I follow what it wants. Any pointers?
Sorry in advance, If i’m missing something obvious

Here is my persistence class if it matters

package com.jnjdodev.ignition.modules.websocket;

import com.inductiveautomation.ignition.gateway.localdb.persistence.Category;
import com.inductiveautomation.ignition.gateway.localdb.persistence.IdentityField;
import com.inductiveautomation.ignition.gateway.localdb.persistence.IntField;
import com.inductiveautomation.ignition.gateway.localdb.persistence.PersistentRecord;
import com.inductiveautomation.ignition.gateway.localdb.persistence.RecordMeta;


import simpleorm.dataset.SFieldFlags;

public class WebSocketsRecord extends PersistentRecord {

	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public static final RecordMeta<WebSocketsRecord> META = new RecordMeta<>(
			WebSocketsRecord.class, "WebSocketsRecord").setNounKey("WebSocketsRecord.Noun")
            .setNounPluralKey("WebSocketsRecord.Noun.Plural");

	public static final IdentityField Id = new IdentityField(META);
	
	
	 public static final IntField WebSocketPort = new IntField(META, "WebSocketPort",
	            SFieldFlags.SMANDATORY).setDefault(23333);
	@Override
	public RecordMeta<?> getMeta() {
		// TODO Auto-generated method stub
		return META;

	}
	

	public void setPort(int port)
	{
		this.setInt(WebSocketPort, port);
	}
	
	public int getPort()
	{
		return this.getInt(WebSocketPort);
	}

	
}
0 Likes

#11

Does your SettingsPage still have the public IConfigPage constructor?

	public SettingsPage(final IConfigPage configPage) {
0 Likes

#12

Yes it does, should it not?

0 Likes

#13

It should, but the error’s indicating that it doesn’t:

org.apache.wicket.WicketRuntimeException: Can't instantiate page using constructor 'public com.inductiveautomation.ignition.gateway.web.pages.Config(org.apache.wicket.request.mapper.parameter.PageParameters)' and argument 'path=[WebSocket.WebScocketSettings]'. Might be it doesn't exist, may be it is not visible (public).

Is it just a typo? You’ve got "WebScocketSettings" in a few code snippets.

0 Likes

#14

Yeah it’s just a typo but a consistent Typo lol… I think (Double checking)

0 Likes

#15

ok So I’ve double checked everything and still can’t figure it out. I’m gonna post my files one more time hoping someone can see what I’m missing.

SettingsPage.java
I’m using LenientResourceModel(“xopc.config.settings.paneltitle”) from above not sure if that’s right or what exactly does it mean? Examples seems to have their own?

public class SettingsPage extends RecordEditForm {

    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public static final Pair<String, String> MENU_LOCATION =
	        Pair.of(WebSocketGatewayHook.CONFIG_CATEGORY.getName(), "Settings");

	
	public SettingsPage(final IConfigPage configPage) {
        super(configPage, null, new LenientResourceModel("xopc.config.settings.paneltitle"),
            ((IgnitionWebApp) Application.get()).getContext().getPersistenceInterface().find(
            		WebSocketsRecord.META, 0L));
    }

    @Override
    public Pair<String, String> getMenuLocation() {
    	return MENU_LOCATION;
    }

}

My persistance Record

package com.jnjdodev.ignition.modules.websocket;


import com.inductiveautomation.ignition.gateway.localdb.persistence.Category;
import com.inductiveautomation.ignition.gateway.localdb.persistence.IdentityField;
import com.inductiveautomation.ignition.gateway.localdb.persistence.IntField;
import com.inductiveautomation.ignition.gateway.localdb.persistence.PersistentRecord;
import com.inductiveautomation.ignition.gateway.localdb.persistence.RecordMeta;


import simpleorm.dataset.SFieldFlags;

public class WebSocketsRecord extends PersistentRecord {

	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public static final RecordMeta<WebSocketsRecord> META = new RecordMeta<>(
			WebSocketsRecord.class, "WebSocketsRecord").setNounKey("WebSocketsRecord.Noun")
            .setNounPluralKey("WebSocketsRecord.Noun.Plural");

	public static final IdentityField Id = new IdentityField(META);
	
	
	 public static final IntField WebSocketPort = new IntField(META, "WebSocketPort",
	            SFieldFlags.SMANDATORY).setDefault(23333);
	@Override
	public RecordMeta<?> getMeta() {
		// TODO Auto-generated method stub
		return META;

	}
	

	public void setPort(int port)
	{
		this.setInt(WebSocketPort, port);
	}
	
	public int getPort()
	{
		return this.getInt(WebSocketPort);
	}
	
}

Hook class

public void setup(GatewayContext context) {
		// TODO Auto-generated method stub
		this.context = context; 
		try {
			this.context.getSchemaUpdater().updatePersistentRecords(WebSocketsRecord.META);
		    maybeCreateWebSocketSettings(context);
...
public void maybeCreateWebSocketSettings(GatewayContext context) {
        logger.trace("Attempting to create GitConnector Settings Record");
        try {
            WebSocketsRecord settingsRecord = context.getLocalPersistenceInterface().createNew(WebSocketsRecord.META);
            settingsRecord.setPort(23333);

            /*
             * This doesn't override existing settings, only replaces it with these if we didn't
             * exist already.
             */
            context.getSchemaUpdater().ensureRecordExists(settingsRecord);
        } catch (Exception e) {
 
        }


    }
@Override
    public List<ConfigCategory> getConfigCategories() {
        return Collections.singletonList(CONFIG_CATEGORY);
    }
	
	public static final ConfigCategory CONFIG_CATEGORY =
	        new ConfigCategory("WebSocket", "WebSocket", 700);

	 public static final IConfigTab HCE_CONFIG_ENTRY = DefaultConfigTab.builder()
	            .category(CONFIG_CATEGORY)
	            .name("Settings")
	            .i18n("WebSocket")
	            .page(SettingsPage.class)
	            .build();
	
	 @Override
	    public List<? extends IConfigTab> getConfigPanels() {
		 return Collections.singletonList(
		            HCE_CONFIG_ENTRY
		        );
	 }	

Getting this error when I click on the menu item

Exception
org.apache.wicket.WicketRuntimeException: Can't instantiate page using constructor 'public com.inductiveautomation.ignition.gateway.web.pages.Config(org.apache.wicket.request.mapper.parameter.PageParameters)' and argument 'path=[WebSocket.Settings]'. Might be it doesn't exist, may be it is not visible (public).

at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:193)

at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:98)

at org.apache.wicket.DefaultMapperContext.newPageInstance(DefaultMapperContext.java:137)

at org.apache.wicket.core.request.handler.PageProvider.resolvePageInstance(PageProvider.java:278)

at org.apache.wicket.core.request.handler.PageProvider.getPageInstance(PageProvider.java:166)

at org.apache.wicket.request.handler.render.PageRenderer.getPage(PageRenderer.java:78)

at org.apache.wicket.request.handler.render.WebPageRenderer.renderPage(WebPageRenderer.java:94)

at org.apache.wicket.request.handler.render.WebPageRenderer.respond(WebPageRenderer.java:244)

at org.apache.wicket.core.request.handler.RenderPageRequestHandler.respond(RenderPageRequestHandler.java:165)

at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:814)

at org.apache.wicket.request.RequestHandlerStack.execute(RequestHandlerStack.java:64)

at org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:253)

at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:210)

at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:281)

at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:188)

at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:245)

at com.inductiveautomation.ignition.gateway.bootstrap.GatewayFilter.doFilter(GatewayFilter.java:74)

at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1629)

at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)

at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)

at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)

at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)

at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:190)

at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595)

at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)

at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1253)

at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)

at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)

at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564)

at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)

at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1155)

at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)

at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:61)

at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)

at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:335)

at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:61)

at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:126)

at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)

at org.eclipse.jetty.server.Server.handle(Server.java:530)

at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:347)

at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:256)

at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)

at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)

at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)

at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:247)

at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:140)

at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)

at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:382)

at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:708)

at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:626)

at java.base/java.lang.Thread.run(Unknown Source)

Caused by: java.lang.reflect.InvocationTargetException: null

at jdk.internal.reflect.GeneratedConstructorAccessor62.newInstance(Unknown Source)

at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)

at java.base/java.lang.reflect.Constructor.newInstance(Unknown Source)

at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:170)

... 50 common frames omitted

Caused by: java.lang.RuntimeException: Unable to create config panel WebSocket.Settings

at com.inductiveautomation.ignition.gateway.web.models.DefaultConfigTab.getPanel(DefaultConfigTab.java:99)

at com.inductiveautomation.ignition.gateway.web.pages.Config.(Config.java:109)

... 54 common frames omitted

Caused by: java.lang.reflect.InvocationTargetException: null

at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)

at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)

at java.base/java.lang.reflect.Constructor.newInstance(Unknown Source)

at com.inductiveautomation.ignition.gateway.web.models.DefaultConfigTab.getPanel(DefaultConfigTab.java:91)

... 55 common frames omitted

Caused by: java.lang.NullPointerException: null

at com.inductiveautomation.ignition.gateway.web.models.DirectRecordListModel.(DirectRecordListModel.java:46)

at com.inductiveautomation.ignition.gateway.web.models.CompoundRecordModel.(CompoundRecordModel.java:48)

at com.inductiveautomation.ignition.gateway.web.models.CompoundRecordModel.(CompoundRecordModel.java:41)

at com.inductiveautomation.ignition.gateway.web.components.RecordEditForm.(RecordEditForm.java:65)

at com.jnjdodev.ignition.modules.websocket.SettingsPage.(SettingsPage.java:25)

... 60 common frames omitted

Lastly the menu Item seems to be kinda weird with a bunch of question marks around it?
image

Any ideas are really appreciated!

I"ve managed to write an entire working module but can’t figure out the Settings page LoL!

Thanks again~!

0 Likes

#16

The question marks are because you haven’t loaded a bundle of translation properties for the resource keys you have provided. (Similar to the properties specific to the settings record, which get autoloaded.) Look at the BundleUtil class.

1 Like

#17

Thanks @pturmel I’ll give that a shot

0 Likes

#18

Thanks @pturmel that fixed all my issues

1 Like