I don’t see an obvious problem. I do see that you haven’t made your record types serializable. Pretty sure that isn’t optional.
Okay thanks, Ill wait and see what @PGriffith says, he got me this far lol!
I think
@Override
public @Nullable ExtensionPointType getExtensionPoint(String typeId) {
return null;
}
Should be a switch on typeId
mapping "MIR"
and "OTTO"
to your different extension point types - that way, when you try to create a new record, it creates a new extension point type, and that new extension point type creates the actual record.
And, I don't think your subtype actually has to extend SCMBaseType. Internally we usually use an abstract base type that handles the description/name key, so the subclass only has to pass in a type ID, but that's mostly up to you.
OK thank you. Whats the point of this field?
I have created these:
If i goto edit them, the user could choose from this drop down, or edit the extension type itself. I feel like I should be hiding that drop down from the user?
Yes, you want to make the profile (and type, on the base record) invisible; in a static block in the record class do something like this:
Type.getFormMeta().setVisible(false);
Awesome. Now just the refactoring needs done
So I am querying the base record, then I get the type and check it equals the “MIR” type.
I then need the associated MirSettingsRecord with that type… how would I ensure I get the right one?
SQuery<SCMBaseRecord> query = new SQuery<>(SCMBaseRecord.META);
List<SCMBaseRecord> results = context.getPersistenceInterface().query(query);
for (int i = 0; i < results.size(); i++) {
if (results.get(i).getType().equals("MIR")) {
What I would do is follow the model we use internally. Your ‘manager’ queries all the (base) records on startup, then finds their type. Then each ExtensionPointType
you’ve created defines a ‘createNewInstance’ method (that accepts a base record), and uses the findProfileSettingsRecord
method on ExtensionPointType
to get its own “subrecord”. Then you feed the values from the base and the subrecord into your actual extension point class’ constructor.
Sorry I am confused. Are you describing how the ExternsionPointManager works?
I though the extensionPointManager was only called via the ExtensionPointPage. Are you saying I need to somehow register the extensionPointManager in the gateway first?
No.
Whatever manager class you’re already creating in your module’s GatewayHook
should be the class that implements ExtensionPointManager
. On startup
, it runs the query to find all the SCMBaseRecord
s in the database. For each of those records, it will pull out the type field, then run getExtensionPoint
to retrieve the specific ExtensionPointType
of each of your types of subrecords. You should add an abstract base class (extending BaseExtensionPointType
) that defines a createNewInstance(GatewayContext context, SCMBaseRecord record)
method. Then the manager, while it’s going through the list of records, can call createNewInstance
on each record in the database to create the new instances. To retrieve the subrecord’s individual records, you use findProfileSettingsRecord
inside the createNewInstance
function.
So manager starts up, finds all the records. Finds the extension point, then asks each extension point to create itself, providing the base record. Each extension point can use its base record to find it’s ‘child’ record, and then use those together to create its instance, and hand that back to the ‘manager’, so that the manager can run whatever other bookkeeping it needs to.
I have this as my base class.
@SuppressWarnings(“serial”)
public class SCMBaseType extends BaseExtensionPointType {
public SCMBaseType(String typeId, String nameKey, String descriptionKey) {
super(typeId, nameKey, descriptionKey);
}
@Override
public RecordMeta<? extends PersistentRecord> getSettingsRecordType() {
return SCMBaseRecord.META;
}
}
Is this were I put the createNewInstance function? and then do I extend MirExtensionType and OTTOExtensionType off of this base class?
Yes, exactly.
Ok. So then here I am.
Now this may break… wouldn’t findProfileSettingsRecord return a MirSettingsRecord or an OTTOSettingsRecord here?
At this point it is working.
My last problem is this:
I am returning a new SCMExtensionPointManager() in my ExtensionPoint Page Class
@SuppressWarnings(“serial”)
public class SCMBaseSettingsPage extends ExtensionPointPage {
public static final Pair<String, String> MENU_LOCATION = Pair.of(GatewayHook.CONFIG_CATEGORY.getName(), "mirconfig");
public SCMBaseSettingsPage(IConfigPage configPage) {
super(configPage);
}
@Override
protected ExtensionPointManager getExtensionPointManager() {
return new SCMExtensionPointManager();
}
@Override
public Pair<String, String> getMenuLocation() {
return MENU_LOCATION;
}
@Override
protected RecordMeta<SCMBaseRecord> getRecordMeta() {
return SCMBaseRecord.META;
}
}
I am also declaring a new SCMExtensionPointManager instance in my gateway, so I can call it’s startup and shutdown methods when appropriate.
Shouldn’t I be using only one instance here? if so, what the recommended way of doing this?
You're not fully implementing things.
createNewInstance
should be returning a concrete instance of whatever base actual thing MirSettingsRecord
or OTTOSettingsRecord
map to - a MirInstance()
or OTTOInstance()
, which take as constructor parameters an SCMSettingsRecord
and a MirSettingsRecord
/OTTOSettingsRecord
, as appropriate. findProfileSettingsRecord
is just a convenience method to do the foreign key lookup from the SCMBaseRecord
that's provided - you then need to use the parent and child record together, and actually pass them in to your constructed object.
The easiest way is to use the singleton pattern (Design Pattern - Singleton Pattern). You could even have your GatewayHook
be the singleton, if you want; it just has to implement the ExtensionPointManager
methods. But you definitely should not be creating new instances.
Great. Implemented Singleton, and updated createNewInstance(). This is only my second large java project. I am mainly a python guy so this has been a fun learning curve.
At this point it is working well. I am going to throw together a tutorial in the forums for any future goers.
Thank you!
Probably should have just done this earlier, but I threw together a full example:
Great saves me the time ahaha
The original cause of this thread has been solved, but I could see the answer to this question being relevant to anyone implementing this page, so asking here.
How do you make the ExtensionPointPage poll/refresh one of the values on-screen for each record?
For instance on the Database Connections Config page the "Status" column is polling every X seconds.
I don't see a column doing that in the example you made @PGriffith