1515 */
1616package org .netbeans .modules .nbcode .java .notebook ;
1717
18+ import com .google .gson .JsonObject ;
19+ import java .net .URI ;
20+ import java .nio .file .Paths ;
1821import java .util .ArrayList ;
22+ import java .util .HashMap ;
1923import java .util .List ;
2024import java .util .Map ;
2125import java .util .concurrent .CancellationException ;
2226import java .util .concurrent .CompletableFuture ;
2327import java .util .concurrent .ConcurrentHashMap ;
2428import java .util .concurrent .ExecutionException ;
29+ import java .util .function .BiConsumer ;
2530import java .util .logging .Level ;
2631import java .util .logging .Logger ;
2732import jdk .jshell .JShell ;
2833import org .eclipse .lsp4j .NotebookDocument ;
34+ import org .netbeans .api .project .Project ;
2935import static org .netbeans .modules .nbcode .java .notebook .NotebookUtils .checkEmptyString ;
36+ import org .netbeans .modules .nbcode .java .project .ProjectConfigurationUtils ;
37+ import org .netbeans .modules .nbcode .java .project .ProjectContext ;
3038
3139/**
3240 *
@@ -56,45 +64,41 @@ private static class Singleton {
5664 private static final NotebookSessionManager instance = new NotebookSessionManager ();
5765 }
5866
59- private CompletableFuture <JShell > jshellBuilder (JshellStreamsHandler streamsHandler ) {
60- return CompletableFuture .supplyAsync (() -> {
61- try {
62- NotebookConfigs .getInstance ().getInitialized ().get ();
63- } catch (InterruptedException ex ) {
64- LOG .log (Level .WARNING , "InterruptedException occurred while getting notebook configs: {0}" , ex .getMessage ());
65- } catch (ExecutionException ex ) {
66- LOG .log (Level .WARNING , "ExecutionException occurred while getting notebook configs: {0}" , ex .getMessage ());
67- }
68- List <String > compilerOptions = getCompilerOptions ();
69- List <String > remoteOptions = getRemoteVmOptions ();
70- if (compilerOptions .isEmpty ()) {
71- return JShell .builder ()
72- .out (streamsHandler .getPrintOutStream ())
73- .err (streamsHandler .getPrintErrStream ())
74- .in (streamsHandler .getInputStream ())
75- .compilerOptions ()
76- .remoteVMOptions ()
77- .build ();
78- } else {
79- return JShell .builder ()
80- .out (streamsHandler .getPrintOutStream ())
81- .err (streamsHandler .getPrintErrStream ())
82- .in (streamsHandler .getInputStream ())
83- .compilerOptions (compilerOptions .toArray (new String [0 ]))
84- .remoteVMOptions (remoteOptions .toArray (new String [0 ]))
85- .build ();
86- }
67+ private CompletableFuture <JShell > jshellBuilder (String notebookUri , JshellStreamsHandler streamsHandler ) {
68+ return NotebookConfigs .getInstance ().getInitialized ()
69+ .thenCompose (v -> getProjectContextForNotebook (notebookUri )
70+ .thenApply (prj -> jshellBuildWithProject (prj , streamsHandler )
71+ )).exceptionally (throwable -> {
72+ LOG .log (Level .WARNING , "Failed to get project context, using default JShell configuration" , throwable );
73+ return jshellBuildWithProject (null , streamsHandler );
8774 });
8875 }
8976
77+ private JShell jshellBuildWithProject (Project prj , JshellStreamsHandler streamsHandler ) {
78+ List <String > compilerOptions = getCompilerOptions (prj );
79+ List <String > remoteOptions = getRemoteVmOptions (prj );
80+
81+ JShell .Builder builder = JShell .builder ()
82+ .out (streamsHandler .getPrintOutStream ())
83+ .err (streamsHandler .getPrintErrStream ())
84+ .in (streamsHandler .getInputStream ());
85+
86+ if (!compilerOptions .isEmpty ()) {
87+ builder .compilerOptions (compilerOptions .toArray (new String [0 ]))
88+ .remoteVMOptions (remoteOptions .toArray (new String [0 ]));
89+ }
90+
91+ return builder .build ();
92+ }
93+
9094 public CompletableFuture <JShell > createSession (NotebookDocument notebookDoc ) {
9195 String notebookId = notebookDoc .getUri ();
9296
9397 return sessions .computeIfAbsent (notebookId , id -> {
9498 JshellStreamsHandler handler = new JshellStreamsHandler (id , CodeEval .getInstance ().outStreamFlushCb , CodeEval .getInstance ().errStreamFlushCb );
9599 jshellStreamsMap .put (id , handler );
96100
97- CompletableFuture <JShell > future = jshellBuilder (handler );
101+ CompletableFuture <JShell > future = jshellBuilder (notebookDoc . getUri (), handler );
98102
99103 future .thenAccept (jshell -> onJshellInit (notebookId , jshell ))
100104 .exceptionally (ex -> {
@@ -106,58 +110,85 @@ public CompletableFuture<JShell> createSession(NotebookDocument notebookDoc) {
106110 });
107111 }
108112
109- private List <String > getCompilerOptions () {
113+ private List <String > getCompilerOptions (Project prj ) {
110114 List <String > compilerOptions = new ArrayList <>();
111- String classpath = NotebookConfigs .getInstance ().getClassPath ();
112- String modulePath = NotebookConfigs .getInstance ().getModulePath ();
113- String addModules = NotebookConfigs .getInstance ().getAddModules ();
114- boolean isEnablePreview = NotebookConfigs .getInstance ().isEnablePreview ();
115- String notebookJdkVersion = NotebookConfigs .getInstance ().getJdkVersion ();
116-
117- if (!checkEmptyString (classpath )) {
118- compilerOptions .add (CLASS_PATH );
119- compilerOptions .add (classpath );
120- }
121- if (!checkEmptyString (modulePath )) {
122- compilerOptions .add (MODULE_PATH );
123- compilerOptions .add (modulePath );
124- }
125- if (!checkEmptyString (addModules )) {
126- compilerOptions .add (ADD_MODULES );
127- compilerOptions .add (addModules );
128- }
129- if (isEnablePreview ) {
115+ NotebookConfigs configs = NotebookConfigs .getInstance ();
116+
117+ BiConsumer <String , String > addOption = (flag , value ) -> {
118+ if (!checkEmptyString (value )) {
119+ compilerOptions .add (flag );
120+ compilerOptions .add (value );
121+ }
122+ };
123+
124+ addOption .accept (CLASS_PATH , configs .getClassPath ());
125+ addOption .accept (MODULE_PATH , configs .getModulePath ());
126+ addOption .accept (ADD_MODULES , configs .getAddModules ());
127+
128+ if (configs .isEnablePreview ()) {
130129 compilerOptions .add (ENABLE_PREVIEW );
131130 compilerOptions .add (SOURCE_FLAG );
132- compilerOptions .add (notebookJdkVersion );
131+ compilerOptions .add (configs .getJdkVersion ());
132+ }
133+
134+ if (prj != null ) {
135+ List <String > projOptions = ProjectConfigurationUtils .compilerOptions (prj );
136+ Map <String , String > prjConfigMap = new HashMap <>();
137+ for (int i = 0 ; i < projOptions .size () - 1 ; i += 2 ) {
138+ prjConfigMap .put (projOptions .get (i ), projOptions .get (i + 1 ));
139+ }
140+
141+ if (checkEmptyString (configs .getClassPath ()) && prjConfigMap .containsKey (CLASS_PATH )) {
142+ addOption .accept (CLASS_PATH , prjConfigMap .get (CLASS_PATH ));
143+ }
144+ if (checkEmptyString (configs .getModulePath ()) && prjConfigMap .containsKey (MODULE_PATH )) {
145+ addOption .accept (MODULE_PATH , prjConfigMap .get (MODULE_PATH ));
146+ }
147+ if (checkEmptyString (configs .getAddModules ()) && prjConfigMap .containsKey (ADD_MODULES )) {
148+ addOption .accept (ADD_MODULES , prjConfigMap .get (ADD_MODULES ));
149+ }
133150 }
134151
135152 return compilerOptions ;
136153 }
137154
138- private List <String > getRemoteVmOptions () {
155+ private List <String > getRemoteVmOptions (Project prj ) {
139156 List <String > remoteOptions = new ArrayList <>();
140- String classpath = NotebookConfigs .getInstance ().getClassPath ();
141- String modulePath = NotebookConfigs .getInstance ().getModulePath ();
142- String addModules = NotebookConfigs .getInstance ().getAddModules ();
143- boolean isEnablePreview = NotebookConfigs .getInstance ().isEnablePreview ();
144-
145- if (!checkEmptyString (classpath )) {
146- remoteOptions .add (CLASS_PATH );
147- remoteOptions .add (classpath );
148- }
149- if (!checkEmptyString (modulePath )) {
150- remoteOptions .add (MODULE_PATH );
151- remoteOptions .add (modulePath );
152- }
153- if (!checkEmptyString (addModules )) {
154- remoteOptions .add (ADD_MODULES );
155- remoteOptions .add (addModules );
156- }
157+ NotebookConfigs configs = NotebookConfigs .getInstance ();
158+ boolean isEnablePreview = configs .isEnablePreview ();
159+
160+ BiConsumer <String , String > addOption = (flag , value ) -> {
161+ if (!checkEmptyString (value )) {
162+ remoteOptions .add (flag );
163+ remoteOptions .add (value );
164+ }
165+ };
166+
167+ addOption .accept (CLASS_PATH , configs .getClassPath ());
168+ addOption .accept (MODULE_PATH , configs .getModulePath ());
169+ addOption .accept (ADD_MODULES , configs .getAddModules ());
170+
157171 if (isEnablePreview ) {
158172 remoteOptions .add (ENABLE_PREVIEW );
159173 }
160174
175+ if (prj != null ) {
176+ List <String > projOptions = ProjectConfigurationUtils .launchVMOptions (prj );
177+ Map <String , String > prjConfigMap = new HashMap <>();
178+ for (int i = 0 ; i < projOptions .size () - 1 ; i += 2 ) {
179+ prjConfigMap .put (projOptions .get (i ), projOptions .get (i + 1 ));
180+ }
181+
182+ if (checkEmptyString (configs .getClassPath ()) && prjConfigMap .containsKey (CLASS_PATH )) {
183+ addOption .accept (CLASS_PATH , prjConfigMap .get (CLASS_PATH ));
184+ }
185+ if (checkEmptyString (configs .getModulePath ()) && prjConfigMap .containsKey (MODULE_PATH )) {
186+ addOption .accept (MODULE_PATH , prjConfigMap .get (MODULE_PATH ));
187+ }
188+ if (checkEmptyString (configs .getAddModules ()) && prjConfigMap .containsKey (ADD_MODULES )) {
189+ addOption .accept (ADD_MODULES , prjConfigMap .get (ADD_MODULES ));
190+ }
191+ }
161192 return remoteOptions ;
162193 }
163194
@@ -205,4 +236,28 @@ public void closeSession(String notebookUri) {
205236 handler .close ();
206237 }
207238 }
239+
240+ private CompletableFuture <Project > getProjectContextForNotebook (String notebookUri ) {
241+ JsonObject mapping = NotebookConfigs .getInstance ().getNotebookProjectMapping ();
242+ String notebookPath = URI .create (notebookUri ).getPath ();
243+ String projectKey = mapping .has (notebookPath )
244+ ? Paths .get (mapping .get (notebookPath ).getAsString ()).toUri ().toString ()
245+ : notebookUri ;
246+
247+ Project prj = ProjectContext .getProject (projectKey );
248+
249+ if (prj == null ) {
250+ LOG .log (Level .WARNING , "Project not found or not open in workspace: {0}" , projectKey );
251+ return null ;
252+ }
253+
254+ return ProjectConfigurationUtils .buildProject (prj ).thenApply (buildStatus -> {
255+ if (!buildStatus ) {
256+ LOG .log (Level .WARNING , "Error while building project: {0}" , projectKey );
257+ return null ;
258+ }
259+ return prj ;
260+ });
261+
262+ }
208263}
0 commit comments