Adding Settings

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();
		}

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

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

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?

Ah, it changed a bit in 8.0.

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

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

1 Like

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!

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

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

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);
	}

	
}

Does your SettingsPage still have the public IConfigPage constructor?

	public SettingsPage(final IConfigPage configPage) {

Yes it does, should it not?

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.

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

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~!

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

Thanks @pturmel I’ll give that a shot

Thanks @pturmel that fixed all my issues

1 Like