Tom, thanks for the review. Very much appreciated!. I'll try to address some of the issues.
Yes, the thread was moved.
I do expect I'll be writing up an Extensions HowTo to replace the prior, out-of-date, documents such as Giuliano Tortoreto's OpenRefine Extension Doc and the great Owen Stephens' Writing an Extension to Add New GREL Functions to OpenRefine. It would be ideal to document it all in an OpenRefine space instead of a separate document--likely at OR's Writing extensions.
Even today, the documentation specifies the use of "reconstructors". See Writing extensions: Server-side: Operations and Writing extensions: Server-side: Overlay Models
Project Specific Setting
To clarify, an extension may manage its own settings and data including settings and data that apply to specific projects. Some of this information should certainly be stored in an Overlay and any Change blobs for a specific project. I shouldn't need to store the Project information in these blobs since the Overlay and Change blobs are loading for a specific project anyway.
Commands and Operations:
Operations, in general, are project independent. However, they are applied to a specific project. Since operations are associated with commands (i.e., commands carry out operations), knowing what project they are applied to can help an extension determine context for its operations used in a specific project. Certainly, the user selected a command that implements operations to be applied to the specific project...not every project. This is why the AbstractOperation base class has:
public Process createProcess(Project project, Properties options)
and
protected HistoryEntry createHistoryEntry(Project project, long historyEntryID)
and
protected String getBriefDescription(Project project)
Then, the Project is essential to operations.
When the project is loaded, reconstruction manages the history of those operations on a specific project. However, the Project parameter is NOT specifically required via the Jackson process like it was using the older "reconstruct" method. However, the Project ID is available during reconstruction via:
@JacksonInject("projectID") long iProjectID
If @JacksonInject("projectID")
is the way to fix this issue, then problem solved. It was't documented anywhere.
To be fair, a reconstruction should be "complete", i.e., the data loaded from OR should contain everything the Operation object needs to "completely" reconstruct itself. However, an extension may be doing more than what OR "needs"...that is why it is an extension! The JSON data may just contain reference data that an extension uses to "complete" its operations. The Project may be essential reference information for that reconstruction.
In my case, the RDF Transform Operations take a Project in its ctors. The related Command creates those Operations with the Project. The old reconstructor recreated the Operation object with the Project. The Jackson process had no way of knowing that, is undocumented, and essential silently "broke" the reconstruction process...which is what caused the Full Disclosure failure.
Making the project information available universally is a low cost addition since every post or get from the client-side gives the server-side access to the project information. Purposely not making it available seems a bit heavy-handed. OR shouldn't be divining what an extension should or shouldn't be doing or needing in its own internal processes.
Changes:
Change objects are applied to or reverted from a project:
void apply(Project var1);
void revert(Project var1);
Then, why wouldn't the project be accessible in the static Change load() method? Again, like Operations, the Project should be available as reference data so that the extension can do whatever it needs to do. Currently, there is no work-around.
For RDF Transform, there is only one Change class for saving the RDF Transform template state (which is its Overlay data). So, it obviously needs the Project to do that:
... = (RDFTransform) theProject.overlayModels.get(RDFTransform.EXTENSION);
theProject.overlayModels.remove(RDFTransform.EXTENSION);
theProject.overlayModels.put(RDFTransform.EXTENSION, this.thePreviousTransform);
Does RDF Transform need the Project information in the static load() method? No. But it could if it were processing some ancillary change data about the project in the extension (or whatever else it wants to do). We can make esoteric arguments about why an extension should store that information in OR. But, why be pedantic about it? Give extension developers freedom to manage their own system. The Project information is essential to that freedom.
Overlays:
RDF Transform certainly uses an Overlay Model as seen above. It uses the overlay to store the RDF Transform template. However, the overlay model cannot store a Lucene database (well, it could, but that is a heavy lift). Its use is not necessarily critical to the project. It is a support function. It helps the user select class and property values used in the RDF Transform template. Some of the Lucene database entries are project agnostic while other entries reference the project specifically (adding and removing an RDF namespace, its prefix, and all the relate ontology classes and properties to/from a project).
Storing all this in an Overlay would lead to large blobs and need to be reconstructed anyway. Instead, the overlay holds reference information on how the ontology was found (URL, file, or none). For a project, a Lucene database can be reconstructed for a project if it can get to the URL or load a cached server-side, locally stored ontology file. If not, nothing is significantly impacted by its loss...just inconvenienced.
To share a project, an extension can package its own data, if needed, to augment an OR project export. Additionally, it could extend the OR project export if it were given the proper hooks (hint). A developer could just use the Project's directory to store additional content, but I'm not sure how that would be done ATM. I think it would definitely need the Project ID at a minimum.
Extension Initialization
When I was redeveloping the older RDF extension, I was attempting to manage the initialization process. I was having difficulty with many JS features (oddly, simple looping wasn't supported). This may be fixed in the newer Rhino JS.
It finally occurred to me that the server-side JS processor is just calling a bunch of Java classes and objects!!! So, why not just pass all control over to an Initialization Command object and stop the overhead insanity of transferring calls between the JS and Java systems. I agree that the code is relatively small and the performance impact is minimal. However, this version of a "common pattern" seems much cleaner, IMNSHO.
The comment "Fool Butterfly" may be a technically incorrect--I was just trying to indicate that Butterfly's use for executing the "controller.js" file is drastically minimized. The minimized "controller.js" file is a simplified, basic extension launcher. During initialization, it allows the developer to harness all the power of Java with no down side. It also aligns the initialization process via a Command class like all the other extension Command classes. To me, it feels more elegant than using a not-so "pure" JS solution for server-side initialization.
This could reduce (or eliminate?) dependence on Simile Butterfly (and its maintenance). Could OR replace it with the Java Method Server (JMS)?
I'm not sure how the function process(path, request, response)
in the "controller.js" file would be impacted as I don't know how other extensions might use it. It seems to be used as a redirector. Could the functionality be moved to Command classes instead?