Skip to content

Commit def904a

Browse files
committed
we need to register exporter builder components.
There was a hope that we would only need one (global) extension. It is clear now that we need two: one global, one for per-database things. So here we simplify and document that state of affairs, so that it is clear for posterity what is going on and why things are safe.
1 parent bd8892d commit def904a

File tree

6 files changed

+150
-164
lines changed

6 files changed

+150
-164
lines changed

core-write/src/main/java/org/neo4j/gds/core/write/AbstractExportBuildersExtension.java

Lines changed: 0 additions & 120 deletions
This file was deleted.

open-write-services/src/main/java/org/neo4j/gds/OpenGdsExportBuildersExtension.java

Lines changed: 0 additions & 40 deletions
This file was deleted.

procedures/extension/README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
# The OpenGDS extension to Neo4j
22

3-
Here lives the entrypoint for OpenGDS into Neo4j. We use the extension mechanism to register a [single injectable component](../facade/README.md) with Neo4j.
3+
Here live the entrypoints for OpenGDS into Neo4j. We use the extension mechanism to register an [injectable facade component](../facade/README.md) with Neo4j.
4+
We also register per-database components.
5+
6+
The paradigm is, we have the facade holding functionality, accessed via a single component, registered via a global extension.
7+
And we need per-database components as well, for example for exporter builders. That goes via a database scoped extension.
8+
9+
But, importantly, we only _need_ two extensions, one global, one database scoped. Important because it makes code grokable,
10+
you have one place to go read some hopefully declarative-ish code, so that you can grok what an edition comprises.
411

512
This module initialises plugin state and constructs the facade. It is here we make edition specific choices.
613

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Neo4j is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
package org.neo4j.gds.extension;
21+
22+
import org.neo4j.annotations.service.ServiceProvider;
23+
import org.neo4j.gds.core.write.NativeExportBuildersProvider;
24+
import org.neo4j.gds.procedures.integration.ExporterBuildersComponentRegistration;
25+
import org.neo4j.kernel.api.procedure.GlobalProcedures;
26+
import org.neo4j.kernel.extension.ExtensionFactory;
27+
import org.neo4j.kernel.extension.ExtensionType;
28+
import org.neo4j.kernel.extension.context.ExtensionContext;
29+
import org.neo4j.kernel.lifecycle.Lifecycle;
30+
import org.neo4j.kernel.lifecycle.LifecycleAdapter;
31+
32+
/**
33+
* Life in OpenGDS is very simple, we just register native exporter builders as components.
34+
* They are database mode independent.
35+
* We need exporter builders as components since they are @Context injected into e.g. Pregel code.
36+
* Note that this is a database level extension.
37+
* It needs to be one because exporter builders can be database mode dependent.
38+
*/
39+
@SuppressWarnings({"unused", "WeakerAccess"})
40+
@ServiceProvider
41+
public class OpenGdsExportBuildersExtension extends ExtensionFactory<OpenGdsExportBuildersExtension.Dependencies> {
42+
public OpenGdsExportBuildersExtension() {
43+
super(ExtensionType.DATABASE, "gds.open-write-services");
44+
}
45+
46+
@Override
47+
public Lifecycle newInstance(ExtensionContext extensionContext, Dependencies dependencies) {
48+
var globalProcedures = dependencies.globalProcedures();
49+
var exporterBuildersComponentRegistration = new ExporterBuildersComponentRegistration(globalProcedures);
50+
51+
var exportBuildersProvider = new NativeExportBuildersProvider();
52+
exporterBuildersComponentRegistration.registerExporterBuilders(exportBuildersProvider);
53+
54+
return new LifecycleAdapter(); // do nothing
55+
}
56+
57+
public interface Dependencies {
58+
GlobalProcedures globalProcedures();
59+
}
60+
}

procedures/facade/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# Procedure Facade
22

3-
Here we keep the single injectable facade for the GDS procedures.
3+
Here we keep the injectable facade for the GDS procedures.
44

5-
All GDS procedures inject this one dependency, and it forms an umbrella over functional areas like graph store catalog or community algorithms. This keeps each sub interface smaller, more coherent and more manageable.
5+
GDS procedures inject this single dependency, and it forms an umbrella over functional areas like graph store catalog or community algorithms. This keeps each sub interface smaller, more coherent and more manageable.
66

7-
We also here host the integration services needed to cleanly interface with Neo4j. All Neo4j dependencies should be unstacked and wrapped here, because in the layers below we would want to be Neo4j agnostic.
7+
We also here host the integration services needed to cleanly interface with Neo4j. All Neo4j dependencies should be unstacked and wrapped here, because in the layers below we would want to be Neo4j agnostic. That makes them reusable.
88

99
Code in here mainly uses [the applications procedure facade](../algorithms-facade/README.md) and pipelines.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Neo4j is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
package org.neo4j.gds.procedures.integration;
21+
22+
import org.neo4j.gds.core.write.ExportBuildersProvider;
23+
import org.neo4j.gds.core.write.ExporterContext;
24+
import org.neo4j.gds.core.write.NodeLabelExporterBuilder;
25+
import org.neo4j.gds.core.write.NodePropertyExporterBuilder;
26+
import org.neo4j.gds.core.write.RelationshipExporterBuilder;
27+
import org.neo4j.gds.core.write.RelationshipPropertiesExporterBuilder;
28+
import org.neo4j.gds.core.write.RelationshipStreamExporterBuilder;
29+
import org.neo4j.kernel.api.procedure.GlobalProcedures;
30+
31+
public class ExporterBuildersComponentRegistration {
32+
private final GlobalProcedures globalProcedures;
33+
34+
public ExporterBuildersComponentRegistration(GlobalProcedures globalProcedures) {
35+
this.globalProcedures = globalProcedures;
36+
}
37+
38+
public void registerExporterBuilders(ExportBuildersProvider exportBuildersProvider) {
39+
globalProcedures.registerComponent(
40+
NodePropertyExporterBuilder.class,
41+
(ctx) -> exportBuildersProvider.nodePropertyExporterBuilder(
42+
new ExporterContext.ProcedureContextWrapper(ctx)
43+
),
44+
true
45+
);
46+
47+
globalProcedures.registerComponent(
48+
RelationshipStreamExporterBuilder.class,
49+
(ctx) -> exportBuildersProvider.relationshipStreamExporterBuilder(
50+
new ExporterContext.ProcedureContextWrapper(ctx)
51+
),
52+
true
53+
);
54+
55+
globalProcedures.registerComponent(
56+
RelationshipExporterBuilder.class,
57+
(ctx) -> exportBuildersProvider.relationshipExporterBuilder(
58+
new ExporterContext.ProcedureContextWrapper(ctx)
59+
),
60+
true
61+
);
62+
63+
globalProcedures.registerComponent(
64+
RelationshipPropertiesExporterBuilder.class,
65+
(ctx) -> exportBuildersProvider.relationshipPropertiesExporterBuilder(
66+
new ExporterContext.ProcedureContextWrapper(ctx)
67+
),
68+
true
69+
);
70+
71+
globalProcedures.registerComponent(
72+
NodeLabelExporterBuilder.class,
73+
(ctx) -> exportBuildersProvider.nodeLabelExporterBuilder(
74+
new ExporterContext.ProcedureContextWrapper(ctx)
75+
),
76+
true
77+
);
78+
}
79+
}

0 commit comments

Comments
 (0)