diff --git a/enterprise/maven.j2ee/nbproject/project.xml b/enterprise/maven.j2ee/nbproject/project.xml index a70354b63829..71488f740e42 100644 --- a/enterprise/maven.j2ee/nbproject/project.xml +++ b/enterprise/maven.j2ee/nbproject/project.xml @@ -542,6 +542,7 @@ org.netbeans.modules.maven.jaxws org.netbeans.modules.payara.micro + org.netbeans.modules.payara.server.maven org.netbeans.modules.jakarta.transformer org.netbeans.modules.maven.j2ee org.netbeans.modules.maven.j2ee.execution diff --git a/enterprise/payara.micro/src/org/netbeans/modules/fish/payara/micro/project/MicroProjectHook.java b/enterprise/payara.micro/src/org/netbeans/modules/fish/payara/micro/project/MicroProjectHook.java index d13d0a9a8649..973ebc3733ee 100644 --- a/enterprise/payara.micro/src/org/netbeans/modules/fish/payara/micro/project/MicroProjectHook.java +++ b/enterprise/payara.micro/src/org/netbeans/modules/fish/payara/micro/project/MicroProjectHook.java @@ -61,16 +61,14 @@ public void projectClosed() { } } } - + private void updateMicroIcon() { - SpecialIcon specialIcon = project.getLookup().lookup(SpecialIcon.class); - MicroIcon microIcon; - if (specialIcon instanceof MicroIcon) { - microIcon = (MicroIcon) specialIcon; - } else { - return; + for (SpecialIcon specialIcon : project.getLookup().lookupAll(SpecialIcon.class)) { + if (specialIcon instanceof MicroIcon) { + ((MicroIcon) specialIcon).setProject(project); + return; + } } - microIcon.setProject(project); } private void addDeployOnSaveManager(Project project) { diff --git a/enterprise/payara.server.maven/build.xml b/enterprise/payara.server.maven/build.xml new file mode 100644 index 000000000000..77735508b360 --- /dev/null +++ b/enterprise/payara.server.maven/build.xml @@ -0,0 +1,25 @@ + + + + Builds, tests, and runs the project org.netbeans.modules.payara.server.maven + + diff --git a/enterprise/payara.server.maven/manifest.mf b/enterprise/payara.server.maven/manifest.mf new file mode 100644 index 000000000000..905f2f29e066 --- /dev/null +++ b/enterprise/payara.server.maven/manifest.mf @@ -0,0 +1,5 @@ +Manifest-Version: 1.0 +AutoUpdate-Show-In-Client: false +OpenIDE-Module: org.netbeans.modules.payara.server.maven/0 +OpenIDE-Module-Layer: org/netbeans/modules/payara/server/maven/layer.xml +OpenIDE-Module-Specification-Version: 1.0 diff --git a/enterprise/payara.server.maven/nbproject/project.properties b/enterprise/payara.server.maven/nbproject/project.properties new file mode 100644 index 000000000000..0f4ec98bc91a --- /dev/null +++ b/enterprise/payara.server.maven/nbproject/project.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +javac.source=1.8 +javac.compilerargs=-Xlint -Xlint:-serial diff --git a/enterprise/payara.server.maven/nbproject/project.xml b/enterprise/payara.server.maven/nbproject/project.xml new file mode 100644 index 000000000000..4afc7e065835 --- /dev/null +++ b/enterprise/payara.server.maven/nbproject/project.xml @@ -0,0 +1,172 @@ + + + + org.netbeans.modules.apisupport.project + + + org.netbeans.modules.payara.server.maven + + + org.netbeans.api.annotations.common + + + + 1 + 1.27.1 + + + + org.netbeans.modules.j2eeapis + + + + 1 + 1.35.1 + + + + org.netbeans.modules.j2eeserver + + + + 4 + 1.116 + + + + org.netbeans.modules.maven + + + + 2 + 2.133 + + + + org.netbeans.modules.maven.embedder + + + + 2 + 2.58 + + + + org.netbeans.modules.maven.j2ee + + + + 1 + 1.65 + + + + org.netbeans.modules.payara.tooling + + + + 0 + 2.5 + + + + org.netbeans.modules.projectapi + + + + 1 + 1.72 + + + + org.netbeans.modules.projectuiapi + + + + 1 + 1.88.1.8 + + + + org.netbeans.modules.projectuiapi.base + + + + 1 + 1.85.1.9 + + + + org.openide.execution + + + + 9.3.1 + + + + org.openide.filesystems + + + + 9.10.1 + + + + org.openide.util + + + + 9.7.1 + + + + org.openide.util.lookup + + + + 8.33.1 + + + + org.openide.awt + + + + 7.73 + + + + org.openide.util.ui + + + + 9.6.1 + + + + + org.netbeans.modules.payara.server.maven.plugin + + + + diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/layer.xml b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/layer.xml new file mode 100644 index 000000000000..5ff55e39af13 --- /dev/null +++ b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/layer.xml @@ -0,0 +1,5 @@ + + + + diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/plugin/Constants.java b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/plugin/Constants.java new file mode 100644 index 000000000000..7bf7cb719654 --- /dev/null +++ b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/plugin/Constants.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.payara.server.maven.plugin; + +import org.netbeans.api.annotations.common.StaticResource; +import org.netbeans.modules.maven.api.NbMavenProject; +import org.netbeans.spi.project.ActionProvider; + +/** + * @author Gaurav Gupta + */ +public interface Constants { + + String WAR_PACKAGING = "war"; + + String MAVEN_WAR_PROJECT_TYPE = "org-netbeans-modules-maven/" + NbMavenProject.TYPE_WAR; + + String PAYARA_SERVER_MAVEN_PLUGIN = "fish.payara.maven.plugins:payara-server-maven-plugin"; + + String PLUGIN_GROUP_ID = "fish.payara.maven.plugins"; + String PLUGIN_ARTIFACT_ID = "payara-server-maven-plugin"; + + String RUN_SINGLE_ACTION = ActionProvider.COMMAND_RUN_SINGLE + ".deploy"; + String DEBUG_SINGLE_ACTION = ActionProvider.COMMAND_DEBUG_SINGLE + ".deploy"; + String PROFILE_SINGLE_ACTION = ActionProvider.COMMAND_PROFILE_SINGLE + ".deploy"; + + // ── Preference keys (stored per-project via ProjectUtils.getPreferences) ── + String PREF_SERVER_VERSION = "payaraServerVersion"; + String PREF_SERVER_PATH = "payaraServerPath"; + String PREF_DOMAIN_NAME = "domainName"; + String PREF_CONTEXT_ROOT = "contextRoot"; + String PREF_EXPLODED = "exploded"; + String PREF_REMOTE = "remote"; + String PREF_HOST_NAME = "hostName"; + String PREF_ADMIN_PORT = "adminPort"; + String PREF_ADMIN_USER = "adminUser"; + String PREF_INSTANCE_NAME = "instanceName"; + String PREF_HOT_DEPLOY = "hotDeploy"; + String PREF_AUTO_DEPLOY = "autoDeploy"; + String PREF_LIVE_RELOAD = "liveReload"; + String PREF_KEEP_STATE = "keepState"; + String PREF_TRIM_LOG = "trimLog"; + String PREF_DAEMON = "daemon"; + String PREF_IGNORE_TEST = "ignoreTestChanges"; + + // ── Maven property names (passed as -D arguments to the plugin) ────────── + String MVNPROP_SERVER_VERSION = "payara.server.version"; + String MVNPROP_SERVER_PATH = "payara.server.path"; + String MVNPROP_DOMAIN_NAME = "payara.domain.name"; + String MVNPROP_CONTEXT_ROOT = "payara.context.root"; + String MVNPROP_EXPLODED = "payara.exploded"; + String MVNPROP_REMOTE = "payara.remote"; + String MVNPROP_HOST_NAME = "payara.host.name"; + String MVNPROP_ADMIN_PORT = "payara.admin.port"; + String MVNPROP_ADMIN_USER = "payara.admin.user"; + String MVNPROP_INSTANCE_NAME = "payara.instance.name"; + String MVNPROP_HOT_DEPLOY = "payara.hot.deploy"; + String MVNPROP_AUTO_DEPLOY = "payara.auto.deploy"; + String MVNPROP_LIVE_RELOAD = "payara.live.reload"; + String MVNPROP_KEEP_STATE = "payara.keep.state"; + String MVNPROP_TRIM_LOG = "payara.trim.log"; + String MVNPROP_DAEMON = "payara.daemon"; + String MVNPROP_IGNORE_TEST = "payara.ignore.test.changes"; + String PREF_AI_AGENT = "aiAgent"; + String PREF_AI_API_KEY = "aiApiKey"; + String PREF_AI_PROVIDER = "aiProvider"; + String PREF_AI_PROVIDER_LOC = "aiProviderLocation"; + String PREF_AI_MODEL = "aiModel"; + + String ENV_AI_API_KEY = "PAYARA_AI_API_KEY"; + + String MVNPROP_AI_AGENT = "payara.ai.agent"; + String MVNPROP_AI_API_KEY = "payara.ai.api.key"; + String MVNPROP_AI_PROVIDER = "payara.ai.provider"; + String MVNPROP_AI_PROVIDER_LOC = "payara.ai.provider.location"; + String MVNPROP_AI_MODEL = "payara.ai.model"; + + @StaticResource + String PROJECT_ICON = "org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven.png"; + + @StaticResource + String CLEAN_ICON = "org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-clean.png"; + + @StaticResource + String BUILD_ICON = "org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-build.png"; + + @StaticResource + String REBUILD_ICON = "org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-clean-build.png"; + + @StaticResource + String START_ICON = "org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-start.png"; + + @StaticResource + String RESTART_ICON = "org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-restart.png"; + + @StaticResource + String RELOAD_ICON = "org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-reload.png"; + + @StaticResource + String DEBUG_ICON = "org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-debug.png"; + + @StaticResource + String PROFILE_ICON = "org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-profile.png"; +} diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ActionType.java b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ActionType.java new file mode 100644 index 000000000000..0638d7f07c20 --- /dev/null +++ b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ActionType.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.payara.server.maven.project; + +import static org.netbeans.modules.payara.server.maven.plugin.Constants.BUILD_ICON; +import static org.netbeans.modules.payara.server.maven.plugin.Constants.CLEAN_ICON; +import static org.netbeans.modules.payara.server.maven.plugin.Constants.DEBUG_ICON; +import static org.netbeans.modules.payara.server.maven.plugin.Constants.PROFILE_ICON; +import static org.netbeans.modules.payara.server.maven.plugin.Constants.REBUILD_ICON; +import static org.netbeans.modules.payara.server.maven.plugin.Constants.RELOAD_ICON; +import static org.netbeans.modules.payara.server.maven.plugin.Constants.START_ICON; + +/** + * @author Gaurav Gupta + */ +public enum ActionType { + + CLEAN(CLEAN_ICON), + BUILD(BUILD_ICON), + BUILD_WITH_DEPENDENCIES(BUILD_ICON), + REBUILD(REBUILD_ICON), + + SERVER_MAVEN_DEV(RELOAD_ICON), + + RUN(START_ICON), + DEBUG(DEBUG_ICON), + PROFILE(PROFILE_ICON); + + private final String icon; + + private ActionType(String icon) { + this.icon = icon; + } + + public String getIcon() { + return icon; + } + + public static ActionType toAction(String actionType) { + if (actionType == null) { + return null; + } + try { + return ActionType.valueOf(actionType.toUpperCase()); + } catch (IllegalArgumentException e) { + return null; + } + } +} diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/Bundle.properties b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/Bundle.properties new file mode 100644 index 000000000000..9bea6f63cd3a --- /dev/null +++ b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/Bundle.properties @@ -0,0 +1,27 @@ +ServerMavenPropertiesPanel.section.ai=AI Agent +ServerMavenPropertiesPanel.aiAgentLabel.text=Enable AI Agent: +ServerMavenPropertiesPanel.aiApiKeyLabel.text=API Key: +ServerMavenPropertiesPanel.aiProviderLabel.text=Provider: +ServerMavenPropertiesPanel.aiProviderLocLabel.text=Provider Location: +ServerMavenPropertiesPanel.aiModelLabel.text=Model: +ServerMavenPropertiesPanel.section.server=Server Configuration +ServerMavenPropertiesPanel.section.remote=Remote Connection +ServerMavenPropertiesPanel.section.devmode=Dev Mode +ServerMavenPropertiesPanel.serverVersionLabel.text=Payara Server Version: +ServerMavenPropertiesPanel.serverPathLabel.text=Server Path: +ServerMavenPropertiesPanel.serverPathBrowse.tooltip=Browse for Payara Server installation directory +ServerMavenPropertiesPanel.domainNameLabel.text=Domain Name: +ServerMavenPropertiesPanel.contextRootLabel.text=Context Root: +ServerMavenPropertiesPanel.instanceNameLabel.text=Instance Name: +ServerMavenPropertiesPanel.explodedLabel.text=Exploded: +ServerMavenPropertiesPanel.remoteLabel.text=Remote: +ServerMavenPropertiesPanel.hostNameLabel.text=Host Name: +ServerMavenPropertiesPanel.adminPortLabel.text=Admin Port: +ServerMavenPropertiesPanel.adminUserLabel.text=Admin User: +ServerMavenPropertiesPanel.hotDeployLabel.text=Hot Deploy: +ServerMavenPropertiesPanel.autoDeployLabel.text=Auto Deploy: +ServerMavenPropertiesPanel.liveReloadLabel.text=Live Reload: +ServerMavenPropertiesPanel.keepStateLabel.text=Keep State: +ServerMavenPropertiesPanel.trimLogLabel.text=Trim Log: +ServerMavenPropertiesPanel.daemonLabel.text=Daemon: +ServerMavenPropertiesPanel.ignoreTestLabel.text=Ignore Test Changes: diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/LookupProviderImpl.java b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/LookupProviderImpl.java new file mode 100644 index 000000000000..bf50f2ad79e0 --- /dev/null +++ b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/LookupProviderImpl.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.payara.server.maven.project; + +import org.netbeans.api.project.Project; +import static org.netbeans.modules.payara.server.maven.plugin.Constants.MAVEN_WAR_PROJECT_TYPE; +import org.netbeans.spi.project.LookupProvider; +import org.openide.util.Lookup; +import org.openide.util.lookup.Lookups; +import org.openide.util.lookup.ProxyLookup; + +/** + * Adds {@link ServerMavenApplicationContent} to every Maven WAR project, plus + * a dynamic extra lookup that receives a {@link ServerMavenIcon} only when the + * project is detected as a payara-server-maven-plugin project. This ensures the + * icon only appears in server-maven project lookups and never interferes with + * Micro or plain WAR project icon resolution. + * + * @author Gaurav Gupta + */ +@LookupProvider.Registration(projectType = MAVEN_WAR_PROJECT_TYPE) +public class LookupProviderImpl implements LookupProvider { + + @Override + public Lookup createAdditionalLookup(Lookup lookup) { + Project project = lookup.lookup(Project.class); + ServerMavenApplicationContent content = new ServerMavenApplicationContent(project); + return new ProxyLookup(Lookups.singleton(content), content.getExtraLookup()); + } +} diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/PayaraAIModelRegistry.java b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/PayaraAIModelRegistry.java new file mode 100644 index 000000000000..8e90df082f4e --- /dev/null +++ b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/PayaraAIModelRegistry.java @@ -0,0 +1,201 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.payara.server.maven.project; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Fetches available AI model names for each provider. + *

+ * Cloud providers: fetched from OpenRouter's public API with a 30-minute cache.
+ * Local providers (Ollama, LM Studio, GPT4All): fetched live from the local + * server API using the configured or default base URL. + * + * @author Gaurav Gupta + */ +public final class PayaraAIModelRegistry { + + // ── Cloud (OpenRouter) ──────────────────────────────────────────────────── + + private static final String OPENROUTER_URL = "https://openrouter.ai/api/v1/models"; + private static final long CACHE_TTL_MS = Duration.ofMinutes(30).toMillis(); + + private static final Pattern ID_PATTERN = Pattern.compile("\"id\"\\s*:\\s*\"([^\"]+)\""); + private static final Pattern NAME_PATTERN = Pattern.compile("\"name\"\\s*:\\s*\"([^\"]+)\""); + + private static volatile List CACHE = Collections.emptyList(); + private static volatile long lastFetch = 0; + + private PayaraAIModelRegistry() {} + + // ── Local providers ─────────────────────────────────────────────────────── + + public static final Set LOCAL_PROVIDERS = new HashSet<>( + Arrays.asList("OLLAMA", "LM_STUDIO", "GPT4ALL")); + + private static final Map DEFAULT_BASE_URLS = new LinkedHashMap<>(); + static { + DEFAULT_BASE_URLS.put("OLLAMA", "http://localhost:11434"); + DEFAULT_BASE_URLS.put("LM_STUDIO", "http://localhost:1234"); + DEFAULT_BASE_URLS.put("GPT4ALL", "http://localhost:4891"); + } + + /** + * Returns model names for a local provider by querying its running server. + * Falls back to an empty list if the server is not reachable. + * + * @param provider local provider key (OLLAMA, LM_STUDIO, GPT4ALL) + * @param providerLocation custom base URL, or empty/null to use the default + */ + public static List getLocalModels(String provider, String providerLocation) { + String base = (providerLocation != null && !providerLocation.trim().isEmpty()) + ? providerLocation.trim().replaceAll("/$", "") + : DEFAULT_BASE_URLS.getOrDefault(provider, "http://localhost:8080"); + try { + if ("OLLAMA".equals(provider)) { + return fetchNames(base + "/api/tags", NAME_PATTERN); + } else { + // LM Studio and GPT4All both expose an OpenAI-compatible /v1/models + return fetchIds(base + "/v1/models"); + } + } catch (Exception ignored) { + return Collections.emptyList(); + } + } + + // ── Cloud providers (OpenRouter) ────────────────────────────────────────── + + private static final Map> PROVIDER_PREFIXES = new LinkedHashMap<>(); + static { + PROVIDER_PREFIXES.put("OPEN_AI", Arrays.asList("openai/")); + PROVIDER_PREFIXES.put("ANTHROPIC", Arrays.asList("anthropic/")); + PROVIDER_PREFIXES.put("GOOGLE", Arrays.asList("google/")); + PROVIDER_PREFIXES.put("MISTRAL", Arrays.asList("mistralai/", "mistral/")); + PROVIDER_PREFIXES.put("GROQ", Arrays.asList("meta-llama/", "groq/", "mixtral", "llama")); + PROVIDER_PREFIXES.put("DEEPSEEK", Arrays.asList("deepseek/")); + PROVIDER_PREFIXES.put("DEEPINFRA", Collections.emptyList()); + PROVIDER_PREFIXES.put("CUSTOM_OPEN_AI", Collections.emptyList()); + } + + public static List getModels() { + if (!CACHE.isEmpty() + && (System.currentTimeMillis() - lastFetch) < CACHE_TTL_MS) { + return CACHE; + } + synchronized (PayaraAIModelRegistry.class) { + if (!CACHE.isEmpty() + && (System.currentTimeMillis() - lastFetch) < CACHE_TTL_MS) { + return CACHE; + } + try { + List fetched = fetchIds(OPENROUTER_URL); + if (!fetched.isEmpty()) { + CACHE = fetched; + lastFetch = System.currentTimeMillis(); + } + } catch (Exception ignored) { + } + return CACHE; + } + } + + public static List getModelsForProvider(String provider) { + List all = getModels(); + List prefixes = PROVIDER_PREFIXES.get(provider); + if (prefixes == null || prefixes.isEmpty()) { + return all; + } + List filtered = new ArrayList<>(); + for (String id : all) { + for (String prefix : prefixes) { + if (id.startsWith(prefix)) { + int slash = id.indexOf('/'); + filtered.add(slash >= 0 ? id.substring(slash + 1) : id); + break; + } + } + } + return filtered; + } + + // ── HTTP helpers ────────────────────────────────────────────────────────── + + private static String httpGet(String apiUrl) throws Exception { + HttpURLConnection conn = (HttpURLConnection) new URL(apiUrl).openConnection(); + conn.setRequestMethod("GET"); + conn.setConnectTimeout(3_000); + conn.setReadTimeout(5_000); + conn.setRequestProperty("Accept", "application/json"); + try { + if (conn.getResponseCode() != 200) { + return ""; + } + StringBuilder sb = new StringBuilder(); + try (InputStream is = conn.getInputStream(); + BufferedReader br = new BufferedReader( + new InputStreamReader(is, StandardCharsets.UTF_8))) { + String line; + while ((line = br.readLine()) != null) { + sb.append(line); + } + } + return sb.toString(); + } finally { + conn.disconnect(); + } + } + + /** Extracts all {@code "id":"value"} entries from a JSON response. */ + private static List fetchIds(String apiUrl) throws Exception { + String json = httpGet(apiUrl); + List ids = new ArrayList<>(); + Matcher m = ID_PATTERN.matcher(json); + while (m.find()) { + ids.add(m.group(1)); + } + return ids; + } + + /** Extracts all {@code "name":"value"} entries from a JSON response (Ollama). */ + private static List fetchNames(String apiUrl, Pattern pattern) throws Exception { + String json = httpGet(apiUrl); + List names = new ArrayList<>(); + Matcher m = pattern.matcher(json); + while (m.find()) { + names.add(m.group(1)); + } + return names; + } +} diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenActionsProvider.java b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenActionsProvider.java new file mode 100644 index 000000000000..c7d1f7d3a6cb --- /dev/null +++ b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenActionsProvider.java @@ -0,0 +1,151 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.payara.server.maven.project; + +import static org.netbeans.modules.payara.server.maven.plugin.Constants.*; +import java.io.InputStream; +import java.util.Set; +import java.util.prefs.Preferences; +import org.netbeans.api.annotations.common.StaticResource; +import org.netbeans.api.project.Project; +import static org.netbeans.api.project.ProjectUtils.getPreferences; +import org.netbeans.modules.maven.api.NbMavenProject; +import org.netbeans.modules.maven.api.execute.RunConfig; +import org.netbeans.modules.maven.execute.model.NetbeansActionMapping; +import org.netbeans.modules.maven.spi.actions.AbstractMavenActionsProvider; +import org.netbeans.modules.maven.spi.actions.MavenActionsProvider; +import static org.netbeans.spi.project.ActionProvider.COMMAND_DEBUG; +import static org.netbeans.spi.project.ActionProvider.COMMAND_PROFILE; +import static org.netbeans.spi.project.ActionProvider.COMMAND_RUN; +import org.netbeans.spi.project.ProjectServiceProvider; +import org.openide.util.Lookup; + +/** + * @author Gaurav Gupta + */ +@ProjectServiceProvider( + service = MavenActionsProvider.class, + projectType = MAVEN_WAR_PROJECT_TYPE +) +public class ServerMavenActionsProvider implements MavenActionsProvider { + + @StaticResource + static final String ACTION_MAPPINGS = + "org/netbeans/modules/payara/server/maven/project/resources/action-mapping.xml"; + + final AbstractMavenActionsProvider actionsProvider = new AbstractMavenActionsProvider() { + @Override + protected InputStream getActionDefinitionStream() { + return ServerMavenActionsProvider.class + .getClassLoader() + .getResourceAsStream(ACTION_MAPPINGS); + } + + @Override + public boolean isActionEnable(String action, Project project, Lookup lookup) { + NbMavenProject nbMavenProject = project.getLookup().lookup(NbMavenProject.class); + if (nbMavenProject == null || !WAR_PACKAGING.equals(nbMavenProject.getPackagingType())) { + return false; + } + switch (action) { + case COMMAND_RUN: + case COMMAND_DEBUG: + case COMMAND_PROFILE: + case RUN_SINGLE_ACTION: + case DEBUG_SINGLE_ACTION: + case PROFILE_SINGLE_ACTION: + break; + default: + return false; + } + return ServerMavenApplication.getInstance(project) != null; + } + }; + + @Override + public RunConfig createConfigForDefaultAction(String actionName, Project project, Lookup lookup) { + if (ServerMavenApplication.getInstance(project) == null) { + return null; + } + RunConfig rc = actionsProvider.createConfigForDefaultAction(actionName, project, lookup); + if (rc == null) { + return null; + } + Preferences pref = getPreferences(project, ServerMavenApplication.class, true); + setIfNotEmpty(rc, MVNPROP_SERVER_VERSION, pref.get(PREF_SERVER_VERSION, "")); + setIfNotEmpty(rc, MVNPROP_SERVER_PATH, pref.get(PREF_SERVER_PATH, "")); + setIfNotEmpty(rc, MVNPROP_DOMAIN_NAME, pref.get(PREF_DOMAIN_NAME, "")); + setIfNotEmpty(rc, MVNPROP_CONTEXT_ROOT, pref.get(PREF_CONTEXT_ROOT, "")); + setIfNotEmpty(rc, MVNPROP_INSTANCE_NAME, pref.get(PREF_INSTANCE_NAME, "")); + if (pref.getBoolean(PREF_REMOTE, false)) { + rc.setProperty(MVNPROP_REMOTE, Boolean.TRUE.toString()); + setIfNotEmpty(rc, MVNPROP_HOST_NAME, pref.get(PREF_HOST_NAME, "")); + setIfNotEmpty(rc, MVNPROP_ADMIN_PORT, pref.get(PREF_ADMIN_PORT, "")); + setIfNotEmpty(rc, MVNPROP_ADMIN_USER, pref.get(PREF_ADMIN_USER, "")); + } + if (pref.getBoolean(PREF_EXPLODED, true)) rc.setProperty(MVNPROP_EXPLODED, Boolean.TRUE.toString()); + if (pref.getBoolean(PREF_HOT_DEPLOY, false)) rc.setProperty(MVNPROP_HOT_DEPLOY, Boolean.TRUE.toString()); + if (pref.getBoolean(PREF_AUTO_DEPLOY, true)) rc.setProperty(MVNPROP_AUTO_DEPLOY, Boolean.TRUE.toString()); + if (pref.getBoolean(PREF_LIVE_RELOAD, true)) rc.setProperty(MVNPROP_LIVE_RELOAD, Boolean.TRUE.toString()); + if (pref.getBoolean(PREF_KEEP_STATE, true)) rc.setProperty(MVNPROP_KEEP_STATE, Boolean.TRUE.toString()); + if (pref.getBoolean(PREF_TRIM_LOG, true)) rc.setProperty(MVNPROP_TRIM_LOG, Boolean.TRUE.toString()); + if (pref.getBoolean(PREF_DAEMON, false)) rc.setProperty(MVNPROP_DAEMON, Boolean.TRUE.toString()); + if (!pref.getBoolean(PREF_IGNORE_TEST, true)) rc.setProperty(MVNPROP_IGNORE_TEST, Boolean.FALSE.toString()); + if (pref.getBoolean(PREF_AI_AGENT, false)) { + rc.setProperty(MVNPROP_AI_AGENT, Boolean.TRUE.toString()); + String apiKey = pref.get(PREF_AI_API_KEY, ""); + if (apiKey.isEmpty()) { + apiKey = System.getenv(ENV_AI_API_KEY); + } + setIfNotEmpty(rc, MVNPROP_AI_API_KEY, apiKey != null ? apiKey : ""); + setIfNotEmpty(rc, MVNPROP_AI_PROVIDER, pref.get(PREF_AI_PROVIDER, "")); + setIfNotEmpty(rc, MVNPROP_AI_PROVIDER_LOC, pref.get(PREF_AI_PROVIDER_LOC, "")); + setIfNotEmpty(rc, MVNPROP_AI_MODEL, pref.get(PREF_AI_MODEL, "")); + } + return rc; + } + + @Override + public NetbeansActionMapping getMappingForAction(String actionName, Project project) { + if (ServerMavenApplication.getInstance(project) != null) { + return actionsProvider.getMappingForAction(actionName, project); + } + return null; + } + + @Override + public boolean isActionEnable(String action, Project project, Lookup lookup) { + if (ServerMavenApplication.getInstance(project) != null) { + return actionsProvider.isActionEnable(action, project, lookup); + } + return false; + } + + @Override + public Set getSupportedDefaultActions() { + return actionsProvider.getSupportedDefaultActions(); + } + + private static void setIfNotEmpty(org.netbeans.modules.maven.api.execute.RunConfig rc, + String key, String value) { + if (value != null && !value.isEmpty()) { + rc.setProperty(key, value); + } + } +} diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenApplication.java b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenApplication.java new file mode 100644 index 000000000000..c59a46c9d31e --- /dev/null +++ b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenApplication.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.payara.server.maven.project; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.maven.project.MavenProject; +import org.netbeans.api.project.Project; +import static org.netbeans.modules.payara.server.maven.plugin.Constants.PAYARA_SERVER_MAVEN_PLUGIN; +import static org.netbeans.modules.payara.server.maven.plugin.Constants.PLUGIN_ARTIFACT_ID; +import static org.netbeans.modules.payara.server.maven.plugin.Constants.PLUGIN_GROUP_ID; +import org.netbeans.modules.maven.api.NbMavenProject; +import org.openide.execution.ExecutorTask; + +/** + * @author Gaurav Gupta + */ +public class ServerMavenApplication { + + private final Project project; + + private final MavenProject mavenProject; + + private volatile ActionType buildActionType; + + private volatile boolean buildAction; + + private volatile ActionType runActionType; + + private final AtomicInteger runActionCount = new AtomicInteger(); + + private volatile boolean reloadAction; + + private final List runningTasks = new ArrayList<>(); + + private static final String SINGLE = ".single.deploy"; + + public ServerMavenApplication(Project project) { + this.project = project; + NbMavenProject nbMavenProject = project.getLookup().lookup(NbMavenProject.class); + this.mavenProject = nbMavenProject.getMavenProject(); + } + + public Project getProject() { + return project; + } + + public MavenProject getMavenProject() { + return mavenProject; + } + + public void setBuilding(boolean buildAction, String actionType) { + ActionType at = ActionType.toAction(actionType.replace("-", "_")); + this.buildActionType = at; + setBuilding(buildAction); + } + + public void setBuilding(boolean buildAction) { + this.buildAction = buildAction; + NbMavenProject.fireMavenProjectReload(project); + } + + public ActionType getBuildActionType() { + return buildActionType; + } + + public boolean isBuilding() { + return buildAction; + } + + public void setRunning(boolean running, String actionType) { + ActionType at = ActionType.toAction(actionType.replace(SINGLE, "")); + this.runActionType = at; + setRunning(running); + } + + public void setRunning(boolean running) { + if (running) { + runActionCount.incrementAndGet(); + } else if (isRunning()) { + runActionCount.decrementAndGet(); + } + NbMavenProject.fireMavenProjectReload(project); + } + + public boolean isRunning() { + return runActionCount.get() > 0; + } + + public int getRunningInstanceCount() { + return runActionCount.get(); + } + + public ActionType getRunActionType() { + return runActionType; + } + + public void setLoading(boolean loading) { + this.reloadAction = loading; + NbMavenProject.fireMavenProjectReload(project); + } + + public boolean isLoading() { + return reloadAction; + } + + public synchronized void addRunningTask(ExecutorTask task) { + runningTasks.add(task); + } + + public synchronized void stopAllRunningTasks() { + for (ExecutorTask task : runningTasks) { + task.stop(); + } + runningTasks.clear(); + } + + public static ServerMavenApplication getInstance(Project project) { + if (project != null) { + ServerMavenApplicationContent content = project.getLookup().lookup(ServerMavenApplicationContent.class); + if (content != null) { + return content.getApplication(); + } + } + return null; + } + + public static boolean isPayaraServerMavenProject(Project project) { + if (project == null) { + return false; + } + NbMavenProject nbMavenProject = project.getLookup().lookup(NbMavenProject.class); + if (nbMavenProject == null) { + return false; + } + MavenProject mp = nbMavenProject.getMavenProject(); + // Check resolved artifacts first (populated after Maven resolution) + if (mp.getPluginArtifactMap().containsKey(PAYARA_SERVER_MAVEN_PLUGIN)) { + return true; + } + // Check declared build plugins (populated from the POM model, no resolution needed) + return mp.getBuildPlugins().stream() + .anyMatch(p -> PLUGIN_GROUP_ID.equals(p.getGroupId()) + && PLUGIN_ARTIFACT_ID.equals(p.getArtifactId())); + } +} diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenApplicationContent.java b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenApplicationContent.java new file mode 100644 index 000000000000..6a2e3addead4 --- /dev/null +++ b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenApplicationContent.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.payara.server.maven.project; + +import java.beans.PropertyChangeListener; +import javax.swing.SwingUtilities; +import org.netbeans.api.project.Project; +import org.netbeans.modules.maven.api.NbMavenProject; +import org.openide.util.Lookup; +import org.openide.util.lookup.AbstractLookup; +import org.openide.util.lookup.InstanceContent; + +/** + * Lookup-registered wrapper that carries a {@link ServerMavenApplication}. + *

+ * Detection is deferred to the first call of {@link #getApplication()} that + * occurs after the Maven project model has fully loaded, so it is safe to call + * from the Event Dispatch Thread without causing I/O hangs. + *

+ * When a server-maven project is detected, a {@link ServerMavenIcon} is added + * to {@link #getExtraLookup()} so the icon is only present in server-maven + * project lookups — not in plain WAR or Micro project lookups. + *

+ * If the Maven model has not yet loaded at construction time, a + * {@link NbMavenProject#PROP_PROJECT} listener is registered to trigger + * detection as soon as Maven finishes loading. + * + * @author Gaurav Gupta + */ +public class ServerMavenApplicationContent { + + private final Project project; + private volatile boolean initialized; + private volatile ServerMavenApplication application; + + private final InstanceContent extraServices = new InstanceContent(); + private final Lookup extraLookup = new AbstractLookup(extraServices); + + private PropertyChangeListener mavenLoadListener; + + public ServerMavenApplicationContent(Project project) { + this.project = project; + NbMavenProject nbmp = project.getLookup().lookup(NbMavenProject.class); + if (nbmp != null) { + if (nbmp.isMavenProjectLoaded()) { + getApplication(); + } else { + mavenLoadListener = evt -> { + if (NbMavenProject.PROP_PROJECT.equals(evt.getPropertyName())) { + getApplication(); + if (initialized) { + nbmp.removePropertyChangeListener(mavenLoadListener); + mavenLoadListener = null; + } + } + }; + nbmp.addPropertyChangeListener(mavenLoadListener); + } + } + } + + public Lookup getExtraLookup() { + return extraLookup; + } + + public ServerMavenApplication getApplication() { + if (!initialized) { + NbMavenProject nbmp = project.getLookup().lookup(NbMavenProject.class); + if (nbmp != null && nbmp.isMavenProjectLoaded()) { + synchronized (this) { + if (!initialized) { + if (ServerMavenApplication.isPayaraServerMavenProject(project)) { + application = new ServerMavenApplication(project); + ServerMavenIcon icon = new ServerMavenIcon(); + icon.setProject(project); + extraServices.add(icon); + SwingUtilities.invokeLater( + () -> NbMavenProject.fireMavenProjectReload(project)); + } + initialized = true; + } + } + } + } + return application; + } + + synchronized void setApplication(ServerMavenApplication application) { + this.application = application; + this.initialized = true; + } +} diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenIcon.java b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenIcon.java new file mode 100644 index 000000000000..b706f9643210 --- /dev/null +++ b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenIcon.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.payara.server.maven.project; + +import static org.netbeans.modules.payara.server.maven.plugin.Constants.PROJECT_ICON; +import static org.netbeans.modules.payara.server.maven.plugin.Constants.RELOAD_ICON; +import static org.netbeans.modules.payara.server.maven.plugin.Constants.RESTART_ICON; +import javax.swing.Icon; +import org.netbeans.api.project.Project; +import org.netbeans.modules.maven.j2ee.ui.EEIcons.WarIcon; +import org.netbeans.modules.maven.spi.nodes.SpecialIcon; +import static org.openide.util.ImageUtilities.loadImageIcon; + +/** + * Provides the Payara Server Maven project icon. + *

+ * Not registered globally — added to the project lookup dynamically by + * {@link ServerMavenApplicationContent} only when the project is confirmed to + * use the payara-server-maven-plugin. This ensures it never appears in plain + * WAR or Micro project lookups. + * + * @author Gaurav Gupta + */ +public class ServerMavenIcon extends WarIcon { + + private volatile Project project; + + public void setProject(Project project) { + this.project = project; + } + + @Override + public Icon getIcon() { + ServerMavenApplication application = ServerMavenApplication.getInstance(project); + String icon = PROJECT_ICON; + if (application == null) { + return super.getIcon(); + } else if (application.isLoading()) { + icon = RELOAD_ICON; + } else if (application.isBuilding() && application.getBuildActionType() != null) { + icon = application.getBuildActionType().getIcon(); + } else if (application.isRunning()) { + if (application.getRunningInstanceCount() > 1) { + icon = RESTART_ICON; + } else if (application.getRunActionType() != null) { + icon = application.getRunActionType().getIcon(); + } + } + return loadImageIcon(icon, true); + } +} diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenProjectHook.java b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenProjectHook.java new file mode 100644 index 000000000000..133f0bb7988d --- /dev/null +++ b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenProjectHook.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.payara.server.maven.project; + +import org.netbeans.api.project.Project; +import static org.netbeans.modules.payara.server.maven.plugin.Constants.MAVEN_WAR_PROJECT_TYPE; +import org.netbeans.modules.maven.j2ee.ProjectHookImpl; +import org.netbeans.spi.project.ProjectServiceProvider; +import org.netbeans.spi.project.ui.ProjectOpenedHook; + +/** + * @author Gaurav Gupta + */ +@ProjectServiceProvider( + service = ProjectOpenedHook.class, + projectType = MAVEN_WAR_PROJECT_TYPE +) +public class ServerMavenProjectHook extends ProjectHookImpl { + + private final Project project; + + public ServerMavenProjectHook(Project project) { + super(project); + this.project = project; + } + + @Override + public void projectOpened() { + // ServerMavenApplicationContent.getApplication() handles detection + // and dynamically registers ServerMavenIcon when Maven model loads. + ServerMavenApplication.getInstance(project); + } + + @Override + public void projectClosed() { + ServerMavenApplication app = ServerMavenApplication.getInstance(project); + if (app != null) { + app.stopAllRunningTasks(); + } + } +} diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenPropertiesPanel.java b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenPropertiesPanel.java new file mode 100644 index 000000000000..d3b99a12dc6c --- /dev/null +++ b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenPropertiesPanel.java @@ -0,0 +1,436 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.payara.server.maven.project; + +import java.awt.BorderLayout; +import java.io.File; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.prefs.Preferences; +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import javax.swing.JTextField; +import javax.swing.Scrollable; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import org.netbeans.api.project.Project; +import static org.netbeans.api.project.ProjectUtils.getPreferences; +import static org.netbeans.modules.payara.server.maven.plugin.Constants.*; +import org.netbeans.modules.maven.api.customizer.ModelHandle2; +import org.netbeans.modules.payara.tooling.data.PayaraPlatformVersion; +import org.netbeans.modules.payara.tooling.data.PayaraPlatformVersionAPI; +import org.openide.util.NbBundle; +import org.openide.util.RequestProcessor; + +/** + * Project Properties panel for the Payara Server Maven Plugin, + * organised into collapsible sections. + * + * @author Gaurav Gupta + */ +public class ServerMavenPropertiesPanel extends JPanel implements Scrollable { + + private final Preferences pref; + + private static final RequestProcessor RP = new RequestProcessor(ServerMavenPropertiesPanel.class); + + // Server Configuration + private final JComboBox serverVersionCombo = new JComboBox<>(); + private final JTextField serverPathField = new JTextField(); + private final JTextField domainNameField = new JTextField(); + private final JTextField contextRootField = new JTextField(); + private final JTextField instanceNameField = new JTextField(); + + // Remote Connection + private final JCheckBox remoteCheckBox = new JCheckBox(); + private final JTextField hostNameField = new JTextField(); + private final JTextField adminPortField = new JTextField(); + private final JTextField adminUserField = new JTextField(); + + // Dev Mode + private final JCheckBox explodedCheckBox = new JCheckBox(); + private final JCheckBox hotDeployCheckBox = new JCheckBox(); + private final JCheckBox autoDeployCheckBox = new JCheckBox(); + private final JCheckBox liveReloadCheckBox = new JCheckBox(); + private final JCheckBox keepStateCheckBox = new JCheckBox(); + private final JCheckBox trimLogCheckBox = new JCheckBox(); + private final JCheckBox ignoreTestCheckBox = new JCheckBox(); + + // AI Agent + private final JCheckBox aiAgentCheckBox = new JCheckBox(); + private final JTextField aiApiKeyField = new JTextField(); + private final JComboBox aiProviderCombo = new JComboBox<>(); + private final JTextField aiProviderLocField = new JTextField(); + private final JComboBox aiModelCombo = new JComboBox<>(); + + public ServerMavenPropertiesPanel(ModelHandle2 handle, Project project) { + pref = getPreferences(project, ServerMavenApplication.class, true); + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); + + remoteCheckBox.addActionListener(e -> updateRemoteEnabled()); + + // ── Section 1: Server Configuration ────────────────────────────────── + CollapsibleSection serverSection = new CollapsibleSection(msg("section.server"), true); + serverVersionCombo.setEditable(true); + serverVersionCombo.addItem("Loading..."); + serverSection.addComboRow(msg("serverVersionLabel.text"), serverVersionCombo); + + JButton serverPathBrowseButton = new JButton("..."); + serverPathBrowseButton.setToolTipText(msg("serverPathBrowse.tooltip")); + serverPathBrowseButton.addActionListener(e -> { + JFileChooser chooser = new JFileChooser(); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + String current = serverPathField.getText().trim(); + if (!current.isEmpty()) { + chooser.setCurrentDirectory(new File(current)); + } + if (chooser.showOpenDialog(ServerMavenPropertiesPanel.this) == JFileChooser.APPROVE_OPTION) { + serverPathField.setText(chooser.getSelectedFile().getAbsolutePath()); + } + }); + JPanel serverPathPanel = new JPanel(new BorderLayout(4, 0)); + serverPathPanel.setOpaque(false); + serverPathPanel.add(serverPathField, BorderLayout.CENTER); + serverPathPanel.add(serverPathBrowseButton, BorderLayout.EAST); + serverSection.addComponentRow(msg("serverPathLabel.text"), serverPathPanel); + serverSection.addRow(msg("domainNameLabel.text"), domainNameField); + serverSection.addRow(msg("contextRootLabel.text"), contextRootField); + serverSection.addRow(msg("instanceNameLabel.text"), instanceNameField); + + // ── Section 2: Remote Connection ────────────────────────────────────── + CollapsibleSection remoteSection = new CollapsibleSection(msg("section.remote"), false); + remoteSection.addCheckRow(msg("remoteLabel.text"), remoteCheckBox); + remoteSection.addRow(msg("hostNameLabel.text"), hostNameField); + remoteSection.addRow(msg("adminPortLabel.text"), adminPortField); + remoteSection.addRow(msg("adminUserLabel.text"), adminUserField); + + // ── Section 3: Dev Mode ─────────────────────────────────────────────── + CollapsibleSection devSection = new CollapsibleSection(msg("section.devmode"), true); + devSection.addCheckRow(msg("explodedLabel.text"), explodedCheckBox); + devSection.addCheckRow(msg("hotDeployLabel.text"), hotDeployCheckBox); + devSection.addCheckRow(msg("autoDeployLabel.text"), autoDeployCheckBox); + devSection.addCheckRow(msg("liveReloadLabel.text"), liveReloadCheckBox); + devSection.addCheckRow(msg("keepStateLabel.text"), keepStateCheckBox); + devSection.addCheckRow(msg("trimLogLabel.text"), trimLogCheckBox); + devSection.addCheckRow(msg("ignoreTestLabel.text"), ignoreTestCheckBox); + + // ── Section 4: AI Agent ─────────────────────────────────────────────── + CollapsibleSection aiSection = new CollapsibleSection(msg("section.ai"), false); + aiSection.addCheckRow(msg("aiAgentLabel.text"), aiAgentCheckBox); + aiSection.addRow(msg("aiApiKeyLabel.text"), aiApiKeyField); + for (String p : AI_PROVIDERS) aiProviderCombo.addItem(p); + aiProviderCombo.setEditable(true); + aiSection.addComboRow(msg("aiProviderLabel.text"), aiProviderCombo); + aiSection.addRow(msg("aiProviderLocLabel.text"), aiProviderLocField); + aiModelCombo.setEditable(true); + aiModelCombo.addItem(""); + aiSection.addComboRow(msg("aiModelLabel.text"), aiModelCombo); + + add(serverSection); + add(Box.createVerticalStrut(6)); + add(remoteSection); + add(Box.createVerticalStrut(6)); + add(devSection); + add(Box.createVerticalStrut(6)); + add(aiSection); + add(Box.createVerticalGlue()); + + loadPreferences(); + updateRemoteEnabled(); + } + + private void loadPreferences() { + loadServerVersions(pref.get(PREF_SERVER_VERSION, "")); + serverPathField.setText(pref.get(PREF_SERVER_PATH, "")); + domainNameField.setText(pref.get(PREF_DOMAIN_NAME, "")); + contextRootField.setText(pref.get(PREF_CONTEXT_ROOT, "")); + instanceNameField.setText(pref.get(PREF_INSTANCE_NAME, "")); + + remoteCheckBox.setSelected(pref.getBoolean(PREF_REMOTE, false)); + hostNameField.setText(pref.get(PREF_HOST_NAME, "")); + adminPortField.setText(pref.get(PREF_ADMIN_PORT, "")); + adminUserField.setText(pref.get(PREF_ADMIN_USER, "")); + + explodedCheckBox.setSelected(pref.getBoolean(PREF_EXPLODED, true)); + hotDeployCheckBox.setSelected(pref.getBoolean(PREF_HOT_DEPLOY, false)); + autoDeployCheckBox.setSelected(pref.getBoolean(PREF_AUTO_DEPLOY, true)); + liveReloadCheckBox.setSelected(pref.getBoolean(PREF_LIVE_RELOAD, true)); + keepStateCheckBox.setSelected(pref.getBoolean(PREF_KEEP_STATE, true)); + trimLogCheckBox.setSelected(pref.getBoolean(PREF_TRIM_LOG, true)); + ignoreTestCheckBox.setSelected(pref.getBoolean(PREF_IGNORE_TEST, true)); + aiAgentCheckBox.setSelected(pref.getBoolean(PREF_AI_AGENT, false)); + String storedKey = pref.get(PREF_AI_API_KEY, ""); + aiApiKeyField.setText(storedKey); + String envKey = System.getenv(ENV_AI_API_KEY); + if (envKey != null && !envKey.isEmpty()) { + String tip = storedKey.isEmpty() + ? "Using $" + ENV_AI_API_KEY + " env var (enter a key here to override it)" + : "This key overrides the $" + ENV_AI_API_KEY + " env var"; + aiApiKeyField.setToolTipText(tip); + } + String savedProvider = pref.get(PREF_AI_PROVIDER, ""); + if (!savedProvider.isEmpty()) aiProviderCombo.setSelectedItem(savedProvider); + // Listen to provider changes to update model list + aiProviderCombo.addActionListener(e -> { + Object prov = aiProviderCombo.getSelectedItem(); + Object model = aiModelCombo.getSelectedItem(); + loadModelsForProvider( + prov != null ? prov.toString() : "", + model != null ? model.toString() : ""); + }); + loadModelsForProvider(savedProvider, pref.get(PREF_AI_MODEL, "")); + aiProviderLocField.setText(pref.get(PREF_AI_PROVIDER_LOC, "")); + } + + public void applyChanges() { + Object selVer = serverVersionCombo.getSelectedItem(); + pref.put(PREF_SERVER_VERSION, selVer != null ? selVer.toString().trim() : ""); + pref.put(PREF_SERVER_PATH, serverPathField.getText().trim()); + pref.put(PREF_DOMAIN_NAME, domainNameField.getText().trim()); + pref.put(PREF_CONTEXT_ROOT, contextRootField.getText().trim()); + pref.put(PREF_INSTANCE_NAME, instanceNameField.getText().trim()); + + pref.putBoolean(PREF_REMOTE, remoteCheckBox.isSelected()); + pref.put(PREF_HOST_NAME, hostNameField.getText().trim()); + pref.put(PREF_ADMIN_PORT, adminPortField.getText().trim()); + pref.put(PREF_ADMIN_USER, adminUserField.getText().trim()); + + pref.putBoolean(PREF_EXPLODED, explodedCheckBox.isSelected()); + pref.putBoolean(PREF_HOT_DEPLOY, hotDeployCheckBox.isSelected()); + pref.putBoolean(PREF_AUTO_DEPLOY, autoDeployCheckBox.isSelected()); + pref.putBoolean(PREF_LIVE_RELOAD, liveReloadCheckBox.isSelected()); + pref.putBoolean(PREF_KEEP_STATE, keepStateCheckBox.isSelected()); + pref.putBoolean(PREF_TRIM_LOG, trimLogCheckBox.isSelected()); + pref.putBoolean(PREF_IGNORE_TEST, ignoreTestCheckBox.isSelected()); + pref.putBoolean(PREF_AI_AGENT, aiAgentCheckBox.isSelected()); + pref.put(PREF_AI_API_KEY, aiApiKeyField.getText().trim()); + Object selProv = aiProviderCombo.getSelectedItem(); + pref.put(PREF_AI_PROVIDER, selProv != null ? selProv.toString().trim() : ""); + Object selModel = aiModelCombo.getSelectedItem(); + pref.put(PREF_AI_MODEL, selModel != null ? selModel.toString().trim() : ""); + pref.put(PREF_AI_PROVIDER_LOC, aiProviderLocField.getText().trim()); + } + + private void updateRemoteEnabled() { + boolean remote = remoteCheckBox.isSelected(); + hostNameField.setEnabled(remote); + adminPortField.setEnabled(remote); + adminUserField.setEnabled(remote); + } + + /** GenAIProvider enum values from ecosystem-ai (user can type custom values). */ + private static final List AI_PROVIDERS = Arrays.asList( + "", "OPEN_AI", "ANTHROPIC", "GOOGLE", "MISTRAL", "GROQ", + "DEEPSEEK", "DEEPINFRA", "OLLAMA", "LM_STUDIO", "GPT4ALL", "CUSTOM_OPEN_AI" + ); + + /** + * Populates the model combobox for the selected provider. + * Local providers use static lists; cloud providers fetch filtered models from OpenRouter. + */ + private void loadModelsForProvider(String provider, String savedModel) { + RP.post(() -> { + List models = new ArrayList<>(); + models.add(""); + if (provider != null && PayaraAIModelRegistry.LOCAL_PROVIDERS.contains(provider)) { + models.addAll(PayaraAIModelRegistry.getLocalModels( + provider, aiProviderLocField.getText().trim())); + } else if (provider != null && !provider.isEmpty()) { + // Cloud provider: fetch provider-filtered models from OpenRouter + models.addAll(PayaraAIModelRegistry.getModelsForProvider(provider)); + } + SwingUtilities.invokeLater(() -> { + Object current = aiModelCombo.getSelectedItem(); + String keep = (savedModel != null && !savedModel.isEmpty()) + ? savedModel : (current != null ? current.toString() : ""); + aiModelCombo.removeAllItems(); + models.forEach(aiModelCombo::addItem); + if (!keep.isEmpty()) { + aiModelCombo.setSelectedItem(keep); + if (!keep.equals(aiModelCombo.getSelectedItem())) { + aiModelCombo.addItem(keep); + aiModelCombo.setSelectedItem(keep); + } + } + }); + }); + } + + /** Loads Payara Server versions from the tooling API on a background thread. */ + private void loadServerVersions(String saved) { + RP.post(() -> { + List versions = new ArrayList<>(); + versions.add(""); // blank = "let the plugin decide" + try { + List fetched = PayaraPlatformVersion.getVersions(); + fetched.stream() + .sorted(Collections.reverseOrder()) + .forEach(v -> versions.add(v.toString())); + } catch (Exception ex) { + // network unavailable — fall through with empty list + } + SwingUtilities.invokeLater(() -> { + serverVersionCombo.removeAllItems(); + versions.forEach(serverVersionCombo::addItem); + if (!saved.isEmpty()) { + serverVersionCombo.setSelectedItem(saved); + if (!saved.equals(serverVersionCombo.getSelectedItem())) { + // version not in list (e.g. custom) — add and select it + serverVersionCombo.addItem(saved); + serverVersionCombo.setSelectedItem(saved); + } + } + }); + }); + } + + private static String msg(String key) { + return NbBundle.getMessage(ServerMavenPropertiesPanel.class, + "ServerMavenPropertiesPanel." + key); + } + + // ── Scrollable — tracks viewport width so no horizontal bar appears ──────── + + @Override public Dimension getPreferredScrollableViewportSize() { return getPreferredSize(); } + @Override public int getScrollableUnitIncrement(Rectangle r, int o, int d) { return 16; } + @Override public int getScrollableBlockIncrement(Rectangle r, int o, int d) { return 64; } + @Override public boolean getScrollableTracksViewportWidth() { return true; } + @Override public boolean getScrollableTracksViewportHeight() { return false; } + + // ── Collapsible section widget ──────────────────────────────────────────── + + private static final class CollapsibleSection extends JPanel { + + private static final String EXPANDED_ARROW = "▼ "; + private static final String COLLAPSED_ARROW = "► "; + + private boolean expanded; + private final String title; + private final JButton toggle; + private final JPanel content; + private final GridBagConstraints gbc; + private int rowIndex; + + CollapsibleSection(String title, boolean expanded) { + this.title = title; + this.expanded = expanded; + setLayout(new BorderLayout()); + setOpaque(false); + setMaximumSize(new java.awt.Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE)); + + // ── Header ───────────────────────────────────────────────────── + toggle = new JButton((expanded ? EXPANDED_ARROW : COLLAPSED_ARROW) + title); + toggle.setHorizontalAlignment(SwingConstants.LEFT); + toggle.setFont(toggle.getFont().deriveFont(Font.BOLD)); + toggle.setBorderPainted(false); + toggle.setContentAreaFilled(false); + toggle.setFocusPainted(false); + toggle.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + toggle.addActionListener(e -> toggleExpanded()); + + JPanel header = new JPanel(new BorderLayout(4, 0)); + header.setOpaque(false); + header.add(toggle, BorderLayout.WEST); + header.add(new JSeparator(), BorderLayout.CENTER); + + // ── Content ──────────────────────────────────────────────────── + content = new JPanel(new GridBagLayout()); + content.setOpaque(false); + content.setBorder(BorderFactory.createEmptyBorder(4, 20, 4, 0)); + + gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.insets = new Insets(3, 0, 3, 8); + gbc.gridy = 0; + + add(header, BorderLayout.NORTH); + if (expanded) { + add(content, BorderLayout.CENTER); + } + } + + void addComponentRow(String labelText, JPanel component) { + gbc.gridy = rowIndex++; + gbc.gridx = 0; gbc.weightx = 0; gbc.anchor = GridBagConstraints.WEST; + content.add(new JLabel(labelText), gbc); + gbc.gridx = 1; gbc.weightx = 1.0; + content.add(component, gbc); + } + + void addRow(String labelText, JTextField field) { + gbc.gridy = rowIndex++; + gbc.gridx = 0; gbc.weightx = 0; gbc.anchor = GridBagConstraints.WEST; + content.add(new JLabel(labelText), gbc); + gbc.gridx = 1; gbc.weightx = 1.0; + content.add(field, gbc); + } + + void addComboRow(String labelText, JComboBox combo) { + gbc.gridy = rowIndex++; + gbc.gridx = 0; gbc.weightx = 0; gbc.anchor = GridBagConstraints.WEST; + content.add(new JLabel(labelText), gbc); + gbc.gridx = 1; gbc.weightx = 1.0; + content.add(combo, gbc); + } + + void addCheckRow(String labelText, JCheckBox check) { + gbc.gridy = rowIndex++; + gbc.gridx = 0; gbc.weightx = 0; gbc.anchor = GridBagConstraints.WEST; + content.add(new JLabel(labelText), gbc); + gbc.gridx = 1; gbc.weightx = 1.0; + content.add(check, gbc); + } + + private void toggleExpanded() { + expanded = !expanded; + toggle.setText((expanded ? EXPANDED_ARROW : COLLAPSED_ARROW) + title); + if (expanded) { + add(content, BorderLayout.CENTER); + } else { + remove(content); + } + revalidate(); + repaint(); + // propagate layout change up to the containing scroll pane / panel + java.awt.Container p = getParent(); + if (p != null) { + p.revalidate(); + p.repaint(); + } + } + } +} diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenPropertiesPanelProvider.java b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenPropertiesPanelProvider.java new file mode 100644 index 000000000000..3f45d0f49ad9 --- /dev/null +++ b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/ServerMavenPropertiesPanelProvider.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.payara.server.maven.project; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JScrollPane; +import org.netbeans.api.project.Project; +import org.netbeans.modules.maven.api.customizer.ModelHandle2; +import org.netbeans.spi.project.ui.support.ProjectCustomizer; +import org.openide.util.Lookup; + +/** + * Contributes the "Payara Server Maven Plugin" category to the Maven WAR project's + * Project Properties dialog when the project declares + * {@code payara-server-maven-plugin}. + * + * @author Gaurav Gupta + */ +public class ServerMavenPropertiesPanelProvider + implements ProjectCustomizer.CompositeCategoryProvider { + + @ProjectCustomizer.CompositeCategoryProvider.Registration( + projectType = "org-netbeans-modules-maven", + position = 306 + ) + public static ServerMavenPropertiesPanelProvider createServerMaven() { + return new ServerMavenPropertiesPanelProvider(); + } + + @Override + public ProjectCustomizer.Category createCategory(Lookup context) { + Project project = context.lookup(Project.class); + if (ServerMavenApplication.getInstance(project) == null) { + return null; + } + return ProjectCustomizer.Category.create( + "PayaraServerMaven", // NOI18N + "Payara Server Maven Plugin", // NOI18N + null); + } + + @Override + public JComponent createComponent(ProjectCustomizer.Category category, Lookup context) { + Project project = context.lookup(Project.class); + if (ServerMavenApplication.getInstance(project) == null) { + return null; + } + ModelHandle2 handle = context.lookup(ModelHandle2.class); + ServerMavenPropertiesPanel panel = new ServerMavenPropertiesPanel(handle, project); + category.setStoreListener(e -> panel.applyChanges()); + JScrollPane scroll = new JScrollPane(panel); + scroll.setBorder(BorderFactory.createEmptyBorder()); + scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + scroll.getVerticalScrollBar().setUnitIncrement(16); + return scroll; + } +} diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/action-mapping.xml b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/action-mapping.xml new file mode 100644 index 000000000000..8f293f7f02d3 --- /dev/null +++ b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/action-mapping.xml @@ -0,0 +1,176 @@ + + + + + + + run + + war + + + package + payara-server:dev + + + false + + + + + run.single.deploy + + war + + + package + payara-server:dev + + + false + ${webpagePath} + + + + + + + debug + + war + + + package + payara-server:dev + + + -agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=${jpda.address} + true + false + + + + + debug.single.deploy + + war + + + package + payara-server:stop + payara-server:start + + + -agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=${jpda.address} + true + ${webpagePath} + false + + + + + + profile + + war + + + package + payara-server:stop + payara-server:start + + + + java + false + true + + + + + profile.single.deploy + + war + + + package + payara-server:stop + payara-server:start + + + + java + false + true + ${webpagePath} + + + + + + server-maven-dev + + war + + + package + payara-server:dev + + + false + + + + + server-maven-dev-debug + + war + + + package + payara-server:dev + + + -agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=${jpda.address} + true + false + + + + + + server-maven-stop + + payara-server:stop + + + + diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-build.png b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-build.png new file mode 100644 index 000000000000..b42e45e37284 Binary files /dev/null and b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-build.png differ diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-clean-build.png b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-clean-build.png new file mode 100644 index 000000000000..c541df5116db Binary files /dev/null and b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-clean-build.png differ diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-clean.png b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-clean.png new file mode 100644 index 000000000000..6d9f100149b1 Binary files /dev/null and b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-clean.png differ diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-debug.png b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-debug.png new file mode 100644 index 000000000000..eff28181c536 Binary files /dev/null and b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-debug.png differ diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-profile.png b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-profile.png new file mode 100644 index 000000000000..4387ea9d7d5c Binary files /dev/null and b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-profile.png differ diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-reload.png b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-reload.png new file mode 100644 index 000000000000..44174e425557 Binary files /dev/null and b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-reload.png differ diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-restart.png b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-restart.png new file mode 100644 index 000000000000..361b3f8833b3 Binary files /dev/null and b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-restart.png differ diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-start.png b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-start.png new file mode 100644 index 000000000000..a449beef7b64 Binary files /dev/null and b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven-start.png differ diff --git a/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven.png b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven.png new file mode 100644 index 000000000000..c14ecccce077 Binary files /dev/null and b/enterprise/payara.server.maven/src/org/netbeans/modules/payara/server/maven/project/resources/payara-server-maven.png differ diff --git a/enterprise/payara.tooling/nbproject/project.xml b/enterprise/payara.tooling/nbproject/project.xml index 0bdb476c095b..876ba7fe1619 100644 --- a/enterprise/payara.tooling/nbproject/project.xml +++ b/enterprise/payara.tooling/nbproject/project.xml @@ -90,6 +90,7 @@ org.netbeans.modules.payara.micro + org.netbeans.modules.payara.server.maven org.netbeans.modules.payara.common org.netbeans.modules.payara.eecommon org.netbeans.modules.payara.jakartaee diff --git a/java/maven.embedder/nbproject/project.xml b/java/maven.embedder/nbproject/project.xml index c53f48f76c96..63fb43604500 100644 --- a/java/maven.embedder/nbproject/project.xml +++ b/java/maven.embedder/nbproject/project.xml @@ -176,6 +176,7 @@ org.vaadin.netbeans.maven org.netbeans.modules.payara.tooling org.netbeans.modules.payara.micro + org.netbeans.modules.payara.server.maven org.netbeans.modules.jakarta.transformer org.netbeans.modules.j2ee.appengine diff --git a/java/maven.model/nbproject/project.xml b/java/maven.model/nbproject/project.xml index 0820307c5f28..c1377db8a77c 100644 --- a/java/maven.model/nbproject/project.xml +++ b/java/maven.model/nbproject/project.xml @@ -231,6 +231,7 @@ org.vaadin.netbeans.maven org.netbeans.modules.payara.micro + org.netbeans.modules.payara.server.maven org.netbeans.modules.jakarta.transformer org.netbeans.modules.j2ee.appengine diff --git a/java/maven/nbproject/project.xml b/java/maven/nbproject/project.xml index 94ff3287ed83..b498d6d5c5aa 100644 --- a/java/maven/nbproject/project.xml +++ b/java/maven/nbproject/project.xml @@ -654,6 +654,7 @@ org.vaadin.netbeans.maven org.netbeans.modules.payara.micro + org.netbeans.modules.payara.server.maven org.netbeans.modules.jakarta.transformer org.netbeans.modules.j2ee.appengine diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties index ffd892f7ba01..f3ba33465b05 100644 --- a/nbbuild/cluster.properties +++ b/nbbuild/cluster.properties @@ -785,6 +785,7 @@ nb.cluster.enterprise=\ payara.eecommon,\ payara.jakartaee,\ payara.micro,\ + payara.server.maven,\ payara.tooling,\ profiler.j2ee,\ projectimport.eclipse.web,\