From 03aebbf34c13e3902ac00a1578e268af65619797 Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Thu, 30 Mar 2017 17:01:22 +0100 Subject: [PATCH 01/22] Initial impl --- appserver/admingui/payara-fang/pom.xml | 57 ++ appserver/admingui/pom.xml | 1 + appserver/featuresets/payara/pom.xml | 7 + appserver/packager/payara-fang/pom.xml | 115 ++++ .../src/main/assembly/payara-fang.xml | 66 +++ .../src/main/resources/pkg_proto.py | 58 ++ appserver/packager/pom.xml | 1 + .../payara-fang/pom.xml | 31 ++ .../fang/service/PayaraFangLoader.java | 172 ++++++ .../fang/service/PayaraFangService.java | 66 +++ .../service/adapter/PayaraFangAdapter.java | 517 ++++++++++++++++++ .../adapter/PayaraFangAdapterState.java | 35 ++ .../adapter/PayaraFangEndpointDecider.java | 120 ++++ .../PayaraFangConfiguration.java | 32 ++ appserver/payara-appserver-modules/pom.xml | 1 + 15 files changed, 1279 insertions(+) create mode 100644 appserver/admingui/payara-fang/pom.xml create mode 100644 appserver/packager/payara-fang/pom.xml create mode 100644 appserver/packager/payara-fang/src/main/assembly/payara-fang.xml create mode 100644 appserver/packager/payara-fang/src/main/resources/pkg_proto.py create mode 100644 appserver/payara-appserver-modules/payara-fang/pom.xml create mode 100644 appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java create mode 100644 appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java create mode 100644 appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java create mode 100644 appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java create mode 100644 appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java create mode 100644 appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java diff --git a/appserver/admingui/payara-fang/pom.xml b/appserver/admingui/payara-fang/pom.xml new file mode 100644 index 00000000000..975303facab --- /dev/null +++ b/appserver/admingui/payara-fang/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + + fish.payara.admingui + admingui + 4.1.1.172-SNAPSHOT + + + payara-fang + Admin Console Install Fragment for Payara Fang + distribution-fragment + + + + + + org.jvnet.maven-antrun-extended-plugin + maven-antrun-extended-plugin + + + generate-sources + + + + + + + + + run + + + + + + + + + + fish.payara.monitoring + Fang + 0.0.1-ALPHA + war + true + + + diff --git a/appserver/admingui/pom.xml b/appserver/admingui/pom.xml index 6a6e44412f8..f11b2eab6c9 100644 --- a/appserver/admingui/pom.xml +++ b/appserver/admingui/pom.xml @@ -153,6 +153,7 @@ healthcheck-service-console-plugin newrelic-notifier-console-plugin jmx-monitoring-plugin + payara-fang diff --git a/appserver/featuresets/payara/pom.xml b/appserver/featuresets/payara/pom.xml index b9450f26c9c..539930ecac7 100644 --- a/appserver/featuresets/payara/pom.xml +++ b/appserver/featuresets/payara/pom.xml @@ -131,5 +131,12 @@ ${project.version} zip + + + org.glassfish.main.packager + payara-fang + ${project.version} + zip + diff --git a/appserver/packager/payara-fang/pom.xml b/appserver/packager/payara-fang/pom.xml new file mode 100644 index 00000000000..5c98acea434 --- /dev/null +++ b/appserver/packager/payara-fang/pom.xml @@ -0,0 +1,115 @@ + + + + 4.0.0 + + org.glassfish.main.packager + packages + 4.1.1.172-SNAPSHOT + + payara-fang + Payara Fang Package + distribution-fragment + This pom describes how to assemble the Payara Fang package + + + ${project.build.directory}/dependency + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + process-step1 + + + process-step2 + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + process-step3 + + + + + + + + ips + + false + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + process-step4 + + + + + org.glassfish.build + glassfishbuild-maven-plugin + + + process-step5 + + exec + + + + + + maven-resources-plugin + + + copy-resources + + + + + + + + + + + fish.payara.admingui + payara-fang + ${project.version} + zip + true + + + fish.payara.appserver + payara-fang + ${project.version} + + + + diff --git a/appserver/packager/payara-fang/src/main/assembly/payara-fang.xml b/appserver/packager/payara-fang/src/main/assembly/payara-fang.xml new file mode 100644 index 00000000000..a818075c979 --- /dev/null +++ b/appserver/packager/payara-fang/src/main/assembly/payara-fang.xml @@ -0,0 +1,66 @@ + + + + + stage-package + + dir + + + false + + + ${temp.dir}/nucleus + ${install.dir.name}/glassfish + + + ${temp.dir} + + nucleus/** + pkg_proto.py + + ${install.dir.name} + + + diff --git a/appserver/packager/payara-fang/src/main/resources/pkg_proto.py b/appserver/packager/payara-fang/src/main/resources/pkg_proto.py new file mode 100644 index 00000000000..2494487363c --- /dev/null +++ b/appserver/packager/payara-fang/src/main/resources/pkg_proto.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + # + # Copyright (c) 2016 Payara Foundation and/or its affiliates. All rights reserved. + # + # The contents of this file are subject to the terms of either the GNU + # General Public License Version 2 only ("GPL") or the Common Development + # and Distribution License("CDDL") (collectively, the "License"). You + # may not use this file except in compliance with the License. You can + # obtain a copy of the License at + # https://github.com/payara/Payara/blob/master/LICENSE.txt + # See the License for the specific + # language governing permissions and limitations under the License. + # + # When distributing the software, include this License Header Notice in each + # file and include the License file at glassfish/legal/LICENSE.txt. + # + # GPL Classpath Exception: + # The Payara Foundation designates this particular file as subject to the "Classpath" + # exception as provided by the Payara Foundation in the GPL Version 2 section of the License + # file that accompanied this code. + # + # Modifications: + # If applicable, add the following below the License Header, with the fields + # enclosed by brackets [] replaced by your own identifying information: + # "Portions Copyright [year] [name of copyright owner]" + # + # Contributor(s): + # If you wish your version of this file to be governed by only the CDDL or + # only the GPL Version 2, indicate your decision by adding "[Contributor] + # elects to include this software in this distribution under the [CDDL or GPL + # Version 2] license." If you don't indicate a single choice of license, a + # recipient has the option to distribute your version of this file under + # either the CDDL, the GPL Version 2 or to extend the choice of license to + # its licensees as provided above. However, if you add GPL Version 2 code + # and therefore, elected the GPL Version 2 license, then the option applies + # only if the new code is made subject to such option by the copyright + # holder. + +import imp + +conf = imp.load_source("pkg_conf", "../pkg_conf.py") + +pkg = { + "name" : "payara-fang", + "version" : conf.payaraFang_version, + "attributes" : { + "pkg.summary" : "Payara Fang Integration", + "pkg.description" : "Payara Fang module", + "info.classification" : "OSGi Service Platform Release 4", + }, + "dirtrees" : { "glassfish" : {}, + }, + "licenses" : { + "../../../../ApacheLicense.txt" : {"license" : "ApacheV2"}, + } + } diff --git a/appserver/packager/pom.xml b/appserver/packager/pom.xml index 032a7721ba6..decdd1506c7 100644 --- a/appserver/packager/pom.xml +++ b/appserver/packager/pom.xml @@ -179,6 +179,7 @@ payara-api environment-warning payara-rest-endpoints + payara-fang diff --git a/appserver/payara-appserver-modules/payara-fang/pom.xml b/appserver/payara-appserver-modules/payara-fang/pom.xml new file mode 100644 index 00000000000..9af73adddbd --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/pom.xml @@ -0,0 +1,31 @@ + + + 4.0.0 + + org.glassfish.main + payara-appserver-modules + 4.1.1.172-SNAPSHOT + + fish.payara.appserver + payara-fang + glassfish-jar + Payara Fang + + + + org.glassfish.main.common + glassfish-api + ${project.version} + + + org.glassfish.main.common + internal-api + ${project.version} + + + org.glassfish.main.core + kernel + ${project.version} + + + diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java new file mode 100644 index 00000000000..240ee8be2c6 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java @@ -0,0 +1,172 @@ +package fish.payara.appserver.fang.service; + +import com.sun.enterprise.config.serverbeans.Application; +import com.sun.enterprise.config.serverbeans.ApplicationRef; +import com.sun.enterprise.config.serverbeans.Domain; +import com.sun.enterprise.config.serverbeans.Engine; +import com.sun.enterprise.config.serverbeans.Module; +import com.sun.enterprise.config.serverbeans.Server; +import com.sun.enterprise.config.serverbeans.SystemApplications; +import com.sun.enterprise.v3.server.ApplicationLoaderService; +import fish.payara.appserver.fang.service.adapter.PayaraFangAdapter; +import fish.payara.appserver.fang.service.adapter.PayaraFangAdapterState; +import java.beans.PropertyVetoException; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.glassfish.api.admin.config.ApplicationName; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.internal.data.ApplicationInfo; +import org.glassfish.internal.data.ApplicationRegistry; +import org.glassfish.server.ServerEnvironmentImpl; +import org.jvnet.hk2.config.ConfigBean; +import org.jvnet.hk2.config.ConfigBeanProxy; +import org.jvnet.hk2.config.ConfigCode; +import org.jvnet.hk2.config.ConfigSupport; +import org.jvnet.hk2.config.TransactionFailure; + +/** + * + * @author Andrew Pielage + */ +public class PayaraFangLoader extends Thread { + private final Domain domain; + private final ServerEnvironmentImpl serverEnv; + private final String contextRoot; + private final PayaraFangAdapter payaraFangAdapter; + private final ServiceLocator habitat; + private final Logger logger = Logger.getLogger(PayaraFangLoader.class.getName()); + private final List vss; + + PayaraFangLoader(PayaraFangAdapter payaraFangAdapter, ServiceLocator habitat, Domain domain, + ServerEnvironmentImpl serverEnv, String contextRoot, List vss) { + this.payaraFangAdapter = payaraFangAdapter; + this.habitat = habitat; + this.domain = domain; + this.serverEnv = serverEnv; + this.contextRoot = contextRoot; + this.vss = vss; + } + + @Override + public void run() { + try { + if (domain.getSystemApplicationReferencedFrom(serverEnv.getInstanceName(), PayaraFangService.FANG_APP_NAME) + == null) { +// if (serverEnv.isDas()) { + registerApplication(); +// } else { +// logger.log(Level.WARNING, "Payara Fang not yet registered in the DAS"); +// return; +// } + } + + load(); + + // From within this Thread mark the installation process complete + payaraFangAdapter.setInstalling(false); + } catch (Exception ex) { + payaraFangAdapter.setInstalling(false); + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); + logger.log(Level.INFO, "Problem while attempting to register Payara Fang!", ex); + } + } + + + /** + * Register the application + * @throws Exception + */ + private void registerApplication() throws Exception { + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.REGISTERING); + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "Registering the Payara Fang Application..."); + } + + //create the application entry in domain.xml + ConfigCode code = new ConfigCode() { + @Override + public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, TransactionFailure { + SystemApplications systemApplications = (SystemApplications) proxies[0]; + Application application = systemApplications.createChild(Application.class); + systemApplications.getModules().add(application); + application.setName(PayaraFangService.FANG_APP_NAME); + application.setEnabled(Boolean.TRUE.toString()); + application.setObjectType("system-admin"); //TODO + application.setDirectoryDeployed("true"); + application.setContextRoot(contextRoot); + + try { + application.setLocation("${com.sun.aas.installRootURI}/lib/install/applications/" + + PayaraFangService.FANG_APP_NAME); + } catch (Exception me) { + // can't do anything + throw new RuntimeException(me); + } + + Module singleModule = application.createChild(Module.class); + application.getModule().add(singleModule); + singleModule.setName(application.getName()); + Engine webEngine = singleModule.createChild(Engine.class); + webEngine.setSniffer("web"); + Engine weldEngine = singleModule.createChild(Engine.class); + weldEngine.setSniffer("weld"); + singleModule.getEngines().add(webEngine); + singleModule.getEngines().add(weldEngine); + Server s = (Server) proxies[1]; + List arefs = s.getApplicationRef(); + ApplicationRef aref = s.createChild(ApplicationRef.class); + aref.setRef(application.getName()); + aref.setEnabled(Boolean.TRUE.toString()); + aref.setVirtualServers(getVirtualServerList()); + arefs.add(aref); + return true; + } + }; + + Server server = domain.getServerNamed(serverEnv.getInstanceName()); + ConfigSupport.apply(code, domain.getSystemApplications(), server); + + // Set the adapter state + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "Payara Fang Registered."); + } + } + + private String getVirtualServerList() { + if (vss == null) + return ""; + String s = Arrays.toString(vss.toArray(new String[vss.size()])); + //standard JDK implemetation always returns this enclosed in [], remove them + s = s.substring(1, s.length() - 1); + return (s); + } + + private void load() { + ApplicationRegistry appRegistry = habitat.getService(ApplicationRegistry.class); + ApplicationInfo appInfo = appRegistry.get(PayaraFangService.FANG_APP_NAME); + if (appInfo != null && appInfo.isLoaded()) { + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADED); + return; + } + + Application config = payaraFangAdapter.getConfig(); + + if (config == null) { + throw new IllegalStateException("Payara Fang has no system app entry!"); + } + + // Set adapter state + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADING); + + // Load the Payara Fang Application + String sn = serverEnv.getInstanceName(); + ApplicationRef ref = domain.getApplicationRefInServer(sn, PayaraFangService.FANG_APP_NAME); + habitat.getService(ApplicationLoaderService.class).processApplication(config, ref); + + // Set adapter state + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADED); + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java new file mode 100644 index 00000000000..2625af9ce4f --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java @@ -0,0 +1,66 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package fish.payara.appserver.fang.service; + +import com.sun.enterprise.config.serverbeans.Domain; +import fish.payara.appserver.fang.service.adapter.PayaraFangAdapter; +import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.inject.Named; +import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.hk2.runlevel.RunLevel; +import org.glassfish.internal.api.PostStartupRunLevel; +import org.glassfish.server.ServerEnvironmentImpl; +import org.jvnet.hk2.annotations.Optional; +import org.jvnet.hk2.annotations.Service; + +/** + * + * @author Andrew Pielage + */ +@Service(name = "payara-fang") +@RunLevel(PostStartupRunLevel.VAL) +public class PayaraFangService { + + public static final String FANG_APP_NAME = "__fang"; + + @Inject + @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) + @Optional + private PayaraFangConfiguration configuration; + + @Inject + private PayaraFangAdapter payaraFangAdapter; + + @Inject + Domain domain; + + @Inject + ServerEnvironmentImpl serverEnv; + + @Inject + ServiceLocator habitat; + + @PostConstruct + private void postConstruct() { + configuration = habitat.getService(PayaraFangConfiguration.class); + + if (configuration.getEnabled().equals("true")) { + loadApplication(); + } + } + + private void loadApplication() { + try { + new PayaraFangLoader(payaraFangAdapter, habitat, domain, serverEnv, + payaraFangAdapter.getContextRoot(), payaraFangAdapter.getVirtualServers()).start(); + } catch (Exception ex) { + throw new RuntimeException("Unable to load Payara Fang!", ex); + } + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java new file mode 100644 index 00000000000..97adf1925e3 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java @@ -0,0 +1,517 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package fish.payara.appserver.fang.service.adapter; + +import com.sun.appserv.server.util.Version; +import com.sun.enterprise.config.serverbeans.Application; +import com.sun.enterprise.config.serverbeans.Config; +import com.sun.enterprise.config.serverbeans.Domain; +import fish.payara.appserver.fang.service.PayaraFangService; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.inject.Named; +import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.api.container.Adapter; +import org.glassfish.api.event.Events; +import org.glassfish.grizzly.http.Method; +import org.glassfish.grizzly.http.io.OutputBuffer; +import org.glassfish.grizzly.http.server.HttpHandler; +import org.glassfish.grizzly.http.server.Request; +import org.glassfish.grizzly.http.server.Response; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.internal.data.ApplicationRegistry; +import org.glassfish.server.ServerEnvironmentImpl; +import org.jvnet.hk2.annotations.Service; + +/** + * + * @author Andrew Pielage + */ +@Service +public final class PayaraFangAdapter extends HttpHandler implements Adapter { + private String contextRoot; + private File warFile; // GF Admin Console War File Location + private PayaraFangAdapterState stateMsg = PayaraFangAdapterState.UNINITIALISED; + private boolean installing = false; + private boolean isOK = false; + private boolean isRegistered = false; + private ResourceBundle bundle; + private Method[] allowedHttpMethods = {Method.GET, Method.POST, Method.HEAD, Method.DELETE, Method.PUT}; + private String statusHtml; + private String initHtml; + + private static PayaraFangEndpointDecider endpointDecider; + + @Inject + ServerEnvironmentImpl env; + + @Inject + ApplicationRegistry appRegistry; + + @Inject + Domain domain; + + @Inject + ServiceLocator habitat; + + @Inject + Events events; + + @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) + Config serverConfig; + + private final static String INSTALL_ROOT = "com.sun.aas.installRoot"; + private final static Logger logger = Logger.getLogger(PayaraFangAdapter.class.getName()); + private final static String RESOURCE_PACKAGE = "fish/payara/appserver/fang/adapter"; + private final static String STATUS_TOKEN = "%%%STATUS%%%"; + private final static String REDIRECT_TOKEN = "%%%LOCATION%%%"; + private final CountDownLatch latch = new CountDownLatch(1); + + @PostConstruct + public void postConstruct() { + init(); + } + +// private void init() { +// String iRoot = System.getProperty(INSTALL_ROOT) + "/lib/install/applications/fang.war"; +// warFile = new File(iRoot.replace('/', File.separatorChar)); +// +// initState(); +// +// try { +// endpointDecider = new PayaraFangEndpointDecider(serverConfig); +// contextRoot = endpointDecider.getContextRoot(); +// } catch (Exception ex) { +// logger.log(Level.INFO, "Payara Fang Console cannot initialise", ex); +// return; +// } +// } + + private void init() { + if (appExistsInConfig()) { + setStateMsg(PayaraFangAdapterState.NOT_LOADED); + } else { + setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); + } + + try { + endpointDecider = new PayaraFangEndpointDecider(serverConfig); + contextRoot = endpointDecider.getContextRoot(); + } catch (Exception ex) { + logger.log(Level.INFO, "Payara Fang Console cannot initialise", ex); + } + } + +// private void initState() { +// // It is a given that the application is NOT loaded to begin with +// if (appExistsInConfig()) { +// isOK = true; +// setStateMsg(PayaraFangAdapterState.APPLICATION_INSTALLED_BUT_NOT_LOADED); +// } else if (new File(warFile.getParentFile(), FANG_APP_NAME).exists() || warFile.exists()) { +// // The exploded dir, or the .war exists... mark as downloded +// if (logger.isLoggable(Level.FINE)) { +// setStateMsg(PayaraFangAdapterState.DOWNLOADED); +// } +// isOK = true; +// } else { +// setStateMsg(PayaraFangAdapterState.APPLICATION_NOT_INSTALLED); +// } +// } + + private boolean appExistsInConfig() { + return (getConfig() != null); + } + + public Application getConfig() { + Application app = domain.getSystemApplicationReferencedFrom(env.getInstanceName(), PayaraFangService.FANG_APP_NAME); + + return app; + } + + private PayaraFangAdapterState getStateMsg() { + return stateMsg; + } + + public void setStateMsg(PayaraFangAdapterState msg) { + stateMsg = msg; + logger.log(Level.FINE, msg.toString()); + } + + @Override + public void service(Request request, Response response) throws Exception { + bundle = getResourceBundle(request.getLocale()); + Method method = request.getMethod(); + + if (!checkHttpMethodAllowed(method)) { + response.setStatus(java.net.HttpURLConnection.HTTP_BAD_METHOD, + method.getMethodString() + " " + bundle.getString("http.bad.method")); + response.setHeader("Allow", getAllowedHttpMethodsAsString()); + return; + } + + try { + if (!latch.await(100L, TimeUnit.SECONDS)) { + logger.log(Level.SEVERE, "Timed out processing a Payara Fang request"); + return; + } + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, "Cannot process Payara Fang request"); + return; + } + + logRequest(request); + + if (isResourceRequest(request)) { + try { + handleResourceRequest(request, response); + } catch (IOException ioe) { + if (logger.isLoggable(Level.SEVERE)) { + logger.log(Level.SEVERE, "Unable to serve resource: {0}. Cause: {1}", + new Object[]{request.getRequestURI(), ioe.toString()}); + } + + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, ioe.toString(), ioe); + } + } + + return; + } + + response.setContentType("text/html; charset=UTF-8"); + + String serverVersion = Version.getFullVersion(); + + if ("/testifbackendisready.html".equals(request.getRequestURI())) { + // Replace state token + String status = getStateMsg().getI18NKey(); + try { + // Try to get a localized version of this key + status = bundle.getString(status); + } catch (MissingResourceException ex) { + // Use the non-localized String version of the status + status = getStateMsg().toString(); + } + + String wkey = PayaraFangAdapterState.WELCOME_TO.getI18NKey(); + + try { + // Try to get a localized version of this key + serverVersion = bundle.getString(wkey) + " " + serverVersion + "."; + } catch (MissingResourceException ex) { + // Use the non-localized String version of the status + serverVersion = PayaraFangAdapterState.WELCOME_TO.toString() + " " + serverVersion + "."; + } + + status += "\n" + serverVersion; + + try { + OutputBuffer ob = getOutputBuffer(response); + byte[] bytes = (":::" + status).getBytes("UTF-8"); + response.setContentLength(bytes.length); + ob.write(bytes, 0, bytes.length); + ob.flush(); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Unable to serve resource: {0}. Cause: {1}", ex); + } + + return; + } + + if (isApplicationLoaded()) { + handleLoadedState(); + } +// else { +// synchronized(this) { +// if (isInstalling()) { +// sendStatusPage(request, response); +// } else { +// if (isApplicationLoaded()) { +// // Double check here that it is not yet loaded (not +// // likely, but possible) +// handleLoadedState(); +// }else { +// loadConsole(); +// sendStatusPage(request, response); +// } +// } +// } +// } + } + + private ResourceBundle getResourceBundle(Locale locale) { + return ResourceBundle.getBundle( + "com.sun.enterprise.v3.admin.adapter.LocalStrings", locale); + } + + private boolean checkHttpMethodAllowed(Method method) { + for (Method hh : allowedHttpMethods) { + if (hh.equals(method)) { + return true; + } + } + return false; + } + + private String getAllowedHttpMethodsAsString() { + StringBuilder sb = new StringBuilder(allowedHttpMethods[0].getMethodString()); + for (int i = 1; i < allowedHttpMethods.length; i++) { + sb.append(", ").append(allowedHttpMethods[i].getMethodString()); + } + return sb.toString(); + } + + private void logRequest(Request request) { + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "PayaraFangConsoleAdapter's STATE IS: {0}", getStateMsg()); + logger.log(Level.FINE, "Current Thread: {0}", Thread.currentThread().getName()); + + for (final String name : request.getParameterNames()) { + final String values = Arrays.toString(request.getParameterValues(name)); + logger.log(Level.FINE, "Parameter name: {0} values: {1}", new Object[]{name, values}); + } + } + } + + private boolean isResourceRequest(Request request) { + return (getContentType(request.getRequestURI()) != null); + } + + private String getContentType(String resource) { + if (resource == null || resource.length() == 0) { + return null; + } + + if (resource.endsWith(".gif")) { + return "image/gif"; + } else if (resource.endsWith(".jpg")) { + return "image/jpeg"; + } else { + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "Unhandled content-type: {0}", resource); + } + + return null; + } + } + + private void handleResourceRequest(Request request, Response response) throws IOException { + String resourcePath = RESOURCE_PACKAGE + request.getRequestURI(); + + ClassLoader loader = PayaraFangAdapter.class.getClassLoader(); + + try (InputStream inputStream = loader.getResourceAsStream(resourcePath)) { + if (inputStream == null) { + logger.log(Level.WARNING, "Resource not found: {0}", resourcePath); + return; + } + + byte[] buffer = new byte[512]; + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(512); + + for (int i = inputStream.read(buffer); i != -1; i = inputStream.read(buffer)) { + byteArrayOutputStream.write(buffer, 0, i); + } + + String contentType = getContentType(resourcePath); + + if (contentType != null) { + response.setContentType(contentType); + } + + response.setContentLength(byteArrayOutputStream.size()); + OutputStream outputStream = response.getOutputStream(); + byteArrayOutputStream.writeTo(outputStream); + outputStream.flush(); + } + } + + private OutputBuffer getOutputBuffer(Response response) { + response.setStatus(202); + response.setContentType("text/html"); + response.setCharacterEncoding("UTF-8"); + return response.getOutputBuffer(); + } + + public boolean isApplicationLoaded() { + return (stateMsg == PayaraFangAdapterState.LOADED); + } + + private void handleLoadedState() { + // Do nothing + statusHtml = null; + initHtml = null; + } + + private boolean isInstalling() { + return installing; + } + + private void sendStatusPage(Request request, Response response) { + byte[] bytes; + try { + OutputBuffer outputBuffer = getOutputBuffer(response); + + // Replace locale specific Strings + String localHtml = replaceTokens(statusHtml, bundle); + + // Replace state token + String status = getStateMsg().getI18NKey(); + + try { + // Try to get a localized version of this key + status = bundle.getString(status); + } catch (MissingResourceException ex) { + // Use the non-localized String version of the status + status = getStateMsg().toString(); + } + + String locationUrl = request.getScheme()+ "://" + request.getServerName() + ':' + request.getServerPort() + + "/fang"; + + localHtml = localHtml.replace(REDIRECT_TOKEN, locationUrl); + bytes = localHtml.replace(STATUS_TOKEN, status).getBytes("UTF-8"); + response.setContentLength(bytes.length); + outputBuffer.write(bytes, 0, bytes.length); + outputBuffer.flush(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + /** + *

This method replaces all tokens in text with values from the given + * ResourceBundle. A token starts and ends with 3 + * percent (%) characters. The value between the percent characters + * will be used as the key to the given ResourceBundle. + * If a key does not exist in the bundle, no substitution will take + * place for that token.

+ * + * @return The same text except with substituted tokens when available. + * @param text The text containing tokens to be replaced. + * @param bundle The ResourceBundle with keys for the value + */ + private String replaceTokens(String text, ResourceBundle bundle) { + int start = 0; + int end = 0; + StringBuilder stringBuilder = new StringBuilder(""); + + while (start != -1) { + // Find start of token + start = text.indexOf("%%%", end); + if (start != -1) { + // First copy the stuff before the start + stringBuilder.append(text.substring(end, start)); + + // Move past the %%% + start += 3; + + // Find end of token + end = text.indexOf("%%%", start); + if (end != -1) { + try { + // Copy the token value to the buffer + stringBuilder.append(bundle.getString(text.substring(start, end))); + } catch (MissingResourceException ex) { + // Unable to find the resource, so we don't do anything + stringBuilder.append("%%%").append(text.substring(start, end)).append("%%%"); + } + + // Move past the %%% + end += 3; + } else { + // Add back the %%% because we didn't find a matching end + stringBuilder.append("%%%"); + + // Reset end so we can copy the remainder of the text + end = start; + } + } + } + + // Copy the remainder of the text + stringBuilder.append(text.substring(end)); + + // Return the new String + return stringBuilder.toString(); + } + +// void loadConsole() { +// try { +// // We have permission and now we should install (or load) the application. +// setInstalling(true); +// startThread(); // Thread must set installing false +// } catch (Exception ex) { +// // Ensure we haven't crashed with the installing +// // flag set to true (not likely). +// setInstalling(false); +// throw new RuntimeException( +// "Unable to install Admin Console!", ex); +// } +// } + + public void setInstalling(boolean flag) { + installing = flag; + } + +// private void startThread() { +// new PayaraFangInstallerThread(this, habitat, domain, env, contextRoot, endpointDecider.getHosts()).start(); +// } + + + + + + @Override + public HttpHandler getHttpService() { + return this; + } + + @Override + public String getContextRoot() { + return endpointDecider.getContextRoot(); + } + + @Override + public int getListenPort() { + return endpointDecider.getListenPort(); + } + + @Override + public InetAddress getListenAddress() { + return endpointDecider.getListenAddress(); + } + + @Override + public List getVirtualServers() { + return endpointDecider.getHosts(); + } + + @Override + public boolean isRegistered() { + return isRegistered; + } + + @Override + public void setRegistered(boolean isRegistered) { + this.isRegistered = isRegistered; + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java new file mode 100644 index 00000000000..4f1e194eebd --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java @@ -0,0 +1,35 @@ +package fish.payara.appserver.fang.service.adapter; + +/** + * + * @author Andrew Pielage + */ +public enum PayaraFangAdapterState { + NOT_LOADED("state.notLoaded", "Payara Fang is registered in the config but not loaded yet"), + LOADING("state.loading", "Payara Fang is loading"), + LOADED("state.loaded", "Payara Fang is loaded"), + UNINITIALISED("state.uninitialised", "Payara Fang has not been initialised yet"), + REGISTERING("state.registering", "Payara Fang is being registered as a system application"), + NOT_REGISTERED("state.notRegistered", "Payara Fang is not registered in the config"), + WELCOME_TO("status.welcometo", "Welcome to "); + + private final String desc; + private final String i18nKey; + + private PayaraFangAdapterState(String i18nKey, String desc) { + this.i18nKey = i18nKey; + this.desc = desc; + } + + /** + * This is the key that should be used to retrieve the localised message from a properties file. + */ + public String getI18NKey() { + return i18nKey; + } + + @Override + public String toString() { + return (desc); + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java new file mode 100644 index 00000000000..2d11b32c21f --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java @@ -0,0 +1,120 @@ +package fish.payara.appserver.fang.service.adapter; + +import com.sun.enterprise.config.serverbeans.Config; +import com.sun.enterprise.config.serverbeans.ServerTags; +import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.inject.Inject; +import org.glassfish.grizzly.config.dom.NetworkListener; +import org.glassfish.grizzly.config.dom.ThreadPool; +import org.glassfish.hk2.api.ServiceLocator; +import org.jvnet.hk2.config.types.Property; + +/** + * + * @author Andrew Pielage + */ +public class PayaraFangEndpointDecider { + private String contextRoot; + + private int port; + private InetAddress address; + private int maxThreadPoolSize = 5; + private Config config; + private Logger logger = Logger.getLogger(PayaraFangEndpointDecider.class.getName()); + private List hosts; + + private final static String DEFAULT_CONTEXT_ROOT = "/fang"; + + public static final int DEFAULT_ADMIN_PORT = 4848; + + @Inject + ServiceLocator habitat; + + public PayaraFangEndpointDecider(Config config) { + if (config == null || logger == null) + throw new IllegalArgumentException("config or logger can't be null"); + this.config = config; + setValues(); + } + + public int getListenPort() { + return port; + } + + public InetAddress getListenAddress() { + return address; + } + + public int getMaxThreadPoolSize() { + return maxThreadPoolSize; + } + + public String getContextRoot() { + return contextRoot; + } + + private void setValues() { + NetworkListener networkListener = config.getAdminListener(); + ThreadPool threadPool = networkListener.findThreadPool(); + + // Set Thread pool size + if (threadPool != null) { + try { + maxThreadPoolSize = Integer.parseInt(threadPool.getMaxThreadPoolSize()); + } catch (NumberFormatException ex) { + + } + } + + String defaultVirtualServer = networkListener.findHttpProtocol().getHttp().getDefaultVirtualServer(); + hosts = Collections.unmodifiableList(Arrays.asList(defaultVirtualServer)); + + // Set network address + try { + address = InetAddress.getByName(networkListener.getAddress()); + } catch (UnknownHostException e) { + throw new IllegalStateException(e); + } + + // Set the context root and port number + if (ServerTags.ADMIN_LISTENER_ID.equals(networkListener.getName())) { + contextRoot = DEFAULT_CONTEXT_ROOT; + + try { + port = Integer.parseInt(networkListener.getPort()); + } catch(NumberFormatException ne) { + port = DEFAULT_ADMIN_PORT; + } + } + else { + try { + port = Integer.parseInt(networkListener.getPort()); + } catch(NumberFormatException ne) { + port = DEFAULT_ADMIN_PORT; + } + + // Get the context root from the Payara Fang service + PayaraFangConfiguration fangServiceConfiguration = habitat.getService(PayaraFangConfiguration.class); + if (fangServiceConfiguration == null) { + contextRoot = DEFAULT_CONTEXT_ROOT; + } else { + setContextRootFromService(fangServiceConfiguration); + } + } + } + + private void setContextRootFromService(PayaraFangConfiguration fangService) { + contextRoot = fangService.getContextRoot(); + } + + public List getHosts() { + return hosts; + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java new file mode 100644 index 00000000000..3c3824a9162 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java @@ -0,0 +1,32 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package fish.payara.appserver.fang.service.configuration; + +import java.beans.PropertyVetoException; +import org.glassfish.api.admin.config.ConfigExtension; +import org.jvnet.hk2.config.Attribute; +import org.jvnet.hk2.config.ConfigBeanProxy; +import org.jvnet.hk2.config.Configured; + +/** + * + * @author Andrew Pielage + */ +@Configured +public interface PayaraFangConfiguration extends ConfigBeanProxy, ConfigExtension { + + /** + * Checks if Payara Fang is enabled or not + * @return true if enabled + */ + @Attribute(defaultValue="false") + String getEnabled(); + void setEnabled(String value) throws PropertyVetoException; + + @Attribute(defaultValue="/fang") + String getContextRoot(); + void setContextRoot(String contextRoot) throws PropertyVetoException; +} diff --git a/appserver/payara-appserver-modules/pom.xml b/appserver/payara-appserver-modules/pom.xml index 36c7a162809..100fd2d9e9d 100644 --- a/appserver/payara-appserver-modules/pom.xml +++ b/appserver/payara-appserver-modules/pom.xml @@ -69,5 +69,6 @@ zendesk-support environment-warning payara-rest-endpoints + payara-fang From f1d242462e6a5e3886ce5b21ec7a7f4ec4f888ac Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Thu, 6 Apr 2017 10:56:32 +0100 Subject: [PATCH 02/22] Working draft --- .../fang/service/PayaraFangLoader.java | 117 +++++++--- .../service/adapter/PayaraFangAdapter.java | 208 +----------------- 2 files changed, 93 insertions(+), 232 deletions(-) diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java index 240ee8be2c6..0d8b9413ef0 100644 --- a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java +++ b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java @@ -15,12 +15,10 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import org.glassfish.api.admin.config.ApplicationName; import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.internal.data.ApplicationInfo; import org.glassfish.internal.data.ApplicationRegistry; import org.glassfish.server.ServerEnvironmentImpl; -import org.jvnet.hk2.config.ConfigBean; import org.jvnet.hk2.config.ConfigBeanProxy; import org.jvnet.hk2.config.ConfigCode; import org.jvnet.hk2.config.ConfigSupport; @@ -52,42 +50,40 @@ public class PayaraFangLoader extends Thread { @Override public void run() { try { - if (domain.getSystemApplicationReferencedFrom(serverEnv.getInstanceName(), PayaraFangService.FANG_APP_NAME) - == null) { -// if (serverEnv.isDas()) { + // Check if the application is registered for this instance already + if (payaraFangAdapter.getConfig() == null) { + // Only the DAS should create system applications. + if (serverEnv.isDas()) { + createAndRegisterApplication(); + } else { registerApplication(); -// } else { -// logger.log(Level.WARNING, "Payara Fang not yet registered in the DAS"); -// return; -// } + } } load(); - - // From within this Thread mark the installation process complete - payaraFangAdapter.setInstalling(false); } catch (Exception ex) { - payaraFangAdapter.setInstalling(false); payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); - logger.log(Level.INFO, "Problem while attempting to register Payara Fang!", ex); + logger.log(Level.WARNING, "Problem while attempting to register Payara Fang!", ex); } } /** - * Register the application + * Create the system application entry and register the application * @throws Exception */ - private void registerApplication() throws Exception { + private void createAndRegisterApplication() throws Exception { + // Update the adapter state payaraFangAdapter.setStateMsg(PayaraFangAdapterState.REGISTERING); if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "Registering the Payara Fang Application..."); } - //create the application entry in domain.xml + // Create the system application entry and application-ref in the config ConfigCode code = new ConfigCode() { @Override public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, TransactionFailure { + // Create the system application SystemApplications systemApplications = (SystemApplications) proxies[0]; Application application = systemApplications.createChild(Application.class); systemApplications.getModules().add(application); @@ -101,10 +97,10 @@ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, Tran application.setLocation("${com.sun.aas.installRootURI}/lib/install/applications/" + PayaraFangService.FANG_APP_NAME); } catch (Exception me) { - // can't do anything throw new RuntimeException(me); } + // Set the engine types Module singleModule = application.createChild(Module.class); application.getModule().add(singleModule); singleModule.setName(application.getName()); @@ -114,13 +110,16 @@ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, Tran weldEngine.setSniffer("weld"); singleModule.getEngines().add(webEngine); singleModule.getEngines().add(weldEngine); + + // Create the application-ref Server s = (Server) proxies[1]; List arefs = s.getApplicationRef(); ApplicationRef aref = s.createChild(ApplicationRef.class); aref.setRef(application.getName()); aref.setEnabled(Boolean.TRUE.toString()); - aref.setVirtualServers(getVirtualServerList()); + aref.setVirtualServers(getVirtualServerListAsString()); arefs.add(aref); + return true; } }; @@ -128,24 +127,78 @@ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, Tran Server server = domain.getServerNamed(serverEnv.getInstanceName()); ConfigSupport.apply(code, domain.getSystemApplications(), server); - // Set the adapter state + // Update the adapter state payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "Payara Fang Registered."); } } + + private void registerApplication() throws Exception { + // Update the adapter state + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.REGISTERING); + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "Registering the Payara Fang Application..."); + } - private String getVirtualServerList() { - if (vss == null) + // Create the application-ref entry in the domain.xml + ConfigCode code = new ConfigCode() { + @Override + public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, TransactionFailure { + // Get the system application config + SystemApplications systemApplications = (SystemApplications) proxies[0]; + Application application = null; + for (Application systemApplication : systemApplications.getApplications()) { + if (systemApplication.getName().equals(PayaraFangService.FANG_APP_NAME)) { + application = systemApplication; + break; + } + } + + if (application == null) { + throw new IllegalStateException("Payara Fang has no system app entry!"); + } + + // Create the application-ref + Server s = (Server) proxies[1]; + List arefs = s.getApplicationRef(); + ApplicationRef aref = s.createChild(ApplicationRef.class); + aref.setRef(application.getName()); + aref.setEnabled(Boolean.TRUE.toString()); + aref.setVirtualServers(getVirtualServerListAsString()); + arefs.add(aref); + return true; + } + }; + + Server server = domain.getServerNamed(serverEnv.getInstanceName()); + ConfigSupport.apply(code, domain.getSystemApplications(), server); + + // Update the adapter state + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "Payara Fang Registered."); + } + } + + private String getVirtualServerListAsString() { + if (vss == null) { return ""; - String s = Arrays.toString(vss.toArray(new String[vss.size()])); - //standard JDK implemetation always returns this enclosed in [], remove them - s = s.substring(1, s.length() - 1); - return (s); + } + + String virtualServers = Arrays.toString(vss.toArray(new String[vss.size()])); + + // Standard JDK implemetation always returns this enclosed in [], which we don't want + virtualServers = virtualServers.substring(1, virtualServers.length() - 1); + + return virtualServers; } + /** + * Loads the application + */ private void load() { - ApplicationRegistry appRegistry = habitat.getService(ApplicationRegistry.class); + ApplicationRegistry appRegistry = habitat.getService(ApplicationRegistry.class); ApplicationInfo appInfo = appRegistry.get(PayaraFangService.FANG_APP_NAME); if (appInfo != null && appInfo.isLoaded()) { payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADED); @@ -158,15 +211,15 @@ private void load() { throw new IllegalStateException("Payara Fang has no system app entry!"); } - // Set adapter state + // Update adapter state payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADING); // Load the Payara Fang Application - String sn = serverEnv.getInstanceName(); - ApplicationRef ref = domain.getApplicationRefInServer(sn, PayaraFangService.FANG_APP_NAME); - habitat.getService(ApplicationLoaderService.class).processApplication(config, ref); + String instanceName = serverEnv.getInstanceName(); + ApplicationRef ref = domain.getApplicationRefInServer(instanceName, PayaraFangService.FANG_APP_NAME); + habitat.getService(ApplicationLoaderService.class).processApplication(config, ref); - // Set adapter state + // Update adapter state payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADED); } } diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java index 97adf1925e3..8587ec5af49 100644 --- a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java +++ b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java @@ -47,16 +47,11 @@ */ @Service public final class PayaraFangAdapter extends HttpHandler implements Adapter { - private String contextRoot; - private File warFile; // GF Admin Console War File Location private PayaraFangAdapterState stateMsg = PayaraFangAdapterState.UNINITIALISED; - private boolean installing = false; private boolean isOK = false; private boolean isRegistered = false; private ResourceBundle bundle; private Method[] allowedHttpMethods = {Method.GET, Method.POST, Method.HEAD, Method.DELETE, Method.PUT}; - private String statusHtml; - private String initHtml; private static PayaraFangEndpointDecider endpointDecider; @@ -78,11 +73,8 @@ public final class PayaraFangAdapter extends HttpHandler implements Adapter { @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) Config serverConfig; - private final static String INSTALL_ROOT = "com.sun.aas.installRoot"; private final static Logger logger = Logger.getLogger(PayaraFangAdapter.class.getName()); private final static String RESOURCE_PACKAGE = "fish/payara/appserver/fang/adapter"; - private final static String STATUS_TOKEN = "%%%STATUS%%%"; - private final static String REDIRECT_TOKEN = "%%%LOCATION%%%"; private final CountDownLatch latch = new CountDownLatch(1); @PostConstruct @@ -90,21 +82,6 @@ public void postConstruct() { init(); } -// private void init() { -// String iRoot = System.getProperty(INSTALL_ROOT) + "/lib/install/applications/fang.war"; -// warFile = new File(iRoot.replace('/', File.separatorChar)); -// -// initState(); -// -// try { -// endpointDecider = new PayaraFangEndpointDecider(serverConfig); -// contextRoot = endpointDecider.getContextRoot(); -// } catch (Exception ex) { -// logger.log(Level.INFO, "Payara Fang Console cannot initialise", ex); -// return; -// } -// } - private void init() { if (appExistsInConfig()) { setStateMsg(PayaraFangAdapterState.NOT_LOADED); @@ -114,36 +91,17 @@ private void init() { try { endpointDecider = new PayaraFangEndpointDecider(serverConfig); - contextRoot = endpointDecider.getContextRoot(); } catch (Exception ex) { logger.log(Level.INFO, "Payara Fang Console cannot initialise", ex); } } -// private void initState() { -// // It is a given that the application is NOT loaded to begin with -// if (appExistsInConfig()) { -// isOK = true; -// setStateMsg(PayaraFangAdapterState.APPLICATION_INSTALLED_BUT_NOT_LOADED); -// } else if (new File(warFile.getParentFile(), FANG_APP_NAME).exists() || warFile.exists()) { -// // The exploded dir, or the .war exists... mark as downloded -// if (logger.isLoggable(Level.FINE)) { -// setStateMsg(PayaraFangAdapterState.DOWNLOADED); -// } -// isOK = true; -// } else { -// setStateMsg(PayaraFangAdapterState.APPLICATION_NOT_INSTALLED); -// } -// } - private boolean appExistsInConfig() { return (getConfig() != null); } public Application getConfig() { - Application app = domain.getSystemApplicationReferencedFrom(env.getInstanceName(), PayaraFangService.FANG_APP_NAME); - - return app; + return domain.getSystemApplicationReferencedFrom(env.getInstanceName(), PayaraFangService.FANG_APP_NAME); } private PayaraFangAdapterState getStateMsg() { @@ -232,39 +190,17 @@ public void service(Request request, Response response) throws Exception { } catch (IOException ex) { logger.log(Level.SEVERE, "Unable to serve resource: {0}. Cause: {1}", ex); } - - return; - } - - if (isApplicationLoaded()) { - handleLoadedState(); - } -// else { -// synchronized(this) { -// if (isInstalling()) { -// sendStatusPage(request, response); -// } else { -// if (isApplicationLoaded()) { -// // Double check here that it is not yet loaded (not -// // likely, but possible) -// handleLoadedState(); -// }else { -// loadConsole(); -// sendStatusPage(request, response); -// } -// } -// } -// } + } + // TODO: Handle application not being there } private ResourceBundle getResourceBundle(Locale locale) { - return ResourceBundle.getBundle( - "com.sun.enterprise.v3.admin.adapter.LocalStrings", locale); + return ResourceBundle.getBundle("com.sun.enterprise.v3.admin.adapter.LocalStrings", locale); } private boolean checkHttpMethodAllowed(Method method) { - for (Method hh : allowedHttpMethods) { - if (hh.equals(method)) { + for (Method allowedMethod : allowedHttpMethods) { + if (allowedMethod.equals(method)) { return true; } } @@ -276,12 +212,13 @@ private String getAllowedHttpMethodsAsString() { for (int i = 1; i < allowedHttpMethods.length; i++) { sb.append(", ").append(allowedHttpMethods[i].getMethodString()); } + return sb.toString(); } private void logRequest(Request request) { if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, "PayaraFangConsoleAdapter's STATE IS: {0}", getStateMsg()); + logger.log(Level.FINE, "PayaraFangAdapter's STATE IS: {0}", getStateMsg()); logger.log(Level.FINE, "Current Thread: {0}", Thread.currentThread().getName()); for (final String name : request.getParameterNames()) { @@ -351,135 +288,6 @@ private OutputBuffer getOutputBuffer(Response response) { return response.getOutputBuffer(); } - public boolean isApplicationLoaded() { - return (stateMsg == PayaraFangAdapterState.LOADED); - } - - private void handleLoadedState() { - // Do nothing - statusHtml = null; - initHtml = null; - } - - private boolean isInstalling() { - return installing; - } - - private void sendStatusPage(Request request, Response response) { - byte[] bytes; - try { - OutputBuffer outputBuffer = getOutputBuffer(response); - - // Replace locale specific Strings - String localHtml = replaceTokens(statusHtml, bundle); - - // Replace state token - String status = getStateMsg().getI18NKey(); - - try { - // Try to get a localized version of this key - status = bundle.getString(status); - } catch (MissingResourceException ex) { - // Use the non-localized String version of the status - status = getStateMsg().toString(); - } - - String locationUrl = request.getScheme()+ "://" + request.getServerName() + ':' + request.getServerPort() - + "/fang"; - - localHtml = localHtml.replace(REDIRECT_TOKEN, locationUrl); - bytes = localHtml.replace(STATUS_TOKEN, status).getBytes("UTF-8"); - response.setContentLength(bytes.length); - outputBuffer.write(bytes, 0, bytes.length); - outputBuffer.flush(); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - - /** - *

This method replaces all tokens in text with values from the given - * ResourceBundle. A token starts and ends with 3 - * percent (%) characters. The value between the percent characters - * will be used as the key to the given ResourceBundle. - * If a key does not exist in the bundle, no substitution will take - * place for that token.

- * - * @return The same text except with substituted tokens when available. - * @param text The text containing tokens to be replaced. - * @param bundle The ResourceBundle with keys for the value - */ - private String replaceTokens(String text, ResourceBundle bundle) { - int start = 0; - int end = 0; - StringBuilder stringBuilder = new StringBuilder(""); - - while (start != -1) { - // Find start of token - start = text.indexOf("%%%", end); - if (start != -1) { - // First copy the stuff before the start - stringBuilder.append(text.substring(end, start)); - - // Move past the %%% - start += 3; - - // Find end of token - end = text.indexOf("%%%", start); - if (end != -1) { - try { - // Copy the token value to the buffer - stringBuilder.append(bundle.getString(text.substring(start, end))); - } catch (MissingResourceException ex) { - // Unable to find the resource, so we don't do anything - stringBuilder.append("%%%").append(text.substring(start, end)).append("%%%"); - } - - // Move past the %%% - end += 3; - } else { - // Add back the %%% because we didn't find a matching end - stringBuilder.append("%%%"); - - // Reset end so we can copy the remainder of the text - end = start; - } - } - } - - // Copy the remainder of the text - stringBuilder.append(text.substring(end)); - - // Return the new String - return stringBuilder.toString(); - } - -// void loadConsole() { -// try { -// // We have permission and now we should install (or load) the application. -// setInstalling(true); -// startThread(); // Thread must set installing false -// } catch (Exception ex) { -// // Ensure we haven't crashed with the installing -// // flag set to true (not likely). -// setInstalling(false); -// throw new RuntimeException( -// "Unable to install Admin Console!", ex); -// } -// } - - public void setInstalling(boolean flag) { - installing = flag; - } - -// private void startThread() { -// new PayaraFangInstallerThread(this, habitat, domain, env, contextRoot, endpointDecider.getHosts()).start(); -// } - - - - - @Override public HttpHandler getHttpService() { return this; From 119d4f0a1e3d4f376b4904badf9ffa1c593ff18d Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Thu, 6 Apr 2017 15:38:55 +0100 Subject: [PATCH 03/22] Working context roots --- .../fang/service/PayaraFangLoader.java | 3 +++ .../service/adapter/PayaraFangAdapter.java | 4 +++- .../adapter/PayaraFangEndpointDecider.java | 24 +++++++++++-------- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java index 0d8b9413ef0..1fad1b99128 100644 --- a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java +++ b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java @@ -108,8 +108,11 @@ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, Tran webEngine.setSniffer("web"); Engine weldEngine = singleModule.createChild(Engine.class); weldEngine.setSniffer("weld"); + Engine securityEngine = singleModule.createChild(Engine.class); + securityEngine.setSniffer("security"); singleModule.getEngines().add(webEngine); singleModule.getEngines().add(weldEngine); + singleModule.getEngines().add(securityEngine); // Create the application-ref Server s = (Server) proxies[1]; diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java index 8587ec5af49..ce27b68afa1 100644 --- a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java +++ b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java @@ -10,6 +10,7 @@ import com.sun.enterprise.config.serverbeans.Config; import com.sun.enterprise.config.serverbeans.Domain; import fish.payara.appserver.fang.service.PayaraFangService; +import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; @@ -90,7 +91,8 @@ private void init() { } try { - endpointDecider = new PayaraFangEndpointDecider(serverConfig); + PayaraFangConfiguration fangServiceConfiguration = habitat.getService(PayaraFangConfiguration.class); + endpointDecider = new PayaraFangEndpointDecider(serverConfig, fangServiceConfiguration); } catch (Exception ex) { logger.log(Level.INFO, "Payara Fang Console cannot initialise", ex); } diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java index 2d11b32c21f..2093e14f22e 100644 --- a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java +++ b/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java @@ -8,13 +8,15 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.logging.Level; import java.util.logging.Logger; +import javax.annotation.PostConstruct; import javax.inject.Inject; +import javax.inject.Named; +import org.glassfish.api.admin.ServerEnvironment; import org.glassfish.grizzly.config.dom.NetworkListener; import org.glassfish.grizzly.config.dom.ThreadPool; import org.glassfish.hk2.api.ServiceLocator; -import org.jvnet.hk2.config.types.Property; +import org.jvnet.hk2.annotations.Optional; /** * @@ -29,6 +31,7 @@ public class PayaraFangEndpointDecider { private Config config; private Logger logger = Logger.getLogger(PayaraFangEndpointDecider.class.getName()); private List hosts; + private PayaraFangConfiguration fangServiceConfiguration; private final static String DEFAULT_CONTEXT_ROOT = "/fang"; @@ -37,10 +40,11 @@ public class PayaraFangEndpointDecider { @Inject ServiceLocator habitat; - public PayaraFangEndpointDecider(Config config) { + public PayaraFangEndpointDecider(Config config, PayaraFangConfiguration fangServiceConfiguration) { if (config == null || logger == null) throw new IllegalArgumentException("config or logger can't be null"); this.config = config; + this.fangServiceConfiguration = fangServiceConfiguration; setValues(); } @@ -85,7 +89,12 @@ private void setValues() { // Set the context root and port number if (ServerTags.ADMIN_LISTENER_ID.equals(networkListener.getName())) { - contextRoot = DEFAULT_CONTEXT_ROOT; + // Get the context root from the Payara Fang service + if (fangServiceConfiguration == null) { + contextRoot = DEFAULT_CONTEXT_ROOT; + } else { + contextRoot = fangServiceConfiguration.getContextRoot(); + } try { port = Integer.parseInt(networkListener.getPort()); @@ -101,19 +110,14 @@ private void setValues() { } // Get the context root from the Payara Fang service - PayaraFangConfiguration fangServiceConfiguration = habitat.getService(PayaraFangConfiguration.class); if (fangServiceConfiguration == null) { contextRoot = DEFAULT_CONTEXT_ROOT; } else { - setContextRootFromService(fangServiceConfiguration); + contextRoot = fangServiceConfiguration.getContextRoot(); } } } - private void setContextRootFromService(PayaraFangConfiguration fangService) { - contextRoot = fangService.getContextRoot(); - } - public List getHosts() { return hosts; } From 9f54bf426551c094c461449c64cd9103b07a143d Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Thu, 6 Apr 2017 16:11:56 +0100 Subject: [PATCH 04/22] Move into one module --- appserver/admingui/payara-fang/pom.xml | 57 ------------------- appserver/admingui/pom.xml | 1 - appserver/packager/payara-fang/pom.xml | 7 --- .../payara-fang/pom.xml | 57 +++++++++++++++++++ appserver/pom.xml | 1 + 5 files changed, 58 insertions(+), 65 deletions(-) delete mode 100644 appserver/admingui/payara-fang/pom.xml diff --git a/appserver/admingui/payara-fang/pom.xml b/appserver/admingui/payara-fang/pom.xml deleted file mode 100644 index 975303facab..00000000000 --- a/appserver/admingui/payara-fang/pom.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - 4.0.0 - - fish.payara.admingui - admingui - 4.1.1.172-SNAPSHOT - - - payara-fang - Admin Console Install Fragment for Payara Fang - distribution-fragment - - - - - - org.jvnet.maven-antrun-extended-plugin - maven-antrun-extended-plugin - - - generate-sources - - - - - - - - - run - - - - - - - - - - fish.payara.monitoring - Fang - 0.0.1-ALPHA - war - true - - - diff --git a/appserver/admingui/pom.xml b/appserver/admingui/pom.xml index f11b2eab6c9..6a6e44412f8 100644 --- a/appserver/admingui/pom.xml +++ b/appserver/admingui/pom.xml @@ -153,7 +153,6 @@ healthcheck-service-console-plugin newrelic-notifier-console-plugin jmx-monitoring-plugin - payara-fang diff --git a/appserver/packager/payara-fang/pom.xml b/appserver/packager/payara-fang/pom.xml index 5c98acea434..50b9869dce1 100644 --- a/appserver/packager/payara-fang/pom.xml +++ b/appserver/packager/payara-fang/pom.xml @@ -98,13 +98,6 @@ - - fish.payara.admingui - payara-fang - ${project.version} - zip - true - fish.payara.appserver payara-fang diff --git a/appserver/payara-appserver-modules/payara-fang/pom.xml b/appserver/payara-appserver-modules/payara-fang/pom.xml index 9af73adddbd..9c464b8ad4d 100644 --- a/appserver/payara-appserver-modules/payara-fang/pom.xml +++ b/appserver/payara-appserver-modules/payara-fang/pom.xml @@ -11,7 +11,64 @@ glassfish-jar Payara Fang + + + + org.jvnet.maven-antrun-extended-plugin + maven-antrun-extended-plugin + + + generate-sources + + + + + + + + + run + + + + + + org.apache.felix + maven-bundle-plugin + + + bundle-manifest + process-classes + + manifest + + + + + !fish.payara.monitoring.fang.*, + * + + + !fish.payara.monitoring.fang.*, + !glassfish.lib.install.applications.__fang.*, + fish.payara.appserver.fang.service.* + + + + + + + + + + + fish.payara.monitoring + Fang + ${payara.fang.version} + war + true + org.glassfish.main.common glassfish-api diff --git a/appserver/pom.xml b/appserver/pom.xml index 00f49a9b3e4..3b6ba0dc5bb 100644 --- a/appserver/pom.xml +++ b/appserver/pom.xml @@ -149,6 +149,7 @@ 1.1.1 3.3.0.Final 19.0 + 0.0.1-ALPHA From 58665339d824f6f6f4c7bc45e5df84bc781dcc77 Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Fri, 7 Apr 2017 09:38:36 +0100 Subject: [PATCH 05/22] Moved payara-fang application dependency again --- appserver/packager/payara-fang/pom.xml | 26 +++++++++ .../payara-fang/pom.xml | 57 ------------------- 2 files changed, 26 insertions(+), 57 deletions(-) diff --git a/appserver/packager/payara-fang/pom.xml b/appserver/packager/payara-fang/pom.xml index 50b9869dce1..4264eafd673 100644 --- a/appserver/packager/payara-fang/pom.xml +++ b/appserver/packager/payara-fang/pom.xml @@ -32,6 +32,25 @@ + + org.jvnet.maven-antrun-extended-plugin + maven-antrun-extended-plugin + + + generate-sources + + + + + + + + + run + + + + org.apache.maven.plugins maven-dependency-plugin @@ -103,6 +122,13 @@ payara-fang ${project.version} + + fish.payara.monitoring + Fang + ${payara.fang.version} + war + true + diff --git a/appserver/payara-appserver-modules/payara-fang/pom.xml b/appserver/payara-appserver-modules/payara-fang/pom.xml index 9c464b8ad4d..9af73adddbd 100644 --- a/appserver/payara-appserver-modules/payara-fang/pom.xml +++ b/appserver/payara-appserver-modules/payara-fang/pom.xml @@ -11,64 +11,7 @@ glassfish-jar Payara Fang - - - - org.jvnet.maven-antrun-extended-plugin - maven-antrun-extended-plugin - - - generate-sources - - - - - - - - - run - - - - - - org.apache.felix - maven-bundle-plugin - - - bundle-manifest - process-classes - - manifest - - - - - !fish.payara.monitoring.fang.*, - * - - - !fish.payara.monitoring.fang.*, - !glassfish.lib.install.applications.__fang.*, - fish.payara.appserver.fang.service.* - - - - - - - - - - - fish.payara.monitoring - Fang - ${payara.fang.version} - war - true - org.glassfish.main.common glassfish-api From d5e004820cc597b1505b7699037a1b37579abac0 Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Fri, 7 Apr 2017 09:53:31 +0100 Subject: [PATCH 06/22] Rename module --- appserver/packager/payara-fang/pom.xml | 2 +- .../{payara-fang => payara-fang-service}/pom.xml | 2 +- .../fish/payara/appserver/fang/service/PayaraFangLoader.java | 0 .../fish/payara/appserver/fang/service/PayaraFangService.java | 0 .../appserver/fang/service/adapter/PayaraFangAdapter.java | 0 .../appserver/fang/service/adapter/PayaraFangAdapterState.java | 0 .../fang/service/adapter/PayaraFangEndpointDecider.java | 0 .../fang/service/configuration/PayaraFangConfiguration.java | 0 appserver/payara-appserver-modules/pom.xml | 2 +- 9 files changed, 3 insertions(+), 3 deletions(-) rename appserver/payara-appserver-modules/{payara-fang => payara-fang-service}/pom.xml (96%) rename appserver/payara-appserver-modules/{payara-fang => payara-fang-service}/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java (100%) rename appserver/payara-appserver-modules/{payara-fang => payara-fang-service}/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java (100%) rename appserver/payara-appserver-modules/{payara-fang => payara-fang-service}/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java (100%) rename appserver/payara-appserver-modules/{payara-fang => payara-fang-service}/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java (100%) rename appserver/payara-appserver-modules/{payara-fang => payara-fang-service}/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java (100%) rename appserver/payara-appserver-modules/{payara-fang => payara-fang-service}/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java (100%) diff --git a/appserver/packager/payara-fang/pom.xml b/appserver/packager/payara-fang/pom.xml index 4264eafd673..2a5d33cfea9 100644 --- a/appserver/packager/payara-fang/pom.xml +++ b/appserver/packager/payara-fang/pom.xml @@ -119,7 +119,7 @@ fish.payara.appserver - payara-fang + payara-fang-service ${project.version} diff --git a/appserver/payara-appserver-modules/payara-fang/pom.xml b/appserver/payara-appserver-modules/payara-fang-service/pom.xml similarity index 96% rename from appserver/payara-appserver-modules/payara-fang/pom.xml rename to appserver/payara-appserver-modules/payara-fang-service/pom.xml index 9af73adddbd..ea5eccbf1b2 100644 --- a/appserver/payara-appserver-modules/payara-fang/pom.xml +++ b/appserver/payara-appserver-modules/payara-fang-service/pom.xml @@ -7,7 +7,7 @@ 4.1.1.172-SNAPSHOT fish.payara.appserver - payara-fang + payara-fang-service glassfish-jar Payara Fang diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java similarity index 100% rename from appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java rename to appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java similarity index 100% rename from appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java rename to appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java similarity index 100% rename from appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java rename to appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java similarity index 100% rename from appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java rename to appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java similarity index 100% rename from appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java rename to appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java diff --git a/appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java similarity index 100% rename from appserver/payara-appserver-modules/payara-fang/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java rename to appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java diff --git a/appserver/payara-appserver-modules/pom.xml b/appserver/payara-appserver-modules/pom.xml index 100fd2d9e9d..1db33daeb56 100644 --- a/appserver/payara-appserver-modules/pom.xml +++ b/appserver/payara-appserver-modules/pom.xml @@ -69,6 +69,6 @@ zendesk-support environment-warning payara-rest-endpoints - payara-fang + payara-fang-service From cb81a70fb75970f1424ff4036a0df00c8fc6c83e Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Fri, 7 Apr 2017 14:53:56 +0100 Subject: [PATCH 07/22] Refactor to allow multiple context roots --- .../fang/service/PayaraFangLoader.java | 85 ++++++++++++++----- ...ice.java => PayaraFangStartupService.java} | 7 +- .../service/adapter/PayaraFangAdapter.java | 70 +++++++++++---- .../adapter/PayaraFangEndpointDecider.java | 6 +- .../SetPayaraFangConfigurationCommand.java | 38 +++++++++ .../PayaraFangConfiguration.java | 4 + 6 files changed, 168 insertions(+), 42 deletions(-) rename appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/{PayaraFangService.java => PayaraFangStartupService.java} (87%) create mode 100644 appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java index 1fad1b99128..3581d488818 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java @@ -32,41 +32,43 @@ public class PayaraFangLoader extends Thread { private final Domain domain; private final ServerEnvironmentImpl serverEnv; private final String contextRoot; + private String applicationName; + private boolean applicationNameChanged = false; private final PayaraFangAdapter payaraFangAdapter; private final ServiceLocator habitat; private final Logger logger = Logger.getLogger(PayaraFangLoader.class.getName()); private final List vss; PayaraFangLoader(PayaraFangAdapter payaraFangAdapter, ServiceLocator habitat, Domain domain, - ServerEnvironmentImpl serverEnv, String contextRoot, List vss) { + ServerEnvironmentImpl serverEnv, String contextRoot, String applicationName, List vss) { this.payaraFangAdapter = payaraFangAdapter; this.habitat = habitat; this.domain = domain; this.serverEnv = serverEnv; this.contextRoot = contextRoot; + this.applicationName = applicationName; this.vss = vss; } @Override public void run() { try { - // Check if the application is registered for this instance already - if (payaraFangAdapter.getConfig() == null) { - // Only the DAS should create system applications. - if (serverEnv.isDas()) { - createAndRegisterApplication(); - } else { + // Check if the application already exists, creating the system-app entry if it isn't + if (payaraFangAdapter.appExistsInConfig()) { + // Check if the app is actually registered to this instance + if (!payaraFangAdapter.isAppRegistered()) { registerApplication(); } + } else { + createAndRegisterApplication(); } - load(); + loadApplication(); } catch (Exception ex) { payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); logger.log(Level.WARNING, "Problem while attempting to register Payara Fang!", ex); } } - /** * Create the system application entry and register the application @@ -86,16 +88,20 @@ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, Tran // Create the system application SystemApplications systemApplications = (SystemApplications) proxies[0]; Application application = systemApplications.createChild(Application.class); + + // Check if the application name is valid, generating a new one if it isn't + checkAndResolveApplicationName(systemApplications); + systemApplications.getModules().add(application); - application.setName(PayaraFangService.FANG_APP_NAME); + application.setName(applicationName); application.setEnabled(Boolean.TRUE.toString()); - application.setObjectType("system-admin"); //TODO + application.setObjectType("system-admin"); application.setDirectoryDeployed("true"); application.setContextRoot(contextRoot); try { application.setLocation("${com.sun.aas.installRootURI}/lib/install/applications/" - + PayaraFangService.FANG_APP_NAME); + + PayaraFangStartupService.DEFAULT_FANG_APP_NAME); } catch (Exception me) { throw new RuntimeException(me); } @@ -103,7 +109,7 @@ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, Tran // Set the engine types Module singleModule = application.createChild(Module.class); application.getModule().add(singleModule); - singleModule.setName(application.getName()); + singleModule.setName(applicationName); Engine webEngine = singleModule.createChild(Engine.class); webEngine.setSniffer("web"); Engine weldEngine = singleModule.createChild(Engine.class); @@ -152,7 +158,7 @@ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, Tran SystemApplications systemApplications = (SystemApplications) proxies[0]; Application application = null; for (Application systemApplication : systemApplications.getApplications()) { - if (systemApplication.getName().equals(PayaraFangService.FANG_APP_NAME)) { + if (systemApplication.getName().equals(applicationName)) { application = systemApplication; break; } @@ -200,15 +206,15 @@ private String getVirtualServerListAsString() { /** * Loads the application */ - private void load() { + private void loadApplication() { ApplicationRegistry appRegistry = habitat.getService(ApplicationRegistry.class); - ApplicationInfo appInfo = appRegistry.get(PayaraFangService.FANG_APP_NAME); + ApplicationInfo appInfo = appRegistry.get(applicationName); if (appInfo != null && appInfo.isLoaded()) { payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADED); return; } - Application config = payaraFangAdapter.getConfig(); + Application config = payaraFangAdapter.getSystemApplicationConfig(); if (config == null) { throw new IllegalStateException("Payara Fang has no system app entry!"); @@ -219,10 +225,51 @@ private void load() { // Load the Payara Fang Application String instanceName = serverEnv.getInstanceName(); - ApplicationRef ref = domain.getApplicationRefInServer(instanceName, PayaraFangService.FANG_APP_NAME); + ApplicationRef ref = domain.getApplicationRefInServer(instanceName, applicationName); habitat.getService(ApplicationLoaderService.class).processApplication(config, ref); - // Update adapter state + // Update adapter state and mark as registered payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADED); + payaraFangAdapter.setAppRegistered(true); } + + private void checkAndResolveApplicationName(SystemApplications systemApplications) { + // Check if the application name is not empty + if (applicationName == null || applicationName.equals("")) { + logger.log(Level.INFO, "No or incorrect application name detected for Payara Fang: reverting to default"); + applicationName = PayaraFangStartupService.DEFAULT_FANG_APP_NAME; + applicationNameChanged = true; + } + + // Loop through the system applications + boolean validApplicationNameFound = false; + int applicationNameSuffix = 1; + while (!validApplicationNameFound) { + // Check if the current application name is in use + validApplicationNameFound = isApplicationNameValid(systemApplications); + + if (!validApplicationNameFound) { + // If the name isn't valid, append a number to it and try again + applicationName = applicationName + "-" + applicationNameSuffix; + applicationNameSuffix++; + applicationNameChanged = true; + } + } + + } + + private boolean isApplicationNameValid(SystemApplications systemApplications) { + boolean validApplicationNameFound = true; + + // Search through the system application names to check if there are any apps with the same name + for (Application systemApplication : systemApplications.getApplications()) { + if (systemApplication.getName().equals(applicationName)) { + // We've found an application with the same name, that means we can't use this one + validApplicationNameFound = false; + break; + } + } + + return validApplicationNameFound; + } } diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangStartupService.java similarity index 87% rename from appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java rename to appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangStartupService.java index 2625af9ce4f..16ebbc557ab 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangStartupService.java @@ -25,9 +25,9 @@ */ @Service(name = "payara-fang") @RunLevel(PostStartupRunLevel.VAL) -public class PayaraFangService { +public class PayaraFangStartupService { - public static final String FANG_APP_NAME = "__fang"; + public static final String DEFAULT_FANG_APP_NAME = "__fang"; @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) @@ -58,7 +58,8 @@ private void postConstruct() { private void loadApplication() { try { new PayaraFangLoader(payaraFangAdapter, habitat, domain, serverEnv, - payaraFangAdapter.getContextRoot(), payaraFangAdapter.getVirtualServers()).start(); + payaraFangAdapter.getContextRoot(), configuration.getApplicationName(), + payaraFangAdapter.getVirtualServers()).start(); } catch (Exception ex) { throw new RuntimeException("Unable to load Payara Fang!", ex); } diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java index ce27b68afa1..e842d80eda1 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java @@ -9,10 +9,9 @@ import com.sun.enterprise.config.serverbeans.Application; import com.sun.enterprise.config.serverbeans.Config; import com.sun.enterprise.config.serverbeans.Domain; -import fish.payara.appserver.fang.service.PayaraFangService; +import com.sun.enterprise.config.serverbeans.SystemApplications; import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -40,6 +39,7 @@ import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.internal.data.ApplicationRegistry; import org.glassfish.server.ServerEnvironmentImpl; +import org.jvnet.hk2.annotations.Optional; import org.jvnet.hk2.annotations.Service; /** @@ -49,10 +49,10 @@ @Service public final class PayaraFangAdapter extends HttpHandler implements Adapter { private PayaraFangAdapterState stateMsg = PayaraFangAdapterState.UNINITIALISED; - private boolean isOK = false; private boolean isRegistered = false; + private boolean appRegistered = false; private ResourceBundle bundle; - private Method[] allowedHttpMethods = {Method.GET, Method.POST, Method.HEAD, Method.DELETE, Method.PUT}; + private final Method[] allowedHttpMethods = {Method.GET, Method.POST, Method.HEAD, Method.DELETE, Method.PUT}; private static PayaraFangEndpointDecider endpointDecider; @@ -74,36 +74,68 @@ public final class PayaraFangAdapter extends HttpHandler implements Adapter { @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) Config serverConfig; + @Inject + @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) + @Optional + PayaraFangConfiguration fangServiceConfiguration; + private final static Logger logger = Logger.getLogger(PayaraFangAdapter.class.getName()); private final static String RESOURCE_PACKAGE = "fish/payara/appserver/fang/adapter"; private final CountDownLatch latch = new CountDownLatch(1); @PostConstruct public void postConstruct() { + fangServiceConfiguration = habitat.getService(PayaraFangConfiguration.class); init(); } private void init() { - if (appExistsInConfig()) { - setStateMsg(PayaraFangAdapterState.NOT_LOADED); - } else { - setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); - } - try { - PayaraFangConfiguration fangServiceConfiguration = habitat.getService(PayaraFangConfiguration.class); endpointDecider = new PayaraFangEndpointDecider(serverConfig, fangServiceConfiguration); } catch (Exception ex) { logger.log(Level.INFO, "Payara Fang Console cannot initialise", ex); } + + if (appExistsInConfig() && (domain.getSystemApplicationReferencedFrom(env.getInstanceName(), + fangServiceConfiguration.getApplicationName()) != null)) { + setStateMsg(PayaraFangAdapterState.NOT_LOADED); + setAppRegistered(true); + } else { + setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); + } } - private boolean appExistsInConfig() { - return (getConfig() != null); + public boolean appExistsInConfig() { + return (getSystemApplicationConfig() != null); } - public Application getConfig() { - return domain.getSystemApplicationReferencedFrom(env.getInstanceName(), PayaraFangService.FANG_APP_NAME); + public Application getSystemApplicationConfig() { + // First, check if there is an app registered for this server with the given application name + Application application = domain.getSystemApplicationReferencedFrom(env.getInstanceName(), + fangServiceConfiguration.getApplicationName()); + + // If the app hasn't been registered to the instance yet, the previous check will return null, so check for one + // with a matching context root instead (as these are also unique) + if (application == null) { + application = getApplicationWithMatchingContextRoot(); + } + + return application; + } + + private Application getApplicationWithMatchingContextRoot() { + Application application = null; + String contextRoot = getContextRoot(); + + SystemApplications systemApplications = domain.getSystemApplications(); + for (Application systemApplication : systemApplications.getApplications()) { + if (systemApplication.getContextRoot().equals(contextRoot)) { + application = systemApplication; + break; + } + } + + return application; } private PayaraFangAdapterState getStateMsg() { @@ -324,4 +356,12 @@ public boolean isRegistered() { public void setRegistered(boolean isRegistered) { this.isRegistered = isRegistered; } + + public boolean isAppRegistered() { + return appRegistered; + } + + public void setAppRegistered(boolean appRegistered) { + this.appRegistered = true; + } } diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java index 2093e14f22e..da6388c6193 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java @@ -9,14 +9,10 @@ import java.util.Collections; import java.util.List; import java.util.logging.Logger; -import javax.annotation.PostConstruct; import javax.inject.Inject; -import javax.inject.Named; -import org.glassfish.api.admin.ServerEnvironment; import org.glassfish.grizzly.config.dom.NetworkListener; import org.glassfish.grizzly.config.dom.ThreadPool; import org.glassfish.hk2.api.ServiceLocator; -import org.jvnet.hk2.annotations.Optional; /** * @@ -29,7 +25,7 @@ public class PayaraFangEndpointDecider { private InetAddress address; private int maxThreadPoolSize = 5; private Config config; - private Logger logger = Logger.getLogger(PayaraFangEndpointDecider.class.getName()); + private static final Logger logger = Logger.getLogger(PayaraFangEndpointDecider.class.getName()); private List hosts; private PayaraFangConfiguration fangServiceConfiguration; diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java new file mode 100644 index 00000000000..39093a93c61 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java @@ -0,0 +1,38 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package fish.payara.appserver.fang.service.admin; + +import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; +import org.glassfish.api.admin.AdminCommand; +import org.glassfish.api.admin.AdminCommandContext; +import org.glassfish.api.admin.ExecuteOn; +import org.glassfish.api.admin.RestEndpoint; +import org.glassfish.api.admin.RestEndpoints; +import org.glassfish.api.admin.RuntimeType; +import org.glassfish.hk2.api.PerLookup; +import org.jvnet.hk2.annotations.Service; + +/** + * + * @author Andrew Pielage + */ +@Service(name = "set-payara-fang-configuration") +@PerLookup +@ExecuteOn(RuntimeType.DAS) +@RestEndpoints({ + @RestEndpoint(configBean = PayaraFangConfiguration.class, + opType = RestEndpoint.OpType.POST, + path = "set-payara-fang-configuration", + description = "Sets the Payara Fang Configuration") +}) +public class SetPayaraFangConfigurationCommand implements AdminCommand { + + @Override + public void execute(AdminCommandContext context) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + +} diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java index 3c3824a9162..2a058be6ff6 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java @@ -29,4 +29,8 @@ public interface PayaraFangConfiguration extends ConfigBeanProxy, ConfigExtensio @Attribute(defaultValue="/fang") String getContextRoot(); void setContextRoot(String contextRoot) throws PropertyVetoException; + + @Attribute(defaultValue="__fang") + String getApplicationName(); + void setApplicationName(String name) throws PropertyVetoException; } From 50fc9543e154722a67d29584cdf17209bbcfa9fd Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Thu, 20 Apr 2017 09:00:17 +0100 Subject: [PATCH 08/22] Fill out set command --- .../fang/service/PayaraFangLoader.java | 36 ++--- .../fang/service/PayaraFangService.java | 133 ++++++++++++++++++ .../service/PayaraFangStartupService.java | 67 --------- .../SetPayaraFangConfigurationCommand.java | 52 ++++++- .../PayaraFangConfiguration.java | 2 +- 5 files changed, 203 insertions(+), 87 deletions(-) create mode 100644 appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java delete mode 100644 appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangStartupService.java diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java index 3581d488818..ba349e301ed 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java @@ -15,6 +15,7 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import javax.inject.Inject; import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.internal.data.ApplicationInfo; import org.glassfish.internal.data.ApplicationRegistry; @@ -33,12 +34,11 @@ public class PayaraFangLoader extends Thread { private final ServerEnvironmentImpl serverEnv; private final String contextRoot; private String applicationName; - private boolean applicationNameChanged = false; private final PayaraFangAdapter payaraFangAdapter; private final ServiceLocator habitat; - private final Logger logger = Logger.getLogger(PayaraFangLoader.class.getName()); + private static final Logger LOGGER = Logger.getLogger(PayaraFangLoader.class.getName()); private final List vss; - + PayaraFangLoader(PayaraFangAdapter payaraFangAdapter, ServiceLocator habitat, Domain domain, ServerEnvironmentImpl serverEnv, String contextRoot, String applicationName, List vss) { this.payaraFangAdapter = payaraFangAdapter; @@ -53,20 +53,22 @@ public class PayaraFangLoader extends Thread { @Override public void run() { try { - // Check if the application already exists, creating the system-app entry if it isn't + // Check if the application already exists if (payaraFangAdapter.appExistsInConfig()) { // Check if the app is actually registered to this instance if (!payaraFangAdapter.isAppRegistered()) { + // We hit here if the app exists, but hasn't been registered to this instance yet registerApplication(); } } else { + // If the app simply doesn't exist, create one and register it for this instance createAndRegisterApplication(); } loadApplication(); } catch (Exception ex) { payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); - logger.log(Level.WARNING, "Problem while attempting to register Payara Fang!", ex); + LOGGER.log(Level.WARNING, "Problem while attempting to register Payara Fang!", ex); } } @@ -77,8 +79,8 @@ public void run() { private void createAndRegisterApplication() throws Exception { // Update the adapter state payaraFangAdapter.setStateMsg(PayaraFangAdapterState.REGISTERING); - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, "Registering the Payara Fang Application..."); + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, "Registering the Payara Fang Application..."); } // Create the system application entry and application-ref in the config @@ -101,7 +103,7 @@ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, Tran try { application.setLocation("${com.sun.aas.installRootURI}/lib/install/applications/" - + PayaraFangStartupService.DEFAULT_FANG_APP_NAME); + + PayaraFangService.DEFAULT_FANG_APP_NAME); } catch (Exception me) { throw new RuntimeException(me); } @@ -138,16 +140,16 @@ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, Tran // Update the adapter state payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, "Payara Fang Registered."); + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, "Payara Fang Registered."); } } private void registerApplication() throws Exception { // Update the adapter state payaraFangAdapter.setStateMsg(PayaraFangAdapterState.REGISTERING); - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, "Registering the Payara Fang Application..."); + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, "Registering the Payara Fang Application..."); } // Create the application-ref entry in the domain.xml @@ -185,8 +187,8 @@ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, Tran // Update the adapter state payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, "Payara Fang Registered."); + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, "Payara Fang Registered."); } } @@ -236,9 +238,8 @@ private void loadApplication() { private void checkAndResolveApplicationName(SystemApplications systemApplications) { // Check if the application name is not empty if (applicationName == null || applicationName.equals("")) { - logger.log(Level.INFO, "No or incorrect application name detected for Payara Fang: reverting to default"); - applicationName = PayaraFangStartupService.DEFAULT_FANG_APP_NAME; - applicationNameChanged = true; + LOGGER.log(Level.INFO, "No or incorrect application name detected for Payara Fang: reverting to default"); + applicationName = PayaraFangService.DEFAULT_FANG_APP_NAME; } // Loop through the system applications @@ -252,7 +253,6 @@ private void checkAndResolveApplicationName(SystemApplications systemApplication // If the name isn't valid, append a number to it and try again applicationName = applicationName + "-" + applicationNameSuffix; applicationNameSuffix++; - applicationNameChanged = true; } } diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java new file mode 100644 index 00000000000..831bbc29fcd --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java @@ -0,0 +1,133 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package fish.payara.appserver.fang.service; + +import com.sun.enterprise.config.serverbeans.Application; +import com.sun.enterprise.config.serverbeans.Config; +import com.sun.enterprise.config.serverbeans.Domain; +import com.sun.enterprise.config.serverbeans.SystemApplications; +import fish.payara.appserver.fang.service.adapter.PayaraFangAdapter; +import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; +import java.beans.PropertyChangeEvent; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.inject.Named; +import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.api.admin.config.ApplicationName; +import org.glassfish.api.event.EventListener; +import org.glassfish.api.event.EventTypes; +import org.glassfish.api.event.Events; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.hk2.runlevel.RunLevel; +import org.glassfish.internal.api.PostStartupRunLevel; +import org.glassfish.server.ServerEnvironmentImpl; +import org.jvnet.hk2.annotations.Optional; +import org.jvnet.hk2.annotations.Service; +import org.jvnet.hk2.config.ConfigBeanProxy; +import org.jvnet.hk2.config.ConfigListener; +import org.jvnet.hk2.config.UnprocessedChangeEvent; +import org.jvnet.hk2.config.UnprocessedChangeEvents; + +/** + * + * @author Andrew Pielage + */ +@Service(name = "payara-fang") +@RunLevel(PostStartupRunLevel.VAL) +public class PayaraFangService implements ConfigListener { + + public static final String DEFAULT_FANG_APP_NAME = "__fang"; + private boolean bootstrapped = false; + + @Inject + @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) + @Optional + private PayaraFangConfiguration configuration; + + @Inject + private PayaraFangAdapter payaraFangAdapter; + + @Inject + Domain domain; + + @Inject + ServerEnvironmentImpl serverEnv; + + @Inject + ServiceLocator habitat; + + @PostConstruct + private void postConstruct() { + configuration = habitat.getService(PayaraFangConfiguration.class); + + if (configuration.getEnabled().equals("true")) { + loadApplication(); + } + } + + private void loadApplication() { + try { + new PayaraFangLoader(payaraFangAdapter, habitat, domain, serverEnv, + payaraFangAdapter.getContextRoot(), configuration.getApplicationName(), + payaraFangAdapter.getVirtualServers()).start(); + } catch (Exception ex) { + throw new RuntimeException("Unable to load Payara Fang!", ex); + } + } + + @Override + public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvents) { + List unprocessedChanges = new ArrayList<>(); + + for (PropertyChangeEvent propertyChangeEvent : propertyChangeEvents) { + // Check if the property change event is for us. + if (propertyChangeEvent.getSource().toString().equals("GlassFishConfigBean." + + PayaraFangConfiguration.class.getName()) && isCurrentInstanceMatchTarget(propertyChangeEvent)) { + // Check if the property has actually changed + if (!propertyChangeEvent.getOldValue().equals(propertyChangeEvent.getNewValue())) { + if (propertyChangeEvent.getPropertyName().equals("enabled") && !bootstrapped) { + loadApplication(); + } else { + unprocessedChanges.add(new UnprocessedChangeEvent(propertyChangeEvent, + "Payara Fang redeploy required")); + } + } + } + } + + if (unprocessedChanges.isEmpty()) { + return null; + } else { + return new UnprocessedChangeEvents(unprocessedChanges); + } + } + + private boolean isCurrentInstanceMatchTarget(PropertyChangeEvent propertyChangeEvent) { + + // If we are an instance then the change will apply to us as it has been + // replicated directly to us by the DAS + if (serverEnv.isInstance()) { + return true; + } + + ConfigBeanProxy proxy = (ConfigBeanProxy) propertyChangeEvent.getSource(); + + // Find the config parent + while (proxy != null && !(proxy instanceof Config)) { + proxy = proxy.getParent(); + } + + if (proxy != null) { + // We have found a config node at the root + // If the root config is the das config return true + return ((Config)proxy).isDas(); + } + + return false; + } +} diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangStartupService.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangStartupService.java deleted file mode 100644 index 16ebbc557ab..00000000000 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangStartupService.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package fish.payara.appserver.fang.service; - -import com.sun.enterprise.config.serverbeans.Domain; -import fish.payara.appserver.fang.service.adapter.PayaraFangAdapter; -import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import javax.inject.Named; -import org.glassfish.api.admin.ServerEnvironment; -import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.hk2.runlevel.RunLevel; -import org.glassfish.internal.api.PostStartupRunLevel; -import org.glassfish.server.ServerEnvironmentImpl; -import org.jvnet.hk2.annotations.Optional; -import org.jvnet.hk2.annotations.Service; - -/** - * - * @author Andrew Pielage - */ -@Service(name = "payara-fang") -@RunLevel(PostStartupRunLevel.VAL) -public class PayaraFangStartupService { - - public static final String DEFAULT_FANG_APP_NAME = "__fang"; - - @Inject - @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) - @Optional - private PayaraFangConfiguration configuration; - - @Inject - private PayaraFangAdapter payaraFangAdapter; - - @Inject - Domain domain; - - @Inject - ServerEnvironmentImpl serverEnv; - - @Inject - ServiceLocator habitat; - - @PostConstruct - private void postConstruct() { - configuration = habitat.getService(PayaraFangConfiguration.class); - - if (configuration.getEnabled().equals("true")) { - loadApplication(); - } - } - - private void loadApplication() { - try { - new PayaraFangLoader(payaraFangAdapter, habitat, domain, serverEnv, - payaraFangAdapter.getContextRoot(), configuration.getApplicationName(), - payaraFangAdapter.getVirtualServers()).start(); - } catch (Exception ex) { - throw new RuntimeException("Unable to load Payara Fang!", ex); - } - } -} diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java index 39093a93c61..6b2d67a5350 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java @@ -5,7 +5,12 @@ */ package fish.payara.appserver.fang.service.admin; +import com.sun.enterprise.config.serverbeans.Config; import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; +import java.beans.PropertyVetoException; +import java.util.logging.Logger; +import javax.inject.Inject; +import org.glassfish.api.Param; import org.glassfish.api.admin.AdminCommand; import org.glassfish.api.admin.AdminCommandContext; import org.glassfish.api.admin.ExecuteOn; @@ -13,7 +18,11 @@ import org.glassfish.api.admin.RestEndpoints; import org.glassfish.api.admin.RuntimeType; import org.glassfish.hk2.api.PerLookup; +import org.glassfish.internal.api.Target; import org.jvnet.hk2.annotations.Service; +import org.jvnet.hk2.config.ConfigSupport; +import org.jvnet.hk2.config.SingleConfigCode; +import org.jvnet.hk2.config.TransactionFailure; /** * @@ -30,9 +39,50 @@ }) public class SetPayaraFangConfigurationCommand implements AdminCommand { + private final static Logger LOGGER = Logger.getLogger(SetPayaraFangConfigurationCommand.class.getName()); + + @Param(optional = true, defaultValue = "server-config") + String target; + + @Param(optional = true) + Boolean enabled; + + @Param(optional = true, alias = "contextroot") + String contextRoot; + + @Param(optional = true) + String name; + + @Inject + private Target targetUtil; + @Override public void execute(AdminCommandContext context) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + Config targetConfig = targetUtil.getConfig(target); + PayaraFangConfiguration fangConfiguration = targetConfig.getExtensionByType(PayaraFangConfiguration.class); + + try { + ConfigSupport.apply(new SingleConfigCode(){ + @Override + public Object run(PayaraFangConfiguration configProxy) throws PropertyVetoException { + if (enabled != null) { + configProxy.setEnabled(enabled.toString()); + } + + if (contextRoot != null) { + configProxy.setContextRoot(contextRoot); + } + + if (name != null) { + configProxy.setApplicationName(name); + } + + return null; + } + }, fangConfiguration); + } catch (TransactionFailure ex) { + context.getActionReport().failure(LOGGER, "Failed to update Payara Fang configuration", ex); + } } } diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java index 2a058be6ff6..872731443e5 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java @@ -22,7 +22,7 @@ public interface PayaraFangConfiguration extends ConfigBeanProxy, ConfigExtensio * Checks if Payara Fang is enabled or not * @return true if enabled */ - @Attribute(defaultValue="false") + @Attribute(defaultValue="false", dataType = Boolean.class) String getEnabled(); void setEnabled(String value) throws PropertyVetoException; From bab91b969072821d347b7b3631cb6d9e0f169def Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Fri, 21 Apr 2017 14:54:54 +0100 Subject: [PATCH 09/22] Delayed boot working --- .../fang/service/PayaraFangLoader.java | 50 +++++++++++++------ .../fang/service/PayaraFangService.java | 42 ++++++++++------ .../service/adapter/PayaraFangAdapter.java | 2 +- .../adapter/PayaraFangAdapterState.java | 1 + 4 files changed, 65 insertions(+), 30 deletions(-) diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java index ba349e301ed..6bfdeb3cf05 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java @@ -59,16 +59,21 @@ public void run() { if (!payaraFangAdapter.isAppRegistered()) { // We hit here if the app exists, but hasn't been registered to this instance yet registerApplication(); + } else if (!contextRoot.equals(payaraFangAdapter.getSystemApplicationConfig().getContextRoot())) { + // We hit here if there is a system application already created and registered to this instance, but + // we've changed the context root and so need to reconfigure the system app + reconfigureSystemApplication(); } } else { // If the app simply doesn't exist, create one and register it for this instance + // We should only be able to reach here if we're the DAS createAndRegisterApplication(); } loadApplication(); } catch (Exception ex) { payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); - LOGGER.log(Level.WARNING, "Problem while attempting to register Payara Fang!", ex); + LOGGER.log(Level.WARNING, "Problem while attempting to register or load Payara Fang!", ex); } } @@ -79,9 +84,7 @@ public void run() { private void createAndRegisterApplication() throws Exception { // Update the adapter state payaraFangAdapter.setStateMsg(PayaraFangAdapterState.REGISTERING); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.log(Level.FINE, "Registering the Payara Fang Application..."); - } + LOGGER.log(Level.FINE, "Registering the Payara Fang Application..."); // Create the system application entry and application-ref in the config ConfigCode code = new ConfigCode() { @@ -140,17 +143,13 @@ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, Tran // Update the adapter state payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.log(Level.FINE, "Payara Fang Registered."); - } + LOGGER.log(Level.FINE, "Payara Fang Registered."); } private void registerApplication() throws Exception { // Update the adapter state payaraFangAdapter.setStateMsg(PayaraFangAdapterState.REGISTERING); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.log(Level.FINE, "Registering the Payara Fang Application..."); - } + LOGGER.log(Level.FINE, "Registering the Payara Fang Application..."); // Create the application-ref entry in the domain.xml ConfigCode code = new ConfigCode() { @@ -187,9 +186,7 @@ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, Tran // Update the adapter state payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.log(Level.FINE, "Payara Fang Registered."); - } + LOGGER.log(Level.FINE, "Payara Fang Registered."); } private String getVirtualServerListAsString() { @@ -271,5 +268,30 @@ private boolean isApplicationNameValid(SystemApplications systemApplications) { } return validApplicationNameFound; - } + } + + private void reconfigureSystemApplication() throws Exception { + Application systemApplication = payaraFangAdapter.getSystemApplicationConfig(); + + // Update the adapter state + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.RECONFIGURING); + LOGGER.log(Level.FINE, "Reconfiguring the Payara Fang Application..."); + + // Reconfigure the system-application entry in the domain.xml + ConfigCode code = new ConfigCode() { + @Override + public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, TransactionFailure { + Application systemApplication = (Application) proxies[0]; + systemApplication.setContextRoot(contextRoot); + + return true; + } + }; + + ConfigSupport.apply(code, systemApplication); + + // Update the adapter state + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); + LOGGER.log(Level.FINE, "Payara Fang Reconfigured."); + } } diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java index 831bbc29fcd..6b1ff3f4e55 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java @@ -5,11 +5,11 @@ */ package fish.payara.appserver.fang.service; -import com.sun.enterprise.config.serverbeans.Application; import com.sun.enterprise.config.serverbeans.Config; import com.sun.enterprise.config.serverbeans.Domain; -import com.sun.enterprise.config.serverbeans.SystemApplications; import fish.payara.appserver.fang.service.adapter.PayaraFangAdapter; +import fish.payara.appserver.fang.service.adapter.PayaraFangAdapterState; +import fish.payara.appserver.fang.service.adapter.PayaraFangEndpointDecider; import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; import java.beans.PropertyChangeEvent; import java.util.ArrayList; @@ -18,10 +18,6 @@ import javax.inject.Inject; import javax.inject.Named; import org.glassfish.api.admin.ServerEnvironment; -import org.glassfish.api.admin.config.ApplicationName; -import org.glassfish.api.event.EventListener; -import org.glassfish.api.event.EventTypes; -import org.glassfish.api.event.Events; import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.hk2.runlevel.RunLevel; import org.glassfish.internal.api.PostStartupRunLevel; @@ -42,12 +38,13 @@ public class PayaraFangService implements ConfigListener { public static final String DEFAULT_FANG_APP_NAME = "__fang"; - private boolean bootstrapped = false; + private boolean startAttempted = false; + private String contextRoot; @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) @Optional - private PayaraFangConfiguration configuration; + private PayaraFangConfiguration payaraFangConfiguration; @Inject private PayaraFangAdapter payaraFangAdapter; @@ -63,17 +60,19 @@ public class PayaraFangService implements ConfigListener { @PostConstruct private void postConstruct() { - configuration = habitat.getService(PayaraFangConfiguration.class); + contextRoot = payaraFangAdapter.getContextRoot(); + payaraFangConfiguration = habitat.getService(PayaraFangConfiguration.class); - if (configuration.getEnabled().equals("true")) { + if (payaraFangConfiguration.getEnabled().equals("true")) { loadApplication(); } } private void loadApplication() { + startAttempted = true; try { new PayaraFangLoader(payaraFangAdapter, habitat, domain, serverEnv, - payaraFangAdapter.getContextRoot(), configuration.getApplicationName(), + contextRoot, payaraFangConfiguration.getApplicationName(), payaraFangAdapter.getVirtualServers()).start(); } catch (Exception ex) { throw new RuntimeException("Unable to load Payara Fang!", ex); @@ -83,6 +82,7 @@ private void loadApplication() { @Override public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvents) { List unprocessedChanges = new ArrayList<>(); + boolean attemptStart = false; for (PropertyChangeEvent propertyChangeEvent : propertyChangeEvents) { // Check if the property change event is for us. @@ -90,16 +90,28 @@ public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvent + PayaraFangConfiguration.class.getName()) && isCurrentInstanceMatchTarget(propertyChangeEvent)) { // Check if the property has actually changed if (!propertyChangeEvent.getOldValue().equals(propertyChangeEvent.getNewValue())) { - if (propertyChangeEvent.getPropertyName().equals("enabled") && !bootstrapped) { - loadApplication(); + // If the application hasn't attempted to start yet + if (propertyChangeEvent.getPropertyName().equals("enabled") && !startAttempted) { + // Set a flag to attempt a load of the application + attemptStart = true; + } else if (propertyChangeEvent.getPropertyName().equals("context-root") && !startAttempted) { + // If we haven't attempted to start yet, grab the new context root + Config serverConfig = domain.getServerNamed(serverEnv.getInstanceName()).getConfig(); + PayaraFangEndpointDecider endpointDecider = new PayaraFangEndpointDecider(serverConfig, + payaraFangConfiguration); + contextRoot = endpointDecider.getContextRoot(); } else { - unprocessedChanges.add(new UnprocessedChangeEvent(propertyChangeEvent, - "Payara Fang redeploy required")); + unprocessedChanges.add(new UnprocessedChangeEvent(propertyChangeEvent, + "Payara Fang redeploy required")); } } } } + if (attemptStart) { + loadApplication(); + } + if (unprocessedChanges.isEmpty()) { return null; } else { diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java index e842d80eda1..316ce370235 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java @@ -138,7 +138,7 @@ private Application getApplicationWithMatchingContextRoot() { return application; } - private PayaraFangAdapterState getStateMsg() { + public PayaraFangAdapterState getStateMsg() { return stateMsg; } diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java index 4f1e194eebd..046e1d703d7 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java @@ -11,6 +11,7 @@ public enum PayaraFangAdapterState { UNINITIALISED("state.uninitialised", "Payara Fang has not been initialised yet"), REGISTERING("state.registering", "Payara Fang is being registered as a system application"), NOT_REGISTERED("state.notRegistered", "Payara Fang is not registered in the config"), + RECONFIGURING("state.reconfiguring", "Payara Fang system-application entry is being reconfigured"), WELCOME_TO("status.welcometo", "Welcome to "); private final String desc; From bd27f1a9b3c5fb4ed2f12149a24fe1272630508c Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Fri, 21 Apr 2017 15:04:13 +0100 Subject: [PATCH 10/22] Minor refactor --- .../fang/service/PayaraFangService.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java index 6b1ff3f4e55..731561365be 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java @@ -85,22 +85,26 @@ public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvent boolean attemptStart = false; for (PropertyChangeEvent propertyChangeEvent : propertyChangeEvents) { - // Check if the property change event is for us. + // Check that the property change event is for us. if (propertyChangeEvent.getSource().toString().equals("GlassFishConfigBean." + PayaraFangConfiguration.class.getName()) && isCurrentInstanceMatchTarget(propertyChangeEvent)) { // Check if the property has actually changed if (!propertyChangeEvent.getOldValue().equals(propertyChangeEvent.getNewValue())) { // If the application hasn't attempted to start yet - if (propertyChangeEvent.getPropertyName().equals("enabled") && !startAttempted) { - // Set a flag to attempt a load of the application - attemptStart = true; - } else if (propertyChangeEvent.getPropertyName().equals("context-root") && !startAttempted) { - // If we haven't attempted to start yet, grab the new context root - Config serverConfig = domain.getServerNamed(serverEnv.getInstanceName()).getConfig(); - PayaraFangEndpointDecider endpointDecider = new PayaraFangEndpointDecider(serverConfig, - payaraFangConfiguration); - contextRoot = endpointDecider.getContextRoot(); + if (!startAttempted) { + // We can only get here if enabled was false at server start, so it's safe to assume that enabled + // is being set to true + if (propertyChangeEvent.getPropertyName().equals("enabled")) { + attemptStart = true; + } else if (propertyChangeEvent.getPropertyName().equals("context-root")) { + // If we haven't attempted to start the app yet, grab the new context root + Config serverConfig = domain.getServerNamed(serverEnv.getInstanceName()).getConfig(); + PayaraFangEndpointDecider endpointDecider = new PayaraFangEndpointDecider(serverConfig, + payaraFangConfiguration); + contextRoot = endpointDecider.getContextRoot(); + } } else { + // If a startup has been attempted, just throw an unprocessed change event unprocessedChanges.add(new UnprocessedChangeEvent(propertyChangeEvent, "Payara Fang redeploy required")); } @@ -108,6 +112,7 @@ public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvent } } + // This should only be true if Payara Fang was not enabled at startup, and we've just enabled the service if (attemptStart) { loadApplication(); } From d67eab56f74a2f50a869c7957c24861ccc3a8a3e Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Fri, 21 Apr 2017 15:08:51 +0100 Subject: [PATCH 11/22] Copyright --- .../fang/service/PayaraFangLoader.java | 89 +++++++++++++++---- .../fang/service/PayaraFangService.java | 50 +++++++++-- .../service/adapter/PayaraFangAdapter.java | 79 +++++++++++++++- .../adapter/PayaraFangAdapterState.java | 40 +++++++++ .../adapter/PayaraFangEndpointDecider.java | 40 +++++++++ .../SetPayaraFangConfigurationCommand.java | 58 ++++++++++-- .../PayaraFangConfiguration.java | 41 ++++++++- 7 files changed, 362 insertions(+), 35 deletions(-) diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java index 6bfdeb3cf05..e1b7a79e00f 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java @@ -1,3 +1,43 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + package fish.payara.appserver.fang.service; import com.sun.enterprise.config.serverbeans.Application; @@ -15,7 +55,6 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import javax.inject.Inject; import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.internal.data.ApplicationInfo; import org.glassfish.internal.data.ApplicationRegistry; @@ -38,9 +77,11 @@ public class PayaraFangLoader extends Thread { private final ServiceLocator habitat; private static final Logger LOGGER = Logger.getLogger(PayaraFangLoader.class.getName()); private final List vss; + private final boolean dynamicStart; PayaraFangLoader(PayaraFangAdapter payaraFangAdapter, ServiceLocator habitat, Domain domain, - ServerEnvironmentImpl serverEnv, String contextRoot, String applicationName, List vss) { + ServerEnvironmentImpl serverEnv, String contextRoot, String applicationName, List vss, + boolean dynamicStart) { this.payaraFangAdapter = payaraFangAdapter; this.habitat = habitat; this.domain = domain; @@ -48,28 +89,46 @@ public class PayaraFangLoader extends Thread { this.contextRoot = contextRoot; this.applicationName = applicationName; this.vss = vss; + this.dynamicStart = dynamicStart; } @Override public void run() { try { - // Check if the application already exists - if (payaraFangAdapter.appExistsInConfig()) { - // Check if the app is actually registered to this instance - if (!payaraFangAdapter.isAppRegistered()) { - // We hit here if the app exists, but hasn't been registered to this instance yet - registerApplication(); - } else if (!contextRoot.equals(payaraFangAdapter.getSystemApplicationConfig().getContextRoot())) { - // We hit here if there is a system application already created and registered to this instance, but - // we've changed the context root and so need to reconfigure the system app - reconfigureSystemApplication(); + // Check if we've started the service dynamically, and so whether or not to override the adapter's config + if (dynamicStart) { + if (payaraFangAdapter.appExistsInConfig(contextRoot)) { + // Check if we need to reconfigure system app to match the overriding config + if (!payaraFangAdapter.isAppRegistered(contextRoot)) { + registerApplication(); + } else { + // Since we're starting dynamically, assume that we need to reconfigure + reconfigureSystemApplication(); + } + } else { + // If the app simply doesn't exist, create one and register it for this instance + createAndRegisterApplication(); } } else { - // If the app simply doesn't exist, create one and register it for this instance - // We should only be able to reach here if we're the DAS - createAndRegisterApplication(); + // Check if the application already exists + if (payaraFangAdapter.appExistsInConfig()) { + // Check if the app is actually registered to this instance + if (!payaraFangAdapter.isAppRegistered()) { + // We hit here if the app exists, but hasn't been registered to this instance yet + registerApplication(); + } else if (!contextRoot.equals(payaraFangAdapter.getSystemApplicationConfig().getContextRoot())) { + // We hit here if there is a system application already created and registered to this instance, + // but we've changed the context root and so need to reconfigure the system app + reconfigureSystemApplication(); + } + } else { + // If the app simply doesn't exist, create one and register it for this instance + createAndRegisterApplication(); + } } + + loadApplication(); } catch (Exception ex) { payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java index 731561365be..82a0e4c6479 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java @@ -1,14 +1,48 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. */ + package fish.payara.appserver.fang.service; import com.sun.enterprise.config.serverbeans.Config; import com.sun.enterprise.config.serverbeans.Domain; import fish.payara.appserver.fang.service.adapter.PayaraFangAdapter; -import fish.payara.appserver.fang.service.adapter.PayaraFangAdapterState; import fish.payara.appserver.fang.service.adapter.PayaraFangEndpointDecider; import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; import java.beans.PropertyChangeEvent; @@ -39,6 +73,7 @@ public class PayaraFangService implements ConfigListener { public static final String DEFAULT_FANG_APP_NAME = "__fang"; private boolean startAttempted = false; + private boolean dynamicStart = false; private String contextRoot; @Inject @@ -73,7 +108,7 @@ private void loadApplication() { try { new PayaraFangLoader(payaraFangAdapter, habitat, domain, serverEnv, contextRoot, payaraFangConfiguration.getApplicationName(), - payaraFangAdapter.getVirtualServers()).start(); + payaraFangAdapter.getVirtualServers(), dynamicStart).start(); } catch (Exception ex) { throw new RuntimeException("Unable to load Payara Fang!", ex); } @@ -82,7 +117,6 @@ private void loadApplication() { @Override public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvents) { List unprocessedChanges = new ArrayList<>(); - boolean attemptStart = false; for (PropertyChangeEvent propertyChangeEvent : propertyChangeEvents) { // Check that the property change event is for us. @@ -95,7 +129,7 @@ public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvent // We can only get here if enabled was false at server start, so it's safe to assume that enabled // is being set to true if (propertyChangeEvent.getPropertyName().equals("enabled")) { - attemptStart = true; + dynamicStart = true; } else if (propertyChangeEvent.getPropertyName().equals("context-root")) { // If we haven't attempted to start the app yet, grab the new context root Config serverConfig = domain.getServerNamed(serverEnv.getInstanceName()).getConfig(); @@ -113,7 +147,7 @@ public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvent } // This should only be true if Payara Fang was not enabled at startup, and we've just enabled the service - if (attemptStart) { + if (dynamicStart) { loadApplication(); } diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java index 316ce370235..acdee78cccb 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java @@ -1,8 +1,43 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. */ + package fish.payara.appserver.fang.service.adapter; import com.sun.appserv.server.util.Version; @@ -109,6 +144,10 @@ public boolean appExistsInConfig() { return (getSystemApplicationConfig() != null); } + public boolean appExistsInConfig(String contextRoot) { + return (getSystemApplicationConfig(contextRoot) != null); + } + public Application getSystemApplicationConfig() { // First, check if there is an app registered for this server with the given application name Application application = domain.getSystemApplicationReferencedFrom(env.getInstanceName(), @@ -123,6 +162,13 @@ public Application getSystemApplicationConfig() { return application; } + public Application getSystemApplicationConfig(String contextRoot) { + // check for an app with a matching context root + Application application = getApplicationWithMatchingContextRoot(contextRoot); + + return application; + } + private Application getApplicationWithMatchingContextRoot() { Application application = null; String contextRoot = getContextRoot(); @@ -138,6 +184,20 @@ private Application getApplicationWithMatchingContextRoot() { return application; } + private Application getApplicationWithMatchingContextRoot(String contextRoot) { + Application application = null; + + SystemApplications systemApplications = domain.getSystemApplications(); + for (Application systemApplication : systemApplications.getApplications()) { + if (systemApplication.getContextRoot().equals(contextRoot)) { + application = systemApplication; + break; + } + } + + return application; + } + public PayaraFangAdapterState getStateMsg() { return stateMsg; } @@ -364,4 +424,17 @@ public boolean isAppRegistered() { public void setAppRegistered(boolean appRegistered) { this.appRegistered = true; } + + public boolean isAppRegistered(String contextRoot) { + boolean registered = false; + Application application = getSystemApplicationConfig(contextRoot); + + // Check if we've found an application with a matching context root, and that it's registered to this instance + if (application != null && (domain.getSystemApplicationReferencedFrom(env.getInstanceName(), + application.getName()) != null)) { + registered = true; + } + + return registered; + } } diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java index 046e1d703d7..eb5660ae5d8 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java @@ -1,3 +1,43 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + package fish.payara.appserver.fang.service.adapter; /** diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java index da6388c6193..6eb7ec68aa4 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java @@ -1,3 +1,43 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + package fish.payara.appserver.fang.service.adapter; import com.sun.enterprise.config.serverbeans.Config; diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java index 6b2d67a5350..3617efd8cfa 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java @@ -1,11 +1,48 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. */ + package fish.payara.appserver.fang.service.admin; +import com.sun.enterprise.admin.util.ClusterOperationUtil; import com.sun.enterprise.config.serverbeans.Config; +import com.sun.enterprise.config.serverbeans.Domain; import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; import java.beans.PropertyVetoException; import java.util.logging.Logger; @@ -14,10 +51,14 @@ import org.glassfish.api.admin.AdminCommand; import org.glassfish.api.admin.AdminCommandContext; import org.glassfish.api.admin.ExecuteOn; +import org.glassfish.api.admin.FailurePolicy; +import org.glassfish.api.admin.ParameterMap; import org.glassfish.api.admin.RestEndpoint; import org.glassfish.api.admin.RestEndpoints; import org.glassfish.api.admin.RuntimeType; +import org.glassfish.api.admin.ServerEnvironment; import org.glassfish.hk2.api.PerLookup; +import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.internal.api.Target; import org.jvnet.hk2.annotations.Service; import org.jvnet.hk2.config.ConfigSupport; @@ -30,7 +71,7 @@ */ @Service(name = "set-payara-fang-configuration") @PerLookup -@ExecuteOn(RuntimeType.DAS) +@ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE}) @RestEndpoints({ @RestEndpoint(configBean = PayaraFangConfiguration.class, opType = RestEndpoint.OpType.POST, @@ -56,6 +97,12 @@ public class SetPayaraFangConfigurationCommand implements AdminCommand { @Inject private Target targetUtil; + @Inject + ServiceLocator habitat; + + @Inject + ServerEnvironment serverEnv; + @Override public void execute(AdminCommandContext context) { Config targetConfig = targetUtil.getConfig(target); @@ -83,6 +130,5 @@ public Object run(PayaraFangConfiguration configProxy) throws PropertyVetoExcept } catch (TransactionFailure ex) { context.getActionReport().failure(LOGGER, "Failed to update Payara Fang configuration", ex); } - } - + } } diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java index 872731443e5..899bfc06c01 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java @@ -1,8 +1,43 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. */ + package fish.payara.appserver.fang.service.configuration; import java.beans.PropertyVetoException; From 9075c7c05f5dc05c03ef05628f3ffcd97443e980 Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Fri, 28 Apr 2017 16:34:52 +0100 Subject: [PATCH 12/22] Dynamic start working on DAS and Standalones --- .../appserver/fang/service/PayaraFangLoader.java | 10 ++++++++-- .../appserver/fang/service/PayaraFangService.java | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java index e1b7a79e00f..5f563b5340e 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java @@ -271,8 +271,14 @@ private void loadApplication() { payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADED); return; } - - Application config = payaraFangAdapter.getSystemApplicationConfig(); + + Application config = null; + if (dynamicStart) { + config = payaraFangAdapter.getSystemApplicationConfig(contextRoot); + } else { + config = payaraFangAdapter.getSystemApplicationConfig(); + } + if (config == null) { throw new IllegalStateException("Payara Fang has no system app entry!"); diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java index 82a0e4c6479..527d0686c48 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java @@ -118,6 +118,9 @@ private void loadApplication() { public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvents) { List unprocessedChanges = new ArrayList<>(); + // Reset dynamicStart to default value + dynamicStart = false; + for (PropertyChangeEvent propertyChangeEvent : propertyChangeEvents) { // Check that the property change event is for us. if (propertyChangeEvent.getSource().toString().equals("GlassFishConfigBean." From ff440fce4fb871c1a7fa97f7872b7ce4bd4bdf81 Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Mon, 15 May 2017 15:59:52 +0100 Subject: [PATCH 13/22] Update version number to match master --- appserver/packager/payara-fang/pom.xml | 2 +- appserver/payara-appserver-modules/payara-fang-service/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appserver/packager/payara-fang/pom.xml b/appserver/packager/payara-fang/pom.xml index 2a5d33cfea9..d39376b001b 100644 --- a/appserver/packager/payara-fang/pom.xml +++ b/appserver/packager/payara-fang/pom.xml @@ -19,7 +19,7 @@ org.glassfish.main.packager packages - 4.1.1.172-SNAPSHOT + 4.1.2.172-SNAPSHOT payara-fang Payara Fang Package diff --git a/appserver/payara-appserver-modules/payara-fang-service/pom.xml b/appserver/payara-appserver-modules/payara-fang-service/pom.xml index ea5eccbf1b2..59d289a8464 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/pom.xml +++ b/appserver/payara-appserver-modules/payara-fang-service/pom.xml @@ -4,7 +4,7 @@ org.glassfish.main payara-appserver-modules - 4.1.1.172-SNAPSHOT + 4.1.2.172-SNAPSHOT fish.payara.appserver payara-fang-service From fb1723ecf7c6f14ab8e9db08718db84fa7ba532c Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Tue, 16 May 2017 11:32:09 +0100 Subject: [PATCH 14/22] Cleanup and comments --- .../payara-fang-service/pom.xml | 24 ++ .../fang/service/PayaraFangLoader.java | 16 +- .../fang/service/PayaraFangService.java | 31 ++- .../service/adapter/PayaraFangAdapter.java | 48 ++-- .../adapter/PayaraFangEndpointDecider.java | 2 +- .../SetPayaraFangConfigurationCommand.java | 11 +- .../PayaraFangConfiguration.java | 11 +- .../fang/service/security/FangAuthModule.java | 205 ++++++++++++++++++ 8 files changed, 305 insertions(+), 43 deletions(-) create mode 100644 appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java diff --git a/appserver/payara-appserver-modules/payara-fang-service/pom.xml b/appserver/payara-appserver-modules/payara-fang-service/pom.xml index 59d289a8464..66e9d3cc4e1 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/pom.xml +++ b/appserver/payara-appserver-modules/payara-fang-service/pom.xml @@ -27,5 +27,29 @@ kernel ${project.version} + + javax + javaee-api + 7.0 + provided + + + org.glassfish.main.security + security + ${project.version} + provided + + + org.glassfish.main.admin + rest-client + ${project.version} + provided + + + fish.payara.admingui + console-common + ${project.version} + provided + diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java index 5f563b5340e..4d4ffd232ee 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java @@ -65,7 +65,7 @@ import org.jvnet.hk2.config.TransactionFailure; /** - * + * Loader class for the Payara Fang application. Handles registering and actual loading of the application. * @author Andrew Pielage */ public class PayaraFangLoader extends Thread { @@ -79,6 +79,18 @@ public class PayaraFangLoader extends Thread { private final List vss; private final boolean dynamicStart; + PayaraFangLoader(PayaraFangAdapter payaraFangAdapter, ServiceLocator habitat, Domain domain, + ServerEnvironmentImpl serverEnv, String contextRoot, String applicationName, List vss) { + this.payaraFangAdapter = payaraFangAdapter; + this.habitat = habitat; + this.domain = domain; + this.serverEnv = serverEnv; + this.contextRoot = contextRoot; + this.applicationName = applicationName; + this.vss = vss; + this.dynamicStart = false; + } + PayaraFangLoader(PayaraFangAdapter payaraFangAdapter, ServiceLocator habitat, Domain domain, ServerEnvironmentImpl serverEnv, String contextRoot, String applicationName, List vss, boolean dynamicStart) { @@ -127,8 +139,6 @@ public void run() { } } - - loadApplication(); } catch (Exception ex) { payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java index 527d0686c48..d47bd3cdc61 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java @@ -64,7 +64,7 @@ import org.jvnet.hk2.config.UnprocessedChangeEvents; /** - * + * The core service for the Payara Fang application. Handles starting and reconfiguration of the application. * @author Andrew Pielage */ @Service(name = "payara-fang") @@ -73,7 +73,6 @@ public class PayaraFangService implements ConfigListener { public static final String DEFAULT_FANG_APP_NAME = "__fang"; private boolean startAttempted = false; - private boolean dynamicStart = false; private String contextRoot; @Inject @@ -104,6 +103,17 @@ private void postConstruct() { } private void loadApplication() { + startAttempted = true; + try { + new PayaraFangLoader(payaraFangAdapter, habitat, domain, serverEnv, + contextRoot, payaraFangConfiguration.getApplicationName(), + payaraFangAdapter.getVirtualServers()).start(); + } catch (Exception ex) { + throw new RuntimeException("Unable to load Payara Fang!", ex); + } + } + + private void loadApplication(boolean dynamicStart) { startAttempted = true; try { new PayaraFangLoader(payaraFangAdapter, habitat, domain, serverEnv, @@ -117,9 +127,7 @@ private void loadApplication() { @Override public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvents) { List unprocessedChanges = new ArrayList<>(); - - // Reset dynamicStart to default value - dynamicStart = false; + boolean dynamicStart = false; for (PropertyChangeEvent propertyChangeEvent : propertyChangeEvents) { // Check that the property change event is for us. @@ -129,9 +137,10 @@ public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvent if (!propertyChangeEvent.getOldValue().equals(propertyChangeEvent.getNewValue())) { // If the application hasn't attempted to start yet if (!startAttempted) { - // We can only get here if enabled was false at server start, so it's safe to assume that enabled - // is being set to true + // We can only get here if enabled was false at server start, so in the case of the enabled + // property, we don't need to compare it to the current value - it can only be true if (propertyChangeEvent.getPropertyName().equals("enabled")) { + // Flag that we want to dynamically start Payara Fang dynamicStart = true; } else if (propertyChangeEvent.getPropertyName().equals("context-root")) { // If we haven't attempted to start the app yet, grab the new context root @@ -141,7 +150,7 @@ public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvent contextRoot = endpointDecider.getContextRoot(); } } else { - // If a startup has been attempted, just throw an unprocessed change event + // If a startup has been attempted, just throw an unprocessed change event as we need to restart unprocessedChanges.add(new UnprocessedChangeEvent(propertyChangeEvent, "Payara Fang redeploy required")); } @@ -151,9 +160,10 @@ public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvent // This should only be true if Payara Fang was not enabled at startup, and we've just enabled the service if (dynamicStart) { - loadApplication(); + loadApplication(true); } + // If we need to restart, throw an unprocessed change event if (unprocessedChanges.isEmpty()) { return null; } else { @@ -161,8 +171,7 @@ public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvent } } - private boolean isCurrentInstanceMatchTarget(PropertyChangeEvent propertyChangeEvent) { - + private boolean isCurrentInstanceMatchTarget(PropertyChangeEvent propertyChangeEvent) { // If we are an instance then the change will apply to us as it has been // replicated directly to us by the DAS if (serverEnv.isInstance()) { diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java index acdee78cccb..ea31cba8708 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java @@ -78,7 +78,7 @@ import org.jvnet.hk2.annotations.Service; /** - * + * The adapter class for the Payara Fang application. * @author Andrew Pielage */ @Service @@ -131,6 +131,7 @@ private void init() { logger.log(Level.INFO, "Payara Fang Console cannot initialise", ex); } + // If the app exists in the domain.xml AND it's registered to this instance if (appExistsInConfig() && (domain.getSystemApplicationReferencedFrom(env.getInstanceName(), fangServiceConfiguration.getApplicationName()) != null)) { setStateMsg(PayaraFangAdapterState.NOT_LOADED); @@ -148,42 +149,42 @@ public boolean appExistsInConfig(String contextRoot) { return (getSystemApplicationConfig(contextRoot) != null); } + /** + * Gets the application config for the system application with the matching name or context root (in that order). + * @return The application config, or null if there is no matching application + */ public Application getSystemApplicationConfig() { // First, check if there is an app registered for this server with the given application name Application application = domain.getSystemApplicationReferencedFrom(env.getInstanceName(), fangServiceConfiguration.getApplicationName()); // If the app hasn't been registered to the instance yet, the previous check will return null, so check for one - // with a matching context root instead (as these are also unique) + // with a matching context root instead (as these are also unique and saves us creating an extra app entry) if (application == null) { - application = getApplicationWithMatchingContextRoot(); + application = getApplicationWithMatchingContextRoot(getContextRoot()); } return application; } - public Application getSystemApplicationConfig(String contextRoot) { - // check for an app with a matching context root + /** + * Gets the application config for the system application with the matching context root. This method is used over the + * overloaded method if you want to skip trying to get the application config based on the application name, such as + * if you've reconfigured the application. + * @param contextRoot The context root of the application + * @return The application config, or null if there is no matching application. + */ + public Application getSystemApplicationConfig(String contextRoot) { Application application = getApplicationWithMatchingContextRoot(contextRoot); return application; } - private Application getApplicationWithMatchingContextRoot() { - Application application = null; - String contextRoot = getContextRoot(); - - SystemApplications systemApplications = domain.getSystemApplications(); - for (Application systemApplication : systemApplications.getApplications()) { - if (systemApplication.getContextRoot().equals(contextRoot)) { - application = systemApplication; - break; - } - } - - return application; - } - + /** + * Helper method that searches through all system applications for one with a matching context root. + * @param contextRoot The context root fo the application. + * @return The application config, or null if there are no applications with a matching context root. + */ private Application getApplicationWithMatchingContextRoot(String contextRoot) { Application application = null; @@ -416,7 +417,7 @@ public boolean isRegistered() { public void setRegistered(boolean isRegistered) { this.isRegistered = isRegistered; } - + public boolean isAppRegistered() { return appRegistered; } @@ -425,6 +426,11 @@ public void setAppRegistered(boolean appRegistered) { this.appRegistered = true; } + /** + * Overloaded method that checks if an application with the provided context root has been registered to this instance. + * @param contextRoot The context root to match. + * @return True if an application has been registered to this instance. + */ public boolean isAppRegistered(String contextRoot) { boolean registered = false; Application application = getSystemApplicationConfig(contextRoot); diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java index 6eb7ec68aa4..e1f7a7b87ff 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java @@ -55,7 +55,7 @@ import org.glassfish.hk2.api.ServiceLocator; /** - * + * This class encapsulates the process of resolving the actual endpoint of the Payara Fang application. * @author Andrew Pielage */ public class PayaraFangEndpointDecider { diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java index 3617efd8cfa..6c3ad7e3854 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java @@ -40,9 +40,7 @@ package fish.payara.appserver.fang.service.admin; -import com.sun.enterprise.admin.util.ClusterOperationUtil; import com.sun.enterprise.config.serverbeans.Config; -import com.sun.enterprise.config.serverbeans.Domain; import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; import java.beans.PropertyVetoException; import java.util.logging.Logger; @@ -51,8 +49,6 @@ import org.glassfish.api.admin.AdminCommand; import org.glassfish.api.admin.AdminCommandContext; import org.glassfish.api.admin.ExecuteOn; -import org.glassfish.api.admin.FailurePolicy; -import org.glassfish.api.admin.ParameterMap; import org.glassfish.api.admin.RestEndpoint; import org.glassfish.api.admin.RestEndpoints; import org.glassfish.api.admin.RuntimeType; @@ -94,6 +90,9 @@ public class SetPayaraFangConfigurationCommand implements AdminCommand { @Param(optional = true) String name; + @Param(optional = true, alias = "securityenabled") + Boolean securityEnabled; + @Inject private Target targetUtil; @@ -124,6 +123,10 @@ public Object run(PayaraFangConfiguration configProxy) throws PropertyVetoExcept configProxy.setApplicationName(name); } + if (securityEnabled != null) { + configProxy.setSecurityEnabled(securityEnabled.toString()); + } + return null; } }, fangConfiguration); diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java index 899bfc06c01..5e772c22c01 100644 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java @@ -57,15 +57,20 @@ public interface PayaraFangConfiguration extends ConfigBeanProxy, ConfigExtensio * Checks if Payara Fang is enabled or not * @return true if enabled */ - @Attribute(defaultValue="false", dataType = Boolean.class) + @Attribute(defaultValue = "false", dataType = Boolean.class) String getEnabled(); void setEnabled(String value) throws PropertyVetoException; - @Attribute(defaultValue="/fang") + @Attribute(defaultValue = "/fang") String getContextRoot(); void setContextRoot(String contextRoot) throws PropertyVetoException; - @Attribute(defaultValue="__fang") + @Attribute(defaultValue = "__fang") String getApplicationName(); void setApplicationName(String name) throws PropertyVetoException; + + @Attribute(defaultValue = "false", dataType = Boolean.class) + String getSecurityEnabled(); + void setSecurityEnabled(String value) throws PropertyVetoException; + } diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java new file mode 100644 index 00000000000..066e7513124 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java @@ -0,0 +1,205 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.appserver.fang.service.security; + +import com.sun.enterprise.security.SecurityServicesUtil; +import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; +import java.io.IOException; +import java.security.Principal; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.message.AuthException; +import javax.security.auth.message.AuthStatus; +import javax.security.auth.message.MessageInfo; +import javax.security.auth.message.MessagePolicy; +import javax.security.auth.message.callback.CallerPrincipalCallback; +import javax.security.auth.message.callback.PasswordValidationCallback; +import javax.security.auth.message.module.ServerAuthModule; +import javax.servlet.RequestDispatcher; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import org.glassfish.hk2.api.ServiceLocator; + +/** + * + * @author Andrew Pielage + */ +public class FangAuthModule implements ServerAuthModule { + + private String contextRoot = null; + private CallbackHandler handler = null; + private boolean securityEnabled = false; + +// private static final String SAVED_SUBJECT = "Saved_Subject"; + private static final String ORIG_REQUEST_PATH = "origRequestPath"; + private static final String LOGIN_PAGE = "/login.xhtml"; +// private static final String ERROR_PAGE = "/error.xhtml"; +// private static final String RESPONSE_TYPE = "application/json"; +// private static final String USER_NAME = "userName"; + private static final Class[] SUPPORTED_MESSAGE_TYPES = new Class[] {HttpServletRequest.class, + HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) + throws AuthException { + this.handler = handler; + ServiceLocator habitat = SecurityServicesUtil.getInstance().getHabitat(); + PayaraFangConfiguration fangConfiguration = habitat.getService(PayaraFangConfiguration.class); + + contextRoot = fangConfiguration.getContextRoot(); + securityEnabled = Boolean.parseBoolean(fangConfiguration.getSecurityEnabled()); + } + + @Override + public Class[] getSupportedMessageTypes() { + return SUPPORTED_MESSAGE_TYPES; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) + throws AuthException { + if (securityEnabled) { + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + HttpSession session = request.getSession(); + + // Check if our session has already been authenticated + Principal userPrincipal = request.getUserPrincipal(); + if (userPrincipal != null) { + try { + handler.handle(new Callback[] { new CallerPrincipalCallback(clientSubject, userPrincipal) }); + + return AuthStatus.SUCCESS; + } catch (IOException | UnsupportedCallbackException ex) { + AuthException ae = new AuthException(); + ae.initCause(ex); + throw ae; + } + } + + // See if the username / password has been passed in... + String username = request.getParameter("j_username"); + String password = request.getParameter("j_password"); + if ((username == null) || (password == null) || !request.getMethod().equalsIgnoreCase("post")) { + // Not passed in, show the login page... + String origPath = request.getRequestURI(); + String queryString = request.getQueryString(); + + if ((queryString != null) && (!queryString.isEmpty())) { + origPath += "?" + queryString; + } + + session.setAttribute(ORIG_REQUEST_PATH, origPath); + RequestDispatcher rd = request.getRequestDispatcher(LOGIN_PAGE); + + try { + rd.forward(request, response); + } catch (Exception ex) { + AuthException authException = new AuthException(); + authException.initCause(ex); + throw authException; + } + + return AuthStatus.SEND_CONTINUE; + } + + // Authenticate the details + PasswordValidationCallback pvCallback = new PasswordValidationCallback(clientSubject, username, + password.toCharArray()); + + try { + handler.handle(new Callback[]{pvCallback}); + } catch (Exception ex) { + AuthException ae = new AuthException(); + ae.initCause(ex); + throw ae; + } + + // Register the session as authenticated + messageInfo.getMap().put("javax.servlet.http.registerSession", Boolean.TRUE.toString()); + + // Redirect to original path + try { + String origRequest = (String) session.getAttribute(ORIG_REQUEST_PATH); + + if ((origRequest == null)) { + origRequest = contextRoot; + } + + response.sendRedirect(response.encodeRedirectURL(origRequest)); + } catch (Exception ex) { + AuthException ae = new AuthException(); + ae.initCause(ex); + throw ae; + } + + // Continue... + return AuthStatus.SUCCESS; + } else { + Callback[] callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, "wibbles") }; + + try { + handler.handle(callbacks); + } catch (IOException | UnsupportedCallbackException ex) { + Logger.getLogger(FangAuthModule.class.getName()).log(Level.SEVERE, null, ex); + } + + return AuthStatus.SUCCESS; + } + } + + @Override + public AuthStatus secureResponse(MessageInfo messageInfo, Subject serviceSubject) throws AuthException { + return AuthStatus.SUCCESS; + } + + @Override + public void cleanSubject(MessageInfo messageInfo, Subject subject) throws AuthException { + if (subject != null) { + subject.getPrincipals().clear(); + } + } +} From f019688371c916c2fc689b051049732dab38a112 Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Wed, 24 May 2017 13:07:10 +0100 Subject: [PATCH 15/22] Move Payara Fang into repo --- appserver/packager/payara-fang/pom.xml | 45 +- .../payara-fang/payara-fang-service/pom.xml | 94 ++++ .../fang/service/PayaraFangLoader.java | 372 +++++++++++++++ .../fang/service/PayaraFangService.java | 196 ++++++++ .../service/adapter/PayaraFangAdapter.java | 446 ++++++++++++++++++ .../adapter/PayaraFangAdapterState.java | 76 +++ .../adapter/PayaraFangEndpointDecider.java | 160 +++++++ .../SetPayaraFangConfigurationCommand.java | 137 ++++++ .../PayaraFangConfiguration.java | 76 +++ .../fang/service/security/FangAuthModule.java | 205 ++++++++ .../payara-fang/payara-fang-war/README.md | 3 + .../payara-fang/payara-fang-war/osgi.bundle | 1 + .../payara-fang/payara-fang-war/pom.xml | 127 +++++ .../payara/monitoring/fang/FangConfig.java | 68 +++ .../monitoring/fang/FangResponseToken.java | 110 +++++ .../payara/monitoring/fang/FangState.java | 82 ++++ .../monitoring/fang/MBeanServerDelegate.java | 116 +++++ .../fang/handler/FangStateHandler.java | 88 ++++ .../handler/MBeanAttributeReadHandler.java | 109 +++++ .../fang/handler/MBeanReadHandler.java | 116 +++++ .../monitoring/fang/handler/ReadHandler.java | 58 +++ .../fang/handler/ResourceHandler.java | 187 ++++++++ .../fang/handler/VersionHandler.java | 59 +++ .../fang/processor/ArrayTypeProcessor.java | 82 ++++ .../processor/CompositeTypeProcessor.java | 73 +++ .../fang/processor/OtherTypeProcessor.java | 56 +++ .../fang/processor/ProcessorFactory.java | 126 +++++ .../fang/processor/SimpleTypeProcessor.java | 59 +++ .../fang/processor/TabularTypeProcessor.java | 74 +++ .../fang/processor/TypeProcessor.java | 65 +++ .../fang/resource/FangStateResource.java | 74 +++ .../fang/resource/MBeanReadResource.java | 97 ++++ .../fang/resource/PathProcessor.java | 141 ++++++ .../src/main/webapp/WEB-INF/glassfish-web.xml | 8 + .../src/main/webapp/WEB-INF/web.xml | 32 ++ .../src/main/webapp/error.xhtml | 58 +++ .../src/main/webapp/j_security_check | 40 ++ .../src/main/webapp/login.xhtml | 60 +++ .../payara-fang/pom.xml | 56 +++ appserver/payara-appserver-modules/pom.xml | 2 +- 40 files changed, 4023 insertions(+), 11 deletions(-) create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-service/pom.xml create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/README.md create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/osgi.bundle create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/pom.xml create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangConfig.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangResponseToken.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangState.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/MBeanServerDelegate.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/FangStateHandler.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/MBeanAttributeReadHandler.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/MBeanReadHandler.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/ReadHandler.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/ResourceHandler.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/VersionHandler.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/ArrayTypeProcessor.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/CompositeTypeProcessor.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/OtherTypeProcessor.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/ProcessorFactory.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/SimpleTypeProcessor.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/TabularTypeProcessor.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/TypeProcessor.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/resource/FangStateResource.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/resource/MBeanReadResource.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/resource/PathProcessor.java create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/WEB-INF/glassfish-web.xml create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/WEB-INF/web.xml create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/error.xhtml create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/j_security_check create mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/login.xhtml create mode 100644 appserver/payara-appserver-modules/payara-fang/pom.xml diff --git a/appserver/packager/payara-fang/pom.xml b/appserver/packager/payara-fang/pom.xml index d39376b001b..b08ed2ed76f 100644 --- a/appserver/packager/payara-fang/pom.xml +++ b/appserver/packager/payara-fang/pom.xml @@ -1,17 +1,42 @@ @@ -40,8 +65,8 @@ generate-sources - - + + @@ -118,13 +143,13 @@ - fish.payara.appserver + fish.payara.appserver.payara-fang payara-fang-service ${project.version} - fish.payara.monitoring - Fang + fish.payara.appserver.payara-fang + payara-fang-war ${payara.fang.version} war true diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/pom.xml b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/pom.xml new file mode 100644 index 00000000000..834fb2193f3 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/pom.xml @@ -0,0 +1,94 @@ + + + + 4.0.0 + + fish.payara.appserver.payara-fang + payara-fang-parent + 4.1.2.172-SNAPSHOT + + fish.payara.appserver.payara-fang + payara-fang-service + glassfish-jar + Payara Fang Service + + + + org.glassfish.main.common + glassfish-api + ${project.version} + + + org.glassfish.main.common + internal-api + ${project.version} + + + org.glassfish.main.core + kernel + ${project.version} + + + javax + javaee-api + 7.0 + provided + + + org.glassfish.main.security + security + ${project.version} + provided + + + org.glassfish.main.admin + rest-client + ${project.version} + provided + + + fish.payara.admingui + console-common + ${project.version} + provided + + + diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java new file mode 100644 index 00000000000..4d4ffd232ee --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java @@ -0,0 +1,372 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package fish.payara.appserver.fang.service; + +import com.sun.enterprise.config.serverbeans.Application; +import com.sun.enterprise.config.serverbeans.ApplicationRef; +import com.sun.enterprise.config.serverbeans.Domain; +import com.sun.enterprise.config.serverbeans.Engine; +import com.sun.enterprise.config.serverbeans.Module; +import com.sun.enterprise.config.serverbeans.Server; +import com.sun.enterprise.config.serverbeans.SystemApplications; +import com.sun.enterprise.v3.server.ApplicationLoaderService; +import fish.payara.appserver.fang.service.adapter.PayaraFangAdapter; +import fish.payara.appserver.fang.service.adapter.PayaraFangAdapterState; +import java.beans.PropertyVetoException; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.internal.data.ApplicationInfo; +import org.glassfish.internal.data.ApplicationRegistry; +import org.glassfish.server.ServerEnvironmentImpl; +import org.jvnet.hk2.config.ConfigBeanProxy; +import org.jvnet.hk2.config.ConfigCode; +import org.jvnet.hk2.config.ConfigSupport; +import org.jvnet.hk2.config.TransactionFailure; + +/** + * Loader class for the Payara Fang application. Handles registering and actual loading of the application. + * @author Andrew Pielage + */ +public class PayaraFangLoader extends Thread { + private final Domain domain; + private final ServerEnvironmentImpl serverEnv; + private final String contextRoot; + private String applicationName; + private final PayaraFangAdapter payaraFangAdapter; + private final ServiceLocator habitat; + private static final Logger LOGGER = Logger.getLogger(PayaraFangLoader.class.getName()); + private final List vss; + private final boolean dynamicStart; + + PayaraFangLoader(PayaraFangAdapter payaraFangAdapter, ServiceLocator habitat, Domain domain, + ServerEnvironmentImpl serverEnv, String contextRoot, String applicationName, List vss) { + this.payaraFangAdapter = payaraFangAdapter; + this.habitat = habitat; + this.domain = domain; + this.serverEnv = serverEnv; + this.contextRoot = contextRoot; + this.applicationName = applicationName; + this.vss = vss; + this.dynamicStart = false; + } + + PayaraFangLoader(PayaraFangAdapter payaraFangAdapter, ServiceLocator habitat, Domain domain, + ServerEnvironmentImpl serverEnv, String contextRoot, String applicationName, List vss, + boolean dynamicStart) { + this.payaraFangAdapter = payaraFangAdapter; + this.habitat = habitat; + this.domain = domain; + this.serverEnv = serverEnv; + this.contextRoot = contextRoot; + this.applicationName = applicationName; + this.vss = vss; + this.dynamicStart = dynamicStart; + } + + @Override + public void run() { + try { + // Check if we've started the service dynamically, and so whether or not to override the adapter's config + if (dynamicStart) { + if (payaraFangAdapter.appExistsInConfig(contextRoot)) { + // Check if we need to reconfigure system app to match the overriding config + if (!payaraFangAdapter.isAppRegistered(contextRoot)) { + registerApplication(); + } else { + // Since we're starting dynamically, assume that we need to reconfigure + reconfigureSystemApplication(); + } + } else { + // If the app simply doesn't exist, create one and register it for this instance + createAndRegisterApplication(); + } + } else { + // Check if the application already exists + if (payaraFangAdapter.appExistsInConfig()) { + // Check if the app is actually registered to this instance + if (!payaraFangAdapter.isAppRegistered()) { + // We hit here if the app exists, but hasn't been registered to this instance yet + registerApplication(); + } else if (!contextRoot.equals(payaraFangAdapter.getSystemApplicationConfig().getContextRoot())) { + // We hit here if there is a system application already created and registered to this instance, + // but we've changed the context root and so need to reconfigure the system app + reconfigureSystemApplication(); + } + } else { + // If the app simply doesn't exist, create one and register it for this instance + createAndRegisterApplication(); + } + } + + loadApplication(); + } catch (Exception ex) { + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); + LOGGER.log(Level.WARNING, "Problem while attempting to register or load Payara Fang!", ex); + } + } + + /** + * Create the system application entry and register the application + * @throws Exception + */ + private void createAndRegisterApplication() throws Exception { + // Update the adapter state + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.REGISTERING); + LOGGER.log(Level.FINE, "Registering the Payara Fang Application..."); + + // Create the system application entry and application-ref in the config + ConfigCode code = new ConfigCode() { + @Override + public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, TransactionFailure { + // Create the system application + SystemApplications systemApplications = (SystemApplications) proxies[0]; + Application application = systemApplications.createChild(Application.class); + + // Check if the application name is valid, generating a new one if it isn't + checkAndResolveApplicationName(systemApplications); + + systemApplications.getModules().add(application); + application.setName(applicationName); + application.setEnabled(Boolean.TRUE.toString()); + application.setObjectType("system-admin"); + application.setDirectoryDeployed("true"); + application.setContextRoot(contextRoot); + + try { + application.setLocation("${com.sun.aas.installRootURI}/lib/install/applications/" + + PayaraFangService.DEFAULT_FANG_APP_NAME); + } catch (Exception me) { + throw new RuntimeException(me); + } + + // Set the engine types + Module singleModule = application.createChild(Module.class); + application.getModule().add(singleModule); + singleModule.setName(applicationName); + Engine webEngine = singleModule.createChild(Engine.class); + webEngine.setSniffer("web"); + Engine weldEngine = singleModule.createChild(Engine.class); + weldEngine.setSniffer("weld"); + Engine securityEngine = singleModule.createChild(Engine.class); + securityEngine.setSniffer("security"); + singleModule.getEngines().add(webEngine); + singleModule.getEngines().add(weldEngine); + singleModule.getEngines().add(securityEngine); + + // Create the application-ref + Server s = (Server) proxies[1]; + List arefs = s.getApplicationRef(); + ApplicationRef aref = s.createChild(ApplicationRef.class); + aref.setRef(application.getName()); + aref.setEnabled(Boolean.TRUE.toString()); + aref.setVirtualServers(getVirtualServerListAsString()); + arefs.add(aref); + + return true; + } + }; + + Server server = domain.getServerNamed(serverEnv.getInstanceName()); + ConfigSupport.apply(code, domain.getSystemApplications(), server); + + // Update the adapter state + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); + LOGGER.log(Level.FINE, "Payara Fang Registered."); + } + + private void registerApplication() throws Exception { + // Update the adapter state + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.REGISTERING); + LOGGER.log(Level.FINE, "Registering the Payara Fang Application..."); + + // Create the application-ref entry in the domain.xml + ConfigCode code = new ConfigCode() { + @Override + public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, TransactionFailure { + // Get the system application config + SystemApplications systemApplications = (SystemApplications) proxies[0]; + Application application = null; + for (Application systemApplication : systemApplications.getApplications()) { + if (systemApplication.getName().equals(applicationName)) { + application = systemApplication; + break; + } + } + + if (application == null) { + throw new IllegalStateException("Payara Fang has no system app entry!"); + } + + // Create the application-ref + Server s = (Server) proxies[1]; + List arefs = s.getApplicationRef(); + ApplicationRef aref = s.createChild(ApplicationRef.class); + aref.setRef(application.getName()); + aref.setEnabled(Boolean.TRUE.toString()); + aref.setVirtualServers(getVirtualServerListAsString()); + arefs.add(aref); + return true; + } + }; + + Server server = domain.getServerNamed(serverEnv.getInstanceName()); + ConfigSupport.apply(code, domain.getSystemApplications(), server); + + // Update the adapter state + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); + LOGGER.log(Level.FINE, "Payara Fang Registered."); + } + + private String getVirtualServerListAsString() { + if (vss == null) { + return ""; + } + + String virtualServers = Arrays.toString(vss.toArray(new String[vss.size()])); + + // Standard JDK implemetation always returns this enclosed in [], which we don't want + virtualServers = virtualServers.substring(1, virtualServers.length() - 1); + + return virtualServers; + } + + /** + * Loads the application + */ + private void loadApplication() { + ApplicationRegistry appRegistry = habitat.getService(ApplicationRegistry.class); + ApplicationInfo appInfo = appRegistry.get(applicationName); + if (appInfo != null && appInfo.isLoaded()) { + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADED); + return; + } + + Application config = null; + if (dynamicStart) { + config = payaraFangAdapter.getSystemApplicationConfig(contextRoot); + } else { + config = payaraFangAdapter.getSystemApplicationConfig(); + } + + + if (config == null) { + throw new IllegalStateException("Payara Fang has no system app entry!"); + } + + // Update adapter state + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADING); + + // Load the Payara Fang Application + String instanceName = serverEnv.getInstanceName(); + ApplicationRef ref = domain.getApplicationRefInServer(instanceName, applicationName); + habitat.getService(ApplicationLoaderService.class).processApplication(config, ref); + + // Update adapter state and mark as registered + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADED); + payaraFangAdapter.setAppRegistered(true); + } + + private void checkAndResolveApplicationName(SystemApplications systemApplications) { + // Check if the application name is not empty + if (applicationName == null || applicationName.equals("")) { + LOGGER.log(Level.INFO, "No or incorrect application name detected for Payara Fang: reverting to default"); + applicationName = PayaraFangService.DEFAULT_FANG_APP_NAME; + } + + // Loop through the system applications + boolean validApplicationNameFound = false; + int applicationNameSuffix = 1; + while (!validApplicationNameFound) { + // Check if the current application name is in use + validApplicationNameFound = isApplicationNameValid(systemApplications); + + if (!validApplicationNameFound) { + // If the name isn't valid, append a number to it and try again + applicationName = applicationName + "-" + applicationNameSuffix; + applicationNameSuffix++; + } + } + + } + + private boolean isApplicationNameValid(SystemApplications systemApplications) { + boolean validApplicationNameFound = true; + + // Search through the system application names to check if there are any apps with the same name + for (Application systemApplication : systemApplications.getApplications()) { + if (systemApplication.getName().equals(applicationName)) { + // We've found an application with the same name, that means we can't use this one + validApplicationNameFound = false; + break; + } + } + + return validApplicationNameFound; + } + + private void reconfigureSystemApplication() throws Exception { + Application systemApplication = payaraFangAdapter.getSystemApplicationConfig(); + + // Update the adapter state + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.RECONFIGURING); + LOGGER.log(Level.FINE, "Reconfiguring the Payara Fang Application..."); + + // Reconfigure the system-application entry in the domain.xml + ConfigCode code = new ConfigCode() { + @Override + public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, TransactionFailure { + Application systemApplication = (Application) proxies[0]; + systemApplication.setContextRoot(contextRoot); + + return true; + } + }; + + ConfigSupport.apply(code, systemApplication); + + // Update the adapter state + payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); + LOGGER.log(Level.FINE, "Payara Fang Reconfigured."); + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java new file mode 100644 index 00000000000..d47bd3cdc61 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java @@ -0,0 +1,196 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package fish.payara.appserver.fang.service; + +import com.sun.enterprise.config.serverbeans.Config; +import com.sun.enterprise.config.serverbeans.Domain; +import fish.payara.appserver.fang.service.adapter.PayaraFangAdapter; +import fish.payara.appserver.fang.service.adapter.PayaraFangEndpointDecider; +import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; +import java.beans.PropertyChangeEvent; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.inject.Named; +import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.hk2.runlevel.RunLevel; +import org.glassfish.internal.api.PostStartupRunLevel; +import org.glassfish.server.ServerEnvironmentImpl; +import org.jvnet.hk2.annotations.Optional; +import org.jvnet.hk2.annotations.Service; +import org.jvnet.hk2.config.ConfigBeanProxy; +import org.jvnet.hk2.config.ConfigListener; +import org.jvnet.hk2.config.UnprocessedChangeEvent; +import org.jvnet.hk2.config.UnprocessedChangeEvents; + +/** + * The core service for the Payara Fang application. Handles starting and reconfiguration of the application. + * @author Andrew Pielage + */ +@Service(name = "payara-fang") +@RunLevel(PostStartupRunLevel.VAL) +public class PayaraFangService implements ConfigListener { + + public static final String DEFAULT_FANG_APP_NAME = "__fang"; + private boolean startAttempted = false; + private String contextRoot; + + @Inject + @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) + @Optional + private PayaraFangConfiguration payaraFangConfiguration; + + @Inject + private PayaraFangAdapter payaraFangAdapter; + + @Inject + Domain domain; + + @Inject + ServerEnvironmentImpl serverEnv; + + @Inject + ServiceLocator habitat; + + @PostConstruct + private void postConstruct() { + contextRoot = payaraFangAdapter.getContextRoot(); + payaraFangConfiguration = habitat.getService(PayaraFangConfiguration.class); + + if (payaraFangConfiguration.getEnabled().equals("true")) { + loadApplication(); + } + } + + private void loadApplication() { + startAttempted = true; + try { + new PayaraFangLoader(payaraFangAdapter, habitat, domain, serverEnv, + contextRoot, payaraFangConfiguration.getApplicationName(), + payaraFangAdapter.getVirtualServers()).start(); + } catch (Exception ex) { + throw new RuntimeException("Unable to load Payara Fang!", ex); + } + } + + private void loadApplication(boolean dynamicStart) { + startAttempted = true; + try { + new PayaraFangLoader(payaraFangAdapter, habitat, domain, serverEnv, + contextRoot, payaraFangConfiguration.getApplicationName(), + payaraFangAdapter.getVirtualServers(), dynamicStart).start(); + } catch (Exception ex) { + throw new RuntimeException("Unable to load Payara Fang!", ex); + } + } + + @Override + public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvents) { + List unprocessedChanges = new ArrayList<>(); + boolean dynamicStart = false; + + for (PropertyChangeEvent propertyChangeEvent : propertyChangeEvents) { + // Check that the property change event is for us. + if (propertyChangeEvent.getSource().toString().equals("GlassFishConfigBean." + + PayaraFangConfiguration.class.getName()) && isCurrentInstanceMatchTarget(propertyChangeEvent)) { + // Check if the property has actually changed + if (!propertyChangeEvent.getOldValue().equals(propertyChangeEvent.getNewValue())) { + // If the application hasn't attempted to start yet + if (!startAttempted) { + // We can only get here if enabled was false at server start, so in the case of the enabled + // property, we don't need to compare it to the current value - it can only be true + if (propertyChangeEvent.getPropertyName().equals("enabled")) { + // Flag that we want to dynamically start Payara Fang + dynamicStart = true; + } else if (propertyChangeEvent.getPropertyName().equals("context-root")) { + // If we haven't attempted to start the app yet, grab the new context root + Config serverConfig = domain.getServerNamed(serverEnv.getInstanceName()).getConfig(); + PayaraFangEndpointDecider endpointDecider = new PayaraFangEndpointDecider(serverConfig, + payaraFangConfiguration); + contextRoot = endpointDecider.getContextRoot(); + } + } else { + // If a startup has been attempted, just throw an unprocessed change event as we need to restart + unprocessedChanges.add(new UnprocessedChangeEvent(propertyChangeEvent, + "Payara Fang redeploy required")); + } + } + } + } + + // This should only be true if Payara Fang was not enabled at startup, and we've just enabled the service + if (dynamicStart) { + loadApplication(true); + } + + // If we need to restart, throw an unprocessed change event + if (unprocessedChanges.isEmpty()) { + return null; + } else { + return new UnprocessedChangeEvents(unprocessedChanges); + } + } + + private boolean isCurrentInstanceMatchTarget(PropertyChangeEvent propertyChangeEvent) { + // If we are an instance then the change will apply to us as it has been + // replicated directly to us by the DAS + if (serverEnv.isInstance()) { + return true; + } + + ConfigBeanProxy proxy = (ConfigBeanProxy) propertyChangeEvent.getSource(); + + // Find the config parent + while (proxy != null && !(proxy instanceof Config)) { + proxy = proxy.getParent(); + } + + if (proxy != null) { + // We have found a config node at the root + // If the root config is the das config return true + return ((Config)proxy).isDas(); + } + + return false; + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java new file mode 100644 index 00000000000..ea31cba8708 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java @@ -0,0 +1,446 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package fish.payara.appserver.fang.service.adapter; + +import com.sun.appserv.server.util.Version; +import com.sun.enterprise.config.serverbeans.Application; +import com.sun.enterprise.config.serverbeans.Config; +import com.sun.enterprise.config.serverbeans.Domain; +import com.sun.enterprise.config.serverbeans.SystemApplications; +import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.inject.Named; +import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.api.container.Adapter; +import org.glassfish.api.event.Events; +import org.glassfish.grizzly.http.Method; +import org.glassfish.grizzly.http.io.OutputBuffer; +import org.glassfish.grizzly.http.server.HttpHandler; +import org.glassfish.grizzly.http.server.Request; +import org.glassfish.grizzly.http.server.Response; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.internal.data.ApplicationRegistry; +import org.glassfish.server.ServerEnvironmentImpl; +import org.jvnet.hk2.annotations.Optional; +import org.jvnet.hk2.annotations.Service; + +/** + * The adapter class for the Payara Fang application. + * @author Andrew Pielage + */ +@Service +public final class PayaraFangAdapter extends HttpHandler implements Adapter { + private PayaraFangAdapterState stateMsg = PayaraFangAdapterState.UNINITIALISED; + private boolean isRegistered = false; + private boolean appRegistered = false; + private ResourceBundle bundle; + private final Method[] allowedHttpMethods = {Method.GET, Method.POST, Method.HEAD, Method.DELETE, Method.PUT}; + + private static PayaraFangEndpointDecider endpointDecider; + + @Inject + ServerEnvironmentImpl env; + + @Inject + ApplicationRegistry appRegistry; + + @Inject + Domain domain; + + @Inject + ServiceLocator habitat; + + @Inject + Events events; + + @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) + Config serverConfig; + + @Inject + @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) + @Optional + PayaraFangConfiguration fangServiceConfiguration; + + private final static Logger logger = Logger.getLogger(PayaraFangAdapter.class.getName()); + private final static String RESOURCE_PACKAGE = "fish/payara/appserver/fang/adapter"; + private final CountDownLatch latch = new CountDownLatch(1); + + @PostConstruct + public void postConstruct() { + fangServiceConfiguration = habitat.getService(PayaraFangConfiguration.class); + init(); + } + + private void init() { + try { + endpointDecider = new PayaraFangEndpointDecider(serverConfig, fangServiceConfiguration); + } catch (Exception ex) { + logger.log(Level.INFO, "Payara Fang Console cannot initialise", ex); + } + + // If the app exists in the domain.xml AND it's registered to this instance + if (appExistsInConfig() && (domain.getSystemApplicationReferencedFrom(env.getInstanceName(), + fangServiceConfiguration.getApplicationName()) != null)) { + setStateMsg(PayaraFangAdapterState.NOT_LOADED); + setAppRegistered(true); + } else { + setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); + } + } + + public boolean appExistsInConfig() { + return (getSystemApplicationConfig() != null); + } + + public boolean appExistsInConfig(String contextRoot) { + return (getSystemApplicationConfig(contextRoot) != null); + } + + /** + * Gets the application config for the system application with the matching name or context root (in that order). + * @return The application config, or null if there is no matching application + */ + public Application getSystemApplicationConfig() { + // First, check if there is an app registered for this server with the given application name + Application application = domain.getSystemApplicationReferencedFrom(env.getInstanceName(), + fangServiceConfiguration.getApplicationName()); + + // If the app hasn't been registered to the instance yet, the previous check will return null, so check for one + // with a matching context root instead (as these are also unique and saves us creating an extra app entry) + if (application == null) { + application = getApplicationWithMatchingContextRoot(getContextRoot()); + } + + return application; + } + + /** + * Gets the application config for the system application with the matching context root. This method is used over the + * overloaded method if you want to skip trying to get the application config based on the application name, such as + * if you've reconfigured the application. + * @param contextRoot The context root of the application + * @return The application config, or null if there is no matching application. + */ + public Application getSystemApplicationConfig(String contextRoot) { + Application application = getApplicationWithMatchingContextRoot(contextRoot); + + return application; + } + + /** + * Helper method that searches through all system applications for one with a matching context root. + * @param contextRoot The context root fo the application. + * @return The application config, or null if there are no applications with a matching context root. + */ + private Application getApplicationWithMatchingContextRoot(String contextRoot) { + Application application = null; + + SystemApplications systemApplications = domain.getSystemApplications(); + for (Application systemApplication : systemApplications.getApplications()) { + if (systemApplication.getContextRoot().equals(contextRoot)) { + application = systemApplication; + break; + } + } + + return application; + } + + public PayaraFangAdapterState getStateMsg() { + return stateMsg; + } + + public void setStateMsg(PayaraFangAdapterState msg) { + stateMsg = msg; + logger.log(Level.FINE, msg.toString()); + } + + @Override + public void service(Request request, Response response) throws Exception { + bundle = getResourceBundle(request.getLocale()); + Method method = request.getMethod(); + + if (!checkHttpMethodAllowed(method)) { + response.setStatus(java.net.HttpURLConnection.HTTP_BAD_METHOD, + method.getMethodString() + " " + bundle.getString("http.bad.method")); + response.setHeader("Allow", getAllowedHttpMethodsAsString()); + return; + } + + try { + if (!latch.await(100L, TimeUnit.SECONDS)) { + logger.log(Level.SEVERE, "Timed out processing a Payara Fang request"); + return; + } + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, "Cannot process Payara Fang request"); + return; + } + + logRequest(request); + + if (isResourceRequest(request)) { + try { + handleResourceRequest(request, response); + } catch (IOException ioe) { + if (logger.isLoggable(Level.SEVERE)) { + logger.log(Level.SEVERE, "Unable to serve resource: {0}. Cause: {1}", + new Object[]{request.getRequestURI(), ioe.toString()}); + } + + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, ioe.toString(), ioe); + } + } + + return; + } + + response.setContentType("text/html; charset=UTF-8"); + + String serverVersion = Version.getFullVersion(); + + if ("/testifbackendisready.html".equals(request.getRequestURI())) { + // Replace state token + String status = getStateMsg().getI18NKey(); + try { + // Try to get a localized version of this key + status = bundle.getString(status); + } catch (MissingResourceException ex) { + // Use the non-localized String version of the status + status = getStateMsg().toString(); + } + + String wkey = PayaraFangAdapterState.WELCOME_TO.getI18NKey(); + + try { + // Try to get a localized version of this key + serverVersion = bundle.getString(wkey) + " " + serverVersion + "."; + } catch (MissingResourceException ex) { + // Use the non-localized String version of the status + serverVersion = PayaraFangAdapterState.WELCOME_TO.toString() + " " + serverVersion + "."; + } + + status += "\n" + serverVersion; + + try { + OutputBuffer ob = getOutputBuffer(response); + byte[] bytes = (":::" + status).getBytes("UTF-8"); + response.setContentLength(bytes.length); + ob.write(bytes, 0, bytes.length); + ob.flush(); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Unable to serve resource: {0}. Cause: {1}", ex); + } + } + // TODO: Handle application not being there + } + + private ResourceBundle getResourceBundle(Locale locale) { + return ResourceBundle.getBundle("com.sun.enterprise.v3.admin.adapter.LocalStrings", locale); + } + + private boolean checkHttpMethodAllowed(Method method) { + for (Method allowedMethod : allowedHttpMethods) { + if (allowedMethod.equals(method)) { + return true; + } + } + return false; + } + + private String getAllowedHttpMethodsAsString() { + StringBuilder sb = new StringBuilder(allowedHttpMethods[0].getMethodString()); + for (int i = 1; i < allowedHttpMethods.length; i++) { + sb.append(", ").append(allowedHttpMethods[i].getMethodString()); + } + + return sb.toString(); + } + + private void logRequest(Request request) { + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "PayaraFangAdapter's STATE IS: {0}", getStateMsg()); + logger.log(Level.FINE, "Current Thread: {0}", Thread.currentThread().getName()); + + for (final String name : request.getParameterNames()) { + final String values = Arrays.toString(request.getParameterValues(name)); + logger.log(Level.FINE, "Parameter name: {0} values: {1}", new Object[]{name, values}); + } + } + } + + private boolean isResourceRequest(Request request) { + return (getContentType(request.getRequestURI()) != null); + } + + private String getContentType(String resource) { + if (resource == null || resource.length() == 0) { + return null; + } + + if (resource.endsWith(".gif")) { + return "image/gif"; + } else if (resource.endsWith(".jpg")) { + return "image/jpeg"; + } else { + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "Unhandled content-type: {0}", resource); + } + + return null; + } + } + + private void handleResourceRequest(Request request, Response response) throws IOException { + String resourcePath = RESOURCE_PACKAGE + request.getRequestURI(); + + ClassLoader loader = PayaraFangAdapter.class.getClassLoader(); + + try (InputStream inputStream = loader.getResourceAsStream(resourcePath)) { + if (inputStream == null) { + logger.log(Level.WARNING, "Resource not found: {0}", resourcePath); + return; + } + + byte[] buffer = new byte[512]; + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(512); + + for (int i = inputStream.read(buffer); i != -1; i = inputStream.read(buffer)) { + byteArrayOutputStream.write(buffer, 0, i); + } + + String contentType = getContentType(resourcePath); + + if (contentType != null) { + response.setContentType(contentType); + } + + response.setContentLength(byteArrayOutputStream.size()); + OutputStream outputStream = response.getOutputStream(); + byteArrayOutputStream.writeTo(outputStream); + outputStream.flush(); + } + } + + private OutputBuffer getOutputBuffer(Response response) { + response.setStatus(202); + response.setContentType("text/html"); + response.setCharacterEncoding("UTF-8"); + return response.getOutputBuffer(); + } + + @Override + public HttpHandler getHttpService() { + return this; + } + + @Override + public String getContextRoot() { + return endpointDecider.getContextRoot(); + } + + @Override + public int getListenPort() { + return endpointDecider.getListenPort(); + } + + @Override + public InetAddress getListenAddress() { + return endpointDecider.getListenAddress(); + } + + @Override + public List getVirtualServers() { + return endpointDecider.getHosts(); + } + + @Override + public boolean isRegistered() { + return isRegistered; + } + + @Override + public void setRegistered(boolean isRegistered) { + this.isRegistered = isRegistered; + } + + public boolean isAppRegistered() { + return appRegistered; + } + + public void setAppRegistered(boolean appRegistered) { + this.appRegistered = true; + } + + /** + * Overloaded method that checks if an application with the provided context root has been registered to this instance. + * @param contextRoot The context root to match. + * @return True if an application has been registered to this instance. + */ + public boolean isAppRegistered(String contextRoot) { + boolean registered = false; + Application application = getSystemApplicationConfig(contextRoot); + + // Check if we've found an application with a matching context root, and that it's registered to this instance + if (application != null && (domain.getSystemApplicationReferencedFrom(env.getInstanceName(), + application.getName()) != null)) { + registered = true; + } + + return registered; + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java new file mode 100644 index 00000000000..eb5660ae5d8 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java @@ -0,0 +1,76 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package fish.payara.appserver.fang.service.adapter; + +/** + * + * @author Andrew Pielage + */ +public enum PayaraFangAdapterState { + NOT_LOADED("state.notLoaded", "Payara Fang is registered in the config but not loaded yet"), + LOADING("state.loading", "Payara Fang is loading"), + LOADED("state.loaded", "Payara Fang is loaded"), + UNINITIALISED("state.uninitialised", "Payara Fang has not been initialised yet"), + REGISTERING("state.registering", "Payara Fang is being registered as a system application"), + NOT_REGISTERED("state.notRegistered", "Payara Fang is not registered in the config"), + RECONFIGURING("state.reconfiguring", "Payara Fang system-application entry is being reconfigured"), + WELCOME_TO("status.welcometo", "Welcome to "); + + private final String desc; + private final String i18nKey; + + private PayaraFangAdapterState(String i18nKey, String desc) { + this.i18nKey = i18nKey; + this.desc = desc; + } + + /** + * This is the key that should be used to retrieve the localised message from a properties file. + */ + public String getI18NKey() { + return i18nKey; + } + + @Override + public String toString() { + return (desc); + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java new file mode 100644 index 00000000000..e1f7a7b87ff --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java @@ -0,0 +1,160 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package fish.payara.appserver.fang.service.adapter; + +import com.sun.enterprise.config.serverbeans.Config; +import com.sun.enterprise.config.serverbeans.ServerTags; +import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.logging.Logger; +import javax.inject.Inject; +import org.glassfish.grizzly.config.dom.NetworkListener; +import org.glassfish.grizzly.config.dom.ThreadPool; +import org.glassfish.hk2.api.ServiceLocator; + +/** + * This class encapsulates the process of resolving the actual endpoint of the Payara Fang application. + * @author Andrew Pielage + */ +public class PayaraFangEndpointDecider { + private String contextRoot; + + private int port; + private InetAddress address; + private int maxThreadPoolSize = 5; + private Config config; + private static final Logger logger = Logger.getLogger(PayaraFangEndpointDecider.class.getName()); + private List hosts; + private PayaraFangConfiguration fangServiceConfiguration; + + private final static String DEFAULT_CONTEXT_ROOT = "/fang"; + + public static final int DEFAULT_ADMIN_PORT = 4848; + + @Inject + ServiceLocator habitat; + + public PayaraFangEndpointDecider(Config config, PayaraFangConfiguration fangServiceConfiguration) { + if (config == null || logger == null) + throw new IllegalArgumentException("config or logger can't be null"); + this.config = config; + this.fangServiceConfiguration = fangServiceConfiguration; + setValues(); + } + + public int getListenPort() { + return port; + } + + public InetAddress getListenAddress() { + return address; + } + + public int getMaxThreadPoolSize() { + return maxThreadPoolSize; + } + + public String getContextRoot() { + return contextRoot; + } + + private void setValues() { + NetworkListener networkListener = config.getAdminListener(); + ThreadPool threadPool = networkListener.findThreadPool(); + + // Set Thread pool size + if (threadPool != null) { + try { + maxThreadPoolSize = Integer.parseInt(threadPool.getMaxThreadPoolSize()); + } catch (NumberFormatException ex) { + + } + } + + String defaultVirtualServer = networkListener.findHttpProtocol().getHttp().getDefaultVirtualServer(); + hosts = Collections.unmodifiableList(Arrays.asList(defaultVirtualServer)); + + // Set network address + try { + address = InetAddress.getByName(networkListener.getAddress()); + } catch (UnknownHostException e) { + throw new IllegalStateException(e); + } + + // Set the context root and port number + if (ServerTags.ADMIN_LISTENER_ID.equals(networkListener.getName())) { + // Get the context root from the Payara Fang service + if (fangServiceConfiguration == null) { + contextRoot = DEFAULT_CONTEXT_ROOT; + } else { + contextRoot = fangServiceConfiguration.getContextRoot(); + } + + try { + port = Integer.parseInt(networkListener.getPort()); + } catch(NumberFormatException ne) { + port = DEFAULT_ADMIN_PORT; + } + } + else { + try { + port = Integer.parseInt(networkListener.getPort()); + } catch(NumberFormatException ne) { + port = DEFAULT_ADMIN_PORT; + } + + // Get the context root from the Payara Fang service + if (fangServiceConfiguration == null) { + contextRoot = DEFAULT_CONTEXT_ROOT; + } else { + contextRoot = fangServiceConfiguration.getContextRoot(); + } + } + } + + public List getHosts() { + return hosts; + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java new file mode 100644 index 00000000000..6c3ad7e3854 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java @@ -0,0 +1,137 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package fish.payara.appserver.fang.service.admin; + +import com.sun.enterprise.config.serverbeans.Config; +import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; +import java.beans.PropertyVetoException; +import java.util.logging.Logger; +import javax.inject.Inject; +import org.glassfish.api.Param; +import org.glassfish.api.admin.AdminCommand; +import org.glassfish.api.admin.AdminCommandContext; +import org.glassfish.api.admin.ExecuteOn; +import org.glassfish.api.admin.RestEndpoint; +import org.glassfish.api.admin.RestEndpoints; +import org.glassfish.api.admin.RuntimeType; +import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.hk2.api.PerLookup; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.internal.api.Target; +import org.jvnet.hk2.annotations.Service; +import org.jvnet.hk2.config.ConfigSupport; +import org.jvnet.hk2.config.SingleConfigCode; +import org.jvnet.hk2.config.TransactionFailure; + +/** + * + * @author Andrew Pielage + */ +@Service(name = "set-payara-fang-configuration") +@PerLookup +@ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE}) +@RestEndpoints({ + @RestEndpoint(configBean = PayaraFangConfiguration.class, + opType = RestEndpoint.OpType.POST, + path = "set-payara-fang-configuration", + description = "Sets the Payara Fang Configuration") +}) +public class SetPayaraFangConfigurationCommand implements AdminCommand { + + private final static Logger LOGGER = Logger.getLogger(SetPayaraFangConfigurationCommand.class.getName()); + + @Param(optional = true, defaultValue = "server-config") + String target; + + @Param(optional = true) + Boolean enabled; + + @Param(optional = true, alias = "contextroot") + String contextRoot; + + @Param(optional = true) + String name; + + @Param(optional = true, alias = "securityenabled") + Boolean securityEnabled; + + @Inject + private Target targetUtil; + + @Inject + ServiceLocator habitat; + + @Inject + ServerEnvironment serverEnv; + + @Override + public void execute(AdminCommandContext context) { + Config targetConfig = targetUtil.getConfig(target); + PayaraFangConfiguration fangConfiguration = targetConfig.getExtensionByType(PayaraFangConfiguration.class); + + try { + ConfigSupport.apply(new SingleConfigCode(){ + @Override + public Object run(PayaraFangConfiguration configProxy) throws PropertyVetoException { + if (enabled != null) { + configProxy.setEnabled(enabled.toString()); + } + + if (contextRoot != null) { + configProxy.setContextRoot(contextRoot); + } + + if (name != null) { + configProxy.setApplicationName(name); + } + + if (securityEnabled != null) { + configProxy.setSecurityEnabled(securityEnabled.toString()); + } + + return null; + } + }, fangConfiguration); + } catch (TransactionFailure ex) { + context.getActionReport().failure(LOGGER, "Failed to update Payara Fang configuration", ex); + } + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java new file mode 100644 index 00000000000..5e772c22c01 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java @@ -0,0 +1,76 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package fish.payara.appserver.fang.service.configuration; + +import java.beans.PropertyVetoException; +import org.glassfish.api.admin.config.ConfigExtension; +import org.jvnet.hk2.config.Attribute; +import org.jvnet.hk2.config.ConfigBeanProxy; +import org.jvnet.hk2.config.Configured; + +/** + * + * @author Andrew Pielage + */ +@Configured +public interface PayaraFangConfiguration extends ConfigBeanProxy, ConfigExtension { + + /** + * Checks if Payara Fang is enabled or not + * @return true if enabled + */ + @Attribute(defaultValue = "false", dataType = Boolean.class) + String getEnabled(); + void setEnabled(String value) throws PropertyVetoException; + + @Attribute(defaultValue = "/fang") + String getContextRoot(); + void setContextRoot(String contextRoot) throws PropertyVetoException; + + @Attribute(defaultValue = "__fang") + String getApplicationName(); + void setApplicationName(String name) throws PropertyVetoException; + + @Attribute(defaultValue = "false", dataType = Boolean.class) + String getSecurityEnabled(); + void setSecurityEnabled(String value) throws PropertyVetoException; + +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java new file mode 100644 index 00000000000..066e7513124 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java @@ -0,0 +1,205 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.appserver.fang.service.security; + +import com.sun.enterprise.security.SecurityServicesUtil; +import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; +import java.io.IOException; +import java.security.Principal; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.message.AuthException; +import javax.security.auth.message.AuthStatus; +import javax.security.auth.message.MessageInfo; +import javax.security.auth.message.MessagePolicy; +import javax.security.auth.message.callback.CallerPrincipalCallback; +import javax.security.auth.message.callback.PasswordValidationCallback; +import javax.security.auth.message.module.ServerAuthModule; +import javax.servlet.RequestDispatcher; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import org.glassfish.hk2.api.ServiceLocator; + +/** + * + * @author Andrew Pielage + */ +public class FangAuthModule implements ServerAuthModule { + + private String contextRoot = null; + private CallbackHandler handler = null; + private boolean securityEnabled = false; + +// private static final String SAVED_SUBJECT = "Saved_Subject"; + private static final String ORIG_REQUEST_PATH = "origRequestPath"; + private static final String LOGIN_PAGE = "/login.xhtml"; +// private static final String ERROR_PAGE = "/error.xhtml"; +// private static final String RESPONSE_TYPE = "application/json"; +// private static final String USER_NAME = "userName"; + private static final Class[] SUPPORTED_MESSAGE_TYPES = new Class[] {HttpServletRequest.class, + HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) + throws AuthException { + this.handler = handler; + ServiceLocator habitat = SecurityServicesUtil.getInstance().getHabitat(); + PayaraFangConfiguration fangConfiguration = habitat.getService(PayaraFangConfiguration.class); + + contextRoot = fangConfiguration.getContextRoot(); + securityEnabled = Boolean.parseBoolean(fangConfiguration.getSecurityEnabled()); + } + + @Override + public Class[] getSupportedMessageTypes() { + return SUPPORTED_MESSAGE_TYPES; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) + throws AuthException { + if (securityEnabled) { + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + HttpSession session = request.getSession(); + + // Check if our session has already been authenticated + Principal userPrincipal = request.getUserPrincipal(); + if (userPrincipal != null) { + try { + handler.handle(new Callback[] { new CallerPrincipalCallback(clientSubject, userPrincipal) }); + + return AuthStatus.SUCCESS; + } catch (IOException | UnsupportedCallbackException ex) { + AuthException ae = new AuthException(); + ae.initCause(ex); + throw ae; + } + } + + // See if the username / password has been passed in... + String username = request.getParameter("j_username"); + String password = request.getParameter("j_password"); + if ((username == null) || (password == null) || !request.getMethod().equalsIgnoreCase("post")) { + // Not passed in, show the login page... + String origPath = request.getRequestURI(); + String queryString = request.getQueryString(); + + if ((queryString != null) && (!queryString.isEmpty())) { + origPath += "?" + queryString; + } + + session.setAttribute(ORIG_REQUEST_PATH, origPath); + RequestDispatcher rd = request.getRequestDispatcher(LOGIN_PAGE); + + try { + rd.forward(request, response); + } catch (Exception ex) { + AuthException authException = new AuthException(); + authException.initCause(ex); + throw authException; + } + + return AuthStatus.SEND_CONTINUE; + } + + // Authenticate the details + PasswordValidationCallback pvCallback = new PasswordValidationCallback(clientSubject, username, + password.toCharArray()); + + try { + handler.handle(new Callback[]{pvCallback}); + } catch (Exception ex) { + AuthException ae = new AuthException(); + ae.initCause(ex); + throw ae; + } + + // Register the session as authenticated + messageInfo.getMap().put("javax.servlet.http.registerSession", Boolean.TRUE.toString()); + + // Redirect to original path + try { + String origRequest = (String) session.getAttribute(ORIG_REQUEST_PATH); + + if ((origRequest == null)) { + origRequest = contextRoot; + } + + response.sendRedirect(response.encodeRedirectURL(origRequest)); + } catch (Exception ex) { + AuthException ae = new AuthException(); + ae.initCause(ex); + throw ae; + } + + // Continue... + return AuthStatus.SUCCESS; + } else { + Callback[] callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, "wibbles") }; + + try { + handler.handle(callbacks); + } catch (IOException | UnsupportedCallbackException ex) { + Logger.getLogger(FangAuthModule.class.getName()).log(Level.SEVERE, null, ex); + } + + return AuthStatus.SUCCESS; + } + } + + @Override + public AuthStatus secureResponse(MessageInfo messageInfo, Subject serviceSubject) throws AuthException { + return AuthStatus.SUCCESS; + } + + @Override + public void cleanSubject(MessageInfo messageInfo, Subject subject) throws AuthException { + if (subject != null) { + subject.getPrincipals().clear(); + } + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/README.md b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/README.md new file mode 100644 index 00000000000..37e1255253c --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/README.md @@ -0,0 +1,3 @@ +# Fang + +JMX and AMX Agent through REST interface. \ No newline at end of file diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/osgi.bundle b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/osgi.bundle new file mode 100644 index 00000000000..71295022bbb --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/osgi.bundle @@ -0,0 +1 @@ +-exportcontents: fish.payara.monitoring.fang; version=${project.version} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/pom.xml b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/pom.xml new file mode 100644 index 00000000000..63f280d8f7f --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/pom.xml @@ -0,0 +1,127 @@ + + + + 4.0.0 + + fish.payara.appserver.payara-fang + payara-fang-parent + 4.1.2.172-SNAPSHOT + + + payara-fang-war + war + Payara Fang War + 0.0.1-ALPHA + + + ${project.build.directory}/endorsed + UTF-8 + + + + + org.codehaus.jettison + jettison + jar + + + com.fasterxml.jackson.core + jackson-databind + jar + + + javax + javaee-web-api + 7.0 + provided + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.7 + 1.7 + + ${endorsed.dir} + + + + + org.apache.maven.plugins + maven-war-plugin + 2.3 + + false + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.6 + + + validate + + copy + + + ${endorsed.dir} + true + + + javax + javaee-endorsed-api + 7.0 + jar + + + + + + + + + diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangConfig.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangConfig.java new file mode 100644 index 00000000000..34201442917 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangConfig.java @@ -0,0 +1,68 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang; + +import java.util.HashSet; +import java.util.Set; +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +/** + * + * @author Fraser Savage + */ +// @HOLD - FANG-3: Implement Fang 'State' handler and resource. +@ApplicationPath("/rest") +public class FangConfig extends Application { + + @Override + public Set> getClasses() { + Set> resources = new HashSet<>(); + addRestResourceClasses(resources); + return resources; + } + + private void addRestResourceClasses(Set> resources) { + resources.add(fish.payara.monitoring.fang.resource + .FangStateResource.class); + resources.add(fish.payara.monitoring.fang.resource + .MBeanReadResource.class); + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangResponseToken.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangResponseToken.java new file mode 100644 index 00000000000..933c36a0467 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangResponseToken.java @@ -0,0 +1,110 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang; + +/** + * + * @author Fraser Savage + */ +public final class FangResponseToken { + + private static final String REQUEST_KEY = "request"; + private static final String VALUE_KEY = "value"; + private static final String STACKTRACE_KEY = "stacktrace"; + private static final String ERROR_TYPE_KEY = "error_type"; + private static final String ERROR_KEY = "error"; + private static final String TIMESTAMP_KEY = "timestamp"; + private static final String HTTP_STATUS_KEY = "status"; + + private static final String MBEAN_NAME_KEY = "mbean"; + private static final String ATTRIBUTE_NAME_KEY = "attribute"; + private static final String REQUEST_TYPE_KEY = "type"; + + private static final String READ_REQUEST_TOKEN = "read"; + private static final String VERSION_REQUEST_TOKEN = "version"; + + public static String getRequestKey() { + return REQUEST_KEY; + } + + public static String getValueKey() { + return VALUE_KEY; + } + + public static String getStacktraceKey() { + return STACKTRACE_KEY; + } + + public static String getErrorTypeKey() { + return ERROR_TYPE_KEY; + } + + public static String getErrorKey() { + return ERROR_KEY; + } + + public static String getTimestampKey() { + return TIMESTAMP_KEY; + } + + public static String getHttpStatusKey() { + return HTTP_STATUS_KEY; + } + + public static String getMbeanNameKey() { + return MBEAN_NAME_KEY; + } + + public static String getAttributeNameKey() { + return ATTRIBUTE_NAME_KEY; + } + + public static String getRequestTypeKey() { + return REQUEST_TYPE_KEY; + } + + public static String getReadRequestToken() { + return READ_REQUEST_TOKEN; + } + + public static String getVersionRequestToken() { + return VERSION_REQUEST_TOKEN; + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangState.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangState.java new file mode 100644 index 00000000000..8dcb646382a --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangState.java @@ -0,0 +1,82 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang; + +/** + * + * @author Fraser Savage + */ +// @HOLD - FANG-3: Implement Fang 'State' handler and resource. +public final class FangState { + + // Keys + private static final String AGENT_NAME_KEY = "agentName"; + private static final String AGENT_VERSION_KEY = "agentVersion"; + private static final String AGENT_TYPE_KEY = "agentType"; + + // Values + private static final String AGENT_NAME = "Fang"; + private static final String AGENT_VERSION = "0.0.1-Alpha"; + private static final String AGENT_TYPE = "war"; + + public static String getAgentNameKey() { + return AGENT_NAME_KEY; + } + + public static String getAgentVersionKey() { + return AGENT_VERSION_KEY; + } + + public static String getAgentTypeKey() { + return AGENT_TYPE_KEY; + } + + public static String getAgentName() { + return AGENT_NAME; + } + + public static String getAgentVersion() { + return AGENT_VERSION; + } + + public static String getAgentType() { + return AGENT_TYPE; + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/MBeanServerDelegate.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/MBeanServerDelegate.java new file mode 100644 index 00000000000..9d955f7c2a0 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/MBeanServerDelegate.java @@ -0,0 +1,116 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang; + +import static java.lang.management.ManagementFactory.getPlatformMBeanServer; +import javax.ejb.Startup; +import javax.inject.Singleton; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.ReflectionException; + +/** + * + * @author Fraser Savage + */ +@Startup +@Singleton +public class MBeanServerDelegate { + + /** + * The reference the delegate holds to the MBeanServer instance. + */ + private final MBeanServer platformServer; + + public MBeanServerDelegate() { + platformServer = getPlatformMBeanServer(); + } + + /** + * Returns an {@link MBeanInfo} object. + * The mbeanname argument must be a valid {@link ObjectName}. + * + * @param mbeanname The value of the MBean {@link ObjectName}. + * @return The instance of {@link MBeanInfo} returned for the mbeanname provided. + * @throws InstanceNotFoundException {@inheritDoc} + * @throws IntrospectionException {@inheritDoc} + * @throws ReflectionException {@inheritDoc} + * @throws MalformedObjectNameException {@inheritDoc} + */ + public MBeanInfo getMBean(String mbeanname) throws InstanceNotFoundException, IntrospectionException, ReflectionException, MalformedObjectNameException { + return platformServer.getMBeanInfo(getMBeanName(mbeanname)); + } + + /** + * Returns an MBean attribute in the form of an {@link Object}. + * The mbeanname argument must be a valid {@link ObjectName}. The attributename + * argument is a specifier relative to the mbeanname argument. + * + * @param mbeanname The value of the MBean {@link ObjectName} + * @param attributename The name of the attribute to get from the mbeanname on the {@link MBeanServer}. + * @return The {@link Object} representing the MBean attribute requested. + * @throws MBeanException {@inheritDoc} + * @throws AttributeNotFoundException {@inheriDoc} + * @throws InstanceNotFoundException {@inheritDoc} + * @throws ReflectionException {@inheritDoc} + * @throws MalformedObjectNameException {@inheritDoc} + */ + public Object getMBeanAttribute(String mbeanname, String attributename) throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException, MalformedObjectNameException { + return platformServer.getAttribute(getMBeanName(mbeanname), attributename); + } + + /** + * Returns an {@link ObjectName}. + * The mbeanname argument must be a valid {@link ObjectName}. + * + * @param mbeanname The value of the {@link ObjectName} to get an instance of. + * @return The {@link ObjectName} corresponding to the mbeanname argument. + * @throws MalformedObjectNameException {@inheritDoc} + */ + private ObjectName getMBeanName(String mbeanname) throws MalformedObjectNameException { + return new ObjectName(mbeanname); + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/FangStateHandler.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/FangStateHandler.java new file mode 100644 index 00000000000..1b78c6be254 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/FangStateHandler.java @@ -0,0 +1,88 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.handler; + +import fish.payara.monitoring.fang.FangResponseToken; +import fish.payara.monitoring.fang.FangState; +import fish.payara.monitoring.fang.MBeanServerDelegate; +import javax.inject.Singleton; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; + +/** + * + * @author Fraser Savage + */ +// @HOLD - FANG-3: Implement Fang 'State' handler and resource. +public class FangStateHandler extends VersionHandler { + + public FangStateHandler(@Singleton MBeanServerDelegate delegate) { + super(delegate); + } + + @Override + JSONObject getRequestObject() { + JSONObject requestObject = new JSONObject(); + try { + requestObject.put(FangResponseToken.getRequestTypeKey(), + FangResponseToken.getVersionRequestToken()); + return requestObject; + } catch (JSONException ex) { + return requestObject; + } + } + + @Override + JSONObject getValueObject() { + JSONObject valueObject = new JSONObject(); + try { + valueObject.put(FangState.getAgentNameKey(), + FangState.getAgentName()); + valueObject.put(FangState.getAgentVersionKey(), + FangState.getAgentVersion()); + valueObject.put(FangState.getAgentTypeKey(), + FangState.getAgentType()); + return valueObject; + } catch (JSONException ex) { + return valueObject; + } + } + +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/MBeanAttributeReadHandler.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/MBeanAttributeReadHandler.java new file mode 100644 index 00000000000..f55340102d9 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/MBeanAttributeReadHandler.java @@ -0,0 +1,109 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.handler; + +import fish.payara.monitoring.fang.FangResponseToken; +import fish.payara.monitoring.fang.MBeanServerDelegate; +import fish.payara.monitoring.fang.processor.ProcessorFactory; +import fish.payara.monitoring.fang.processor.TypeProcessor; +import javax.inject.Singleton; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.MalformedObjectNameException; +import javax.management.ReflectionException; +import javax.ws.rs.core.Response; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; + +/** + * + * @author Fraser Savage + */ +public class MBeanAttributeReadHandler extends ReadHandler { + + private final String mbeanname; + private final String attributename; + + /** + * Creates an instance of MBeanAttributeReadHandler, which handles MBean + * attribute read requests. + * + * @param delegate The {@link MBeanServerDelegate} to get information from. + * @param mbeanname The {@link ObjectName} of the MBean to get information from. + * @param attributename The name of the MBean attribute to get values for. + */ + public MBeanAttributeReadHandler(@Singleton MBeanServerDelegate delegate, + String mbeanname, String attributename) { + super(delegate); + this.mbeanname = mbeanname; + this.attributename = attributename; + } + + @Override + public JSONObject getRequestObject() { + JSONObject requestObject = new JSONObject(); + try { + requestObject.put(FangResponseToken.getMbeanNameKey(), + mbeanname); + requestObject.put(FangResponseToken.getAttributeNameKey(), + attributename); + requestObject.put(FangResponseToken.getRequestTypeKey(), + requesttype); + } catch (JSONException ex) { + super.setStatus(Response.Status.INTERNAL_SERVER_ERROR); + } + return requestObject; + } + + @Override + public Object getValueObject() throws JSONException { + try { + Object attribute = delegate + .getMBeanAttribute(mbeanname, attributename); + TypeProcessor processor = ProcessorFactory.getTypeProcessor(attribute); + + return processor.processObject(attribute); + } catch (InstanceNotFoundException | ReflectionException | MalformedObjectNameException | MBeanException | AttributeNotFoundException ex) { + super.setStatus(Response.Status.NOT_FOUND); + return getTraceObject(ex); + } + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/MBeanReadHandler.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/MBeanReadHandler.java new file mode 100644 index 00000000000..c96291dcab4 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/MBeanReadHandler.java @@ -0,0 +1,116 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.handler; + +import fish.payara.monitoring.fang.FangResponseToken; +import fish.payara.monitoring.fang.MBeanServerDelegate; +import javax.inject.Singleton; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MalformedObjectNameException; +import javax.management.ReflectionException; +import javax.ws.rs.core.Response; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; + +/** + * + * @author Fraser Savage + */ +public class MBeanReadHandler extends ReadHandler { + + private final String mbeanname; + + /** + * Creates an instance of MBeanReadHandler, which handles MBean + * read requests. + * + * @param delegate The {@link MBeanServerDelegate} to get information from. + * @param mbeanname The {@link ObjectName} of the MBean to get information from. + */ + public MBeanReadHandler(@Singleton MBeanServerDelegate delegate, + String mbeanname) { + super(delegate); + this.mbeanname = mbeanname; + } + + @Override + public JSONObject getRequestObject() { + JSONObject requestObject = new JSONObject(); + try { + requestObject.put(FangResponseToken.getMbeanNameKey(), + mbeanname); + requestObject.put(FangResponseToken.getRequestTypeKey(), + requesttype); + } catch (JSONException ex) { + super.setStatus(Response.Status.INTERNAL_SERVER_ERROR); + } + return requestObject; + } + + @Override + public Object getValueObject() throws JSONException { + try { + MBeanInfo mbeanInfo = delegate.getMBean(mbeanname); + return buildAttributes(mbeanInfo); + } catch (InstanceNotFoundException | IntrospectionException | ReflectionException | MalformedObjectNameException ex) { + super.setStatus(Response.Status.NOT_FOUND); + return getTraceObject(ex); + } + } + + private JSONObject buildAttributes(MBeanInfo mbean) throws JSONException { + JSONObject attributesObject = new JSONObject(); + MBeanAttributeInfo[] attributes = mbean.getAttributes(); + + for (MBeanAttributeInfo attribute : attributes) { + String attributeName = attribute.getName(); + MBeanAttributeReadHandler attributeHandler = + new MBeanAttributeReadHandler(delegate, mbeanname, + attributeName); + attributesObject.put(attributeName, + attributeHandler.getValueObject()); + } + + return attributesObject; + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/ReadHandler.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/ReadHandler.java new file mode 100644 index 00000000000..c8b06ea5439 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/ReadHandler.java @@ -0,0 +1,58 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.handler; + +import fish.payara.monitoring.fang.FangResponseToken; +import fish.payara.monitoring.fang.MBeanServerDelegate; + +/** + * + * @author Fraser Savage + */ +public abstract class ReadHandler extends ResourceHandler { + + // Request type of anything extending ReadHandler should be the read request token + protected final String requesttype = FangResponseToken.getReadRequestToken(); + + public ReadHandler(MBeanServerDelegate delegate) { + super(delegate); + } + +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/ResourceHandler.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/ResourceHandler.java new file mode 100644 index 00000000000..74b2e44fe1d --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/ResourceHandler.java @@ -0,0 +1,187 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.handler; + +import fish.payara.monitoring.fang.FangResponseToken; +import fish.payara.monitoring.fang.MBeanServerDelegate; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.ws.rs.core.Response; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; + +/** + * + * @author Fraser Savage + */ +public abstract class ResourceHandler { + + protected final MBeanServerDelegate delegate; + private Response.Status status; + + /** + * Constructs the {@link ResourceHandler}. + * + * @param delegate The {@link MBeanServerDelegate} to get information from. + */ + public ResourceHandler(MBeanServerDelegate delegate) { + this.delegate = delegate; + } + + /** + * Returns a {@link JSONObject} containing the response to the request given + * to the implementing class. + * The response is made up of a request object and a value object. + * In some cases the value object is removed in the case of an exception and + * replaced with an error object. + * + * @return The {@link JSONObject} containing the response to the request. + */ + public JSONObject getResource() { + JSONObject resourceResponse = new JSONObject(); + try { + JSONObject requestObject = getRequestObject(); + resourceResponse.put(FangResponseToken.getRequestKey(), + requestObject); + + Object valueObject = getValueObject(); + resourceResponse.put(FangResponseToken.getValueKey(), + valueObject); + + setStatus(Response.Status.OK); + + if (errorThrown(status)) { + JSONObject traceObject = (JSONObject) resourceResponse + .get(FangResponseToken.getValueKey()); + + resourceResponse.put(FangResponseToken.getStacktraceKey(), + traceObject.get(FangResponseToken.getStacktraceKey())); + resourceResponse.put(FangResponseToken.getErrorTypeKey(), + traceObject.get(FangResponseToken.getErrorTypeKey())); + resourceResponse.put(FangResponseToken.getErrorKey(), + traceObject.get(FangResponseToken.getErrorKey())); + + resourceResponse.remove(FangResponseToken.getValueKey()); + } else { + Long millis = System.currentTimeMillis(); + resourceResponse.put(FangResponseToken.getTimestampKey(), + millis); + } + + int statusCode = status.getStatusCode(); + resourceResponse.put(FangResponseToken.getHttpStatusKey(), + statusCode); + } catch (JSONException ex) { + // @TODO - FANG-6: Properly handle any JSONException caught in the ResourceHandler class. + // Is this the best way to handle it? Return the response built so far and log the issue. + // Don't exactly want to return a JSON error in the response. + // + // Options: + // 1. Place each put in it's own try-catch block so that what can be + // added to the object is added to the object before returning it - ie. + // just carry on. + // 2. Leave it as it currently is. + // 3. Don't return the response object but instead a string denoting + // internal error or something? + Logger.getLogger(ResourceHandler.class.getName()).log(Level.SEVERE, null, ex); + } + return resourceResponse; + } + + /** + * Returns a {@link JSONObject} that contains values relating to the request. + * + * @return A {@link JSONObject} containing the value(s) relating to the request.. + * @throws JSONException {@inheritDoc} + */ + abstract JSONObject getRequestObject() throws JSONException; + + /** + * Returns an {@link Object} that contains values relating to the target of + * the request. + * Typically this is a primitive type or a JSONObject. + * + * @return An {@link Object} containing the value(s) relating to the request target. + * @throws JSONException {@inheritDoc} + */ + abstract Object getValueObject() throws JSONException; + + // If the response status isn't set then will set it + protected void setStatus(Response.Status status) { + if (this.status == null) { + this.status = status; + } + } + + // Gets the JSONObject containing information about the exception passed + protected JSONObject getTraceObject(Exception exception) throws JSONException { + JSONObject traceObject = new JSONObject(); + + StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter); + exception.printStackTrace(printWriter); + + traceObject.put(FangResponseToken.getStacktraceKey(), + stringWriter.toString()); + + traceObject.put(FangResponseToken.getErrorTypeKey(), + exception.getClass().getCanonicalName()); + + traceObject.put(FangResponseToken.getErrorKey(), + exception.getClass().getCanonicalName() + " : " + + exception.getMessage()); + + return traceObject; + } + + // Returns true if one of the checked response codes is passed to it + private boolean errorThrown(Response.Status status) { + switch (status) { + case NOT_FOUND: + return true; + case INTERNAL_SERVER_ERROR: + return true; + default: + return false; + } + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/VersionHandler.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/VersionHandler.java new file mode 100644 index 00000000000..29d480acf07 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/handler/VersionHandler.java @@ -0,0 +1,59 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.handler; + +import fish.payara.monitoring.fang.FangResponseToken; +import fish.payara.monitoring.fang.MBeanServerDelegate; + +/** + * + * @author Fraser Savage + */ +public abstract class VersionHandler extends ResourceHandler { + + // Request type of anything extending VersionHandler should be the Version request token + protected final String requestType = FangResponseToken + .getVersionRequestToken(); + + public VersionHandler(MBeanServerDelegate delegate) { + super(delegate); + } + +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/ArrayTypeProcessor.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/ArrayTypeProcessor.java new file mode 100644 index 00000000000..6a1b712a3ea --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/ArrayTypeProcessor.java @@ -0,0 +1,82 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.processor; + +import java.lang.reflect.Array; +import javax.management.openmbean.ArrayType; +import org.codehaus.jettison.json.JSONArray; +import org.codehaus.jettison.json.JSONException; + +/** + * + * @author Fraser Savage + */ +// @PROPOSED - FANG-2: Flesh out flexible converter system. +public class ArrayTypeProcessor implements TypeProcessor { + + @Override + public Object processObject(Object object) throws JSONException { + Object[] arrayObject; + if (Object[].class.isAssignableFrom(object.getClass())) { + arrayObject = (Object[]) object; + } else { + int length = Array.getLength(object); + arrayObject = new Object[length]; + for (int i =0; i processor = ProcessorFactory + .getTypeProcessor(arrayItem); + + jsonArray.put(processor.processObject(arrayItem)); + } + + return jsonArray; + } + +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/CompositeTypeProcessor.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/CompositeTypeProcessor.java new file mode 100644 index 00000000000..e570d5fc0a5 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/CompositeTypeProcessor.java @@ -0,0 +1,73 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.processor; + +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; + +/** + * + * @author Fraser Savage + */ +// @PROPOSED - FANG-2: Flesh out flexible converter system. +public class CompositeTypeProcessor implements TypeProcessor { + + @Override + public JSONObject processObject(Object object) throws JSONException { + CompositeDataSupport compositeObject = (CompositeDataSupport) object; + return processObject(compositeObject); + } + + private JSONObject processObject(CompositeDataSupport compositeObject) throws JSONException { + JSONObject jsonObject = new JSONObject(); + + for (String entry : compositeObject.getCompositeType().keySet()) { + Object entryObject = compositeObject.get(entry); + TypeProcessor processor = ProcessorFactory.getTypeProcessor(entryObject); + + jsonObject.put(entry, processor.processObject(entryObject)); + } + + return jsonObject; + } + +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/OtherTypeProcessor.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/OtherTypeProcessor.java new file mode 100644 index 00000000000..0f774a3bf8c --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/OtherTypeProcessor.java @@ -0,0 +1,56 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.processor; + +import javax.management.openmbean.OpenType; + +/** + * + * @author Fraser Savage + */ +// @PROPOSED - FANG-2: Flesh out flexible converter system. +public class OtherTypeProcessor implements TypeProcessor { + + @Override + public Object processObject(Object object) { + return object.toString(); + } + +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/ProcessorFactory.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/ProcessorFactory.java new file mode 100644 index 00000000000..b184c7f30c2 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/ProcessorFactory.java @@ -0,0 +1,126 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.processor; + +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularType; + +/** + * + * @author Fraser Savage + */ +// @PROPOSED - FANG-2: Flesh out flexible converter system. +public final class ProcessorFactory { + + /** + * Returns a {@link TypeProcessor} that is best able to process an MBean attribute. + * The processibleObject argument should be an MBean attribute. + * + * @param processibleObject The {@link Object} to get the {@link TypeProcessor} for. + * @return The appropriate {@link TypeProcessor} for the processibleObject given. + */ + public static TypeProcessor getTypeProcessor(Object processibleObject) { + if (isSimpleType(processibleObject)) { + return new SimpleTypeProcessor(); + } else if (isArrayType(processibleObject)) { + return new ArrayTypeProcessor(); + } else if (isCompositeType(processibleObject)) { + return new CompositeTypeProcessor(); + } else if (isTabularType(processibleObject)) { + return new TabularTypeProcessor(); + } else { + return new OtherTypeProcessor(); + } + } + + // Checks if the object passed is a OpenMBean SimpleType + private static boolean isSimpleType(Object object) { + if (SimpleType.BIGDECIMAL.isValue(object)) { + return true; + } else if (SimpleType.BIGINTEGER.isValue(object)) { + return true; + } else if (SimpleType.BOOLEAN.isValue(object)) { + return true; + } else if (SimpleType.BYTE.isValue(object)) { + return true; + } else if (SimpleType.CHARACTER.isValue(object)) { + return true; + } else if (SimpleType.DATE.isValue(object)) { + return true; + } else if (SimpleType.DOUBLE.isValue(object)) { + return true; + } else if (SimpleType.FLOAT.isValue(object)) { + return true; + } else if (SimpleType.INTEGER.isValue(object)) { + return true; + } else if (SimpleType.LONG.isValue(object)) { + return true; + } else if (SimpleType.OBJECTNAME.isValue(object)) { + return true; + } else if (SimpleType.SHORT.isValue(object)) { + return true; + } else if (SimpleType.STRING.isValue(object)) { + return true; + } else { + return SimpleType.VOID.isValue(object); + } + } + + // Checks if the object is an array type + private static boolean isArrayType(Object object) { + return object.getClass().isArray(); + } + + // Checks if the object is a composite type + private static boolean isCompositeType(Object object) { + return (CompositeData.class.isAssignableFrom(object.getClass()) + || CompositeType.class.isAssignableFrom(object.getClass())); + } + + // Checks if the object is a tabular type + private static boolean isTabularType(Object object) { + return (TabularData.class.isAssignableFrom(object.getClass()) + || TabularType.class.isAssignableFrom(object.getClass())); + } + +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/SimpleTypeProcessor.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/SimpleTypeProcessor.java new file mode 100644 index 00000000000..0a4298e9945 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/SimpleTypeProcessor.java @@ -0,0 +1,59 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.processor; + +import javax.management.openmbean.SimpleType; + +/** + * + * @author Fraser Savage + */ +// @PROPOSED - FANG-2: Flesh out flexible converter system. +public class SimpleTypeProcessor implements TypeProcessor { + + @Override + public Object processObject(Object object) { + return object; + } + + +} + + diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/TabularTypeProcessor.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/TabularTypeProcessor.java new file mode 100644 index 00000000000..d3dab271783 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/TabularTypeProcessor.java @@ -0,0 +1,74 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.processor; + +import java.util.Map; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; + +/** + * + * @author Fraser Savage + */ +// @PROPOSED - FANG-2: Flesh out flexible converter system. +public class TabularTypeProcessor implements TypeProcessor { + + @Override + public Object processObject(Object object) throws JSONException { + TabularDataSupport tabularObject = (TabularDataSupport) object; + return processObject(tabularObject); + } + + private JSONObject processObject(TabularDataSupport tabularObject) throws JSONException { + JSONObject jsonObject = new JSONObject(); + + for (Map.Entry entry : tabularObject.entrySet()) { + TypeProcessor valueProcessor = ProcessorFactory.getTypeProcessor(entry.getValue()); + JSONObject pair = (JSONObject) valueProcessor.processObject(entry.getValue()); + + jsonObject.put(pair.get("key").toString() + , pair.get("value")); + } + + return jsonObject; + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/TypeProcessor.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/TypeProcessor.java new file mode 100644 index 00000000000..d3e1927a5c8 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/processor/TypeProcessor.java @@ -0,0 +1,65 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.processor; + +import javax.management.openmbean.OpenType; +import org.codehaus.jettison.json.JSONException; + +/** + * + * @author Fraser Savage + * @param + */ +// @PROPOSED - FANG-2: Flesh out flexible converter system. +public interface TypeProcessor { + + /** + * Returns an {@link Object} which has been processed for serving by a JSON + * REST resource. + * The object parameter must be the correct {@link OpenType}. + * Should return either an {@link Object} or a {@link JSONObject}. + * + * @param object The object to process. + * @return The processed {@link Object} form of object. + * @throws JSONException {@inheritDoc} + */ + public Object processObject(Object object) throws JSONException; + +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/resource/FangStateResource.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/resource/FangStateResource.java new file mode 100644 index 00000000000..fadcac94293 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/resource/FangStateResource.java @@ -0,0 +1,74 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.resource; + +import fish.payara.monitoring.fang.MBeanServerDelegate; +import fish.payara.monitoring.fang.handler.FangStateHandler; +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +/** + * + * @author Fraser Savage + */ +// @HOLD - FANG-3: Implement Fang 'State' handler and resource. +@Path("") +@RequestScoped +public class FangStateResource { + + @Inject + private MBeanServerDelegate mDelegate; + + /** + * Returns the {@link String} form of the {@link JSONObject} resource + * from the ResourceHandler. + * + * @return The {@link String} representation of the FangState {@link JSONObject}. + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public String getFangState() { + return new FangStateHandler(mDelegate).getResource().toString(); + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/resource/MBeanReadResource.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/resource/MBeanReadResource.java new file mode 100644 index 00000000000..8e883b4edf6 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/resource/MBeanReadResource.java @@ -0,0 +1,97 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.resource; + +import fish.payara.monitoring.fang.MBeanServerDelegate; +import fish.payara.monitoring.fang.handler.MBeanReadHandler; +import fish.payara.monitoring.fang.handler.MBeanAttributeReadHandler; +import static fish.payara.monitoring.fang.resource.PathProcessor.getSplitPath; +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +/** + * + * @author Fraser Savage + */ +@Path("read") +@RequestScoped +public class MBeanReadResource { + + @Inject + private MBeanServerDelegate mDelegate; + + /** + * Returns the {@link String} form of the {@link JSONObject} resource + * from the ResourceHandler. + * + * @param path The {@link String} representation of the URL path the resource has received. + * @return The {@link String} representation of the MBeanRead/MBeanAttributeRead {@link JSONObject}. + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + @Path("{path : .+}") + public String getReadResource(@PathParam("path") String path) { + String[] segments = getSplitPath(path); + switch (segments.length) { + case 2: + return getMBeanAttributeRead(segments[0], segments[1]); + case 1: + return getMBeanRead(segments[0]); + default: + return "invalid url"; + // @TODO - FANG-1: What path functionality is there to implement? + } + } + + private String getMBeanRead(String mbeanname) { + return new MBeanReadHandler(mDelegate, mbeanname).getResource() + .toString(); + } + + private String getMBeanAttributeRead(String mbeanname, String attributename) { + return new MBeanAttributeReadHandler(mDelegate, mbeanname, + attributename).getResource().toString(); + } +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/resource/PathProcessor.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/resource/PathProcessor.java new file mode 100644 index 00000000000..4ab0adbd940 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/resource/PathProcessor.java @@ -0,0 +1,141 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.monitoring.fang.resource; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * + * @author Fraser Savage + */ +public final class PathProcessor { + + private static final char[] SPECIAL_CHARS = {'!','/'}; + private static final char ESCAPE_CHAR = SPECIAL_CHARS[0]; + private static int PATH_LENGTH; + + /** + * Takes a {@link String} representation of a URL path and splits it on + * characters in SPECIAL_CHARS while using the ESCAPE_CHAR to escape splits. + * + * @param path The string form of the URL path to split. + * @return The string array containing each split part of the URL path. + */ + static String[] getSplitPath(String path) { + PATH_LENGTH = path.length(); + + if (PATH_LENGTH <= 2) { + String[] url = new String[1]; + url[0] = path; + return url; + } + + List segments = new ArrayList<>(); + processPath(path, segments); + clearPath(segments); + + String[] segmentArray = new String[segments.size()]; + + for (int i=0; i segments) { + StringBuilder segment = new StringBuilder(); + + for (int i=0; i segments) { + Iterator segmentIterator = segments.iterator(); + + while (segmentIterator.hasNext()) { + if (segmentIterator.next().isEmpty()) { + segmentIterator.remove(); + } + } + } + + private static boolean isEscapedChar(String str, int index) { + boolean escaped = false; + + for (int i=(index-1); i>0; i--) { + if (str.charAt(i) == ESCAPE_CHAR) { + escaped = !escaped; + } + else { + break; + } + } + + return escaped; + } + + private static boolean isSpecialChar(char target) { + + for (char reference : SPECIAL_CHARS) { + if (target == reference) { + return true; + } + } + + return false; + } + +} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/WEB-INF/glassfish-web.xml b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/WEB-INF/glassfish-web.xml new file mode 100644 index 00000000000..afdb3285c59 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/WEB-INF/glassfish-web.xml @@ -0,0 +1,8 @@ + + + + + Fang + fang + + diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/WEB-INF/web.xml b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..a304fe45319 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,32 @@ + + + + Everything + + Everything + + /* + + + + Fang + + + + + rest/ + + + + FORM + file + + /login.xhtml + /error.xhtml + + + + + Fang + + diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/error.xhtml b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/error.xhtml new file mode 100644 index 00000000000..6caa8214973 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/error.xhtml @@ -0,0 +1,58 @@ + + + + + + Login Error + + +

Invalid user name or password.

+ +

Please enter a user name or password that is authorized to access this + application. For this application, this means a user that has been + created in the file realm and has been assigned to the + group of TutorialUser.

+ Return to login page + +
+ + diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/j_security_check b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/j_security_check new file mode 100644 index 00000000000..4c52f35d7f8 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/j_security_check @@ -0,0 +1,40 @@ + + diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/login.xhtml b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/login.xhtml new file mode 100644 index 00000000000..e9636179394 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/login.xhtml @@ -0,0 +1,60 @@ + + + + + + Login Form + + +

Hello, please log in:

+
+

Please type your user name: +

+

Please type your password: +

+

+ +

+
+
+ + diff --git a/appserver/payara-appserver-modules/payara-fang/pom.xml b/appserver/payara-appserver-modules/payara-fang/pom.xml new file mode 100644 index 00000000000..b3cee2cd697 --- /dev/null +++ b/appserver/payara-appserver-modules/payara-fang/pom.xml @@ -0,0 +1,56 @@ + + + + 4.0.0 + + org.glassfish.main + payara-appserver-modules + 4.1.2.172-SNAPSHOT + + fish.payara.appserver.payara-fang + payara-fang-parent + pom + Payara Fang Parent + + payara-fang-service + payara-fang-war + + diff --git a/appserver/payara-appserver-modules/pom.xml b/appserver/payara-appserver-modules/pom.xml index 1db33daeb56..100fd2d9e9d 100644 --- a/appserver/payara-appserver-modules/pom.xml +++ b/appserver/payara-appserver-modules/pom.xml @@ -69,6 +69,6 @@ zendesk-support environment-warning payara-rest-endpoints - payara-fang-service + payara-fang
From bebdb26646cbec5d4cd244a69fe0469dce790f34 Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Wed, 24 May 2017 13:14:59 +0100 Subject: [PATCH 16/22] Make securityEnabled not require restart --- .../payara/appserver/fang/service/PayaraFangService.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java index d47bd3cdc61..64c43f00fa7 100644 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java @@ -149,8 +149,9 @@ public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvent payaraFangConfiguration); contextRoot = endpointDecider.getContextRoot(); } - } else { - // If a startup has been attempted, just throw an unprocessed change event as we need to restart + } else if (!propertyChangeEvent.getPropertyName().equals("securityEnabled")) { + // If a startup has been attempted and the changed property isn't securityEnabled, throw an + // unprocessed change event as we need to restart unprocessedChanges.add(new UnprocessedChangeEvent(propertyChangeEvent, "Payara Fang redeploy required")); } From 9af2f7d09fbf2c7f5cce304634c5125b1a7ae55a Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Wed, 24 May 2017 15:42:22 +0100 Subject: [PATCH 17/22] Remove old module, and add in defaults creation --- .../payara-fang-service/pom.xml | 55 --- .../fang/service/PayaraFangLoader.java | 372 --------------- .../fang/service/PayaraFangService.java | 196 -------- .../service/adapter/PayaraFangAdapter.java | 446 ------------------ .../adapter/PayaraFangAdapterState.java | 76 --- .../adapter/PayaraFangEndpointDecider.java | 160 ------- .../SetPayaraFangConfigurationCommand.java | 137 ------ .../PayaraFangConfiguration.java | 76 --- .../fang/service/security/FangAuthModule.java | 205 -------- .../fang/service/PayaraFangService.java | 4 +- .../SetPayaraFangConfigurationCommand.java | 103 +++- 11 files changed, 103 insertions(+), 1727 deletions(-) delete mode 100644 appserver/payara-appserver-modules/payara-fang-service/pom.xml delete mode 100644 appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java delete mode 100644 appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java delete mode 100644 appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java delete mode 100644 appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java delete mode 100644 appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java delete mode 100644 appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java delete mode 100644 appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java delete mode 100644 appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java diff --git a/appserver/payara-appserver-modules/payara-fang-service/pom.xml b/appserver/payara-appserver-modules/payara-fang-service/pom.xml deleted file mode 100644 index 66e9d3cc4e1..00000000000 --- a/appserver/payara-appserver-modules/payara-fang-service/pom.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - 4.0.0 - - org.glassfish.main - payara-appserver-modules - 4.1.2.172-SNAPSHOT - - fish.payara.appserver - payara-fang-service - glassfish-jar - Payara Fang - - - - org.glassfish.main.common - glassfish-api - ${project.version} - - - org.glassfish.main.common - internal-api - ${project.version} - - - org.glassfish.main.core - kernel - ${project.version} - - - javax - javaee-api - 7.0 - provided - - - org.glassfish.main.security - security - ${project.version} - provided - - - org.glassfish.main.admin - rest-client - ${project.version} - provided - - - fish.payara.admingui - console-common - ${project.version} - provided - - - diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java deleted file mode 100644 index 4d4ffd232ee..00000000000 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java +++ /dev/null @@ -1,372 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://github.com/payara/Payara/blob/master/LICENSE.txt - * See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at glassfish/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * The Payara Foundation designates this particular file as subject to the "Classpath" - * exception as provided by the Payara Foundation in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package fish.payara.appserver.fang.service; - -import com.sun.enterprise.config.serverbeans.Application; -import com.sun.enterprise.config.serverbeans.ApplicationRef; -import com.sun.enterprise.config.serverbeans.Domain; -import com.sun.enterprise.config.serverbeans.Engine; -import com.sun.enterprise.config.serverbeans.Module; -import com.sun.enterprise.config.serverbeans.Server; -import com.sun.enterprise.config.serverbeans.SystemApplications; -import com.sun.enterprise.v3.server.ApplicationLoaderService; -import fish.payara.appserver.fang.service.adapter.PayaraFangAdapter; -import fish.payara.appserver.fang.service.adapter.PayaraFangAdapterState; -import java.beans.PropertyVetoException; -import java.util.Arrays; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.internal.data.ApplicationInfo; -import org.glassfish.internal.data.ApplicationRegistry; -import org.glassfish.server.ServerEnvironmentImpl; -import org.jvnet.hk2.config.ConfigBeanProxy; -import org.jvnet.hk2.config.ConfigCode; -import org.jvnet.hk2.config.ConfigSupport; -import org.jvnet.hk2.config.TransactionFailure; - -/** - * Loader class for the Payara Fang application. Handles registering and actual loading of the application. - * @author Andrew Pielage - */ -public class PayaraFangLoader extends Thread { - private final Domain domain; - private final ServerEnvironmentImpl serverEnv; - private final String contextRoot; - private String applicationName; - private final PayaraFangAdapter payaraFangAdapter; - private final ServiceLocator habitat; - private static final Logger LOGGER = Logger.getLogger(PayaraFangLoader.class.getName()); - private final List vss; - private final boolean dynamicStart; - - PayaraFangLoader(PayaraFangAdapter payaraFangAdapter, ServiceLocator habitat, Domain domain, - ServerEnvironmentImpl serverEnv, String contextRoot, String applicationName, List vss) { - this.payaraFangAdapter = payaraFangAdapter; - this.habitat = habitat; - this.domain = domain; - this.serverEnv = serverEnv; - this.contextRoot = contextRoot; - this.applicationName = applicationName; - this.vss = vss; - this.dynamicStart = false; - } - - PayaraFangLoader(PayaraFangAdapter payaraFangAdapter, ServiceLocator habitat, Domain domain, - ServerEnvironmentImpl serverEnv, String contextRoot, String applicationName, List vss, - boolean dynamicStart) { - this.payaraFangAdapter = payaraFangAdapter; - this.habitat = habitat; - this.domain = domain; - this.serverEnv = serverEnv; - this.contextRoot = contextRoot; - this.applicationName = applicationName; - this.vss = vss; - this.dynamicStart = dynamicStart; - } - - @Override - public void run() { - try { - // Check if we've started the service dynamically, and so whether or not to override the adapter's config - if (dynamicStart) { - if (payaraFangAdapter.appExistsInConfig(contextRoot)) { - // Check if we need to reconfigure system app to match the overriding config - if (!payaraFangAdapter.isAppRegistered(contextRoot)) { - registerApplication(); - } else { - // Since we're starting dynamically, assume that we need to reconfigure - reconfigureSystemApplication(); - } - } else { - // If the app simply doesn't exist, create one and register it for this instance - createAndRegisterApplication(); - } - } else { - // Check if the application already exists - if (payaraFangAdapter.appExistsInConfig()) { - // Check if the app is actually registered to this instance - if (!payaraFangAdapter.isAppRegistered()) { - // We hit here if the app exists, but hasn't been registered to this instance yet - registerApplication(); - } else if (!contextRoot.equals(payaraFangAdapter.getSystemApplicationConfig().getContextRoot())) { - // We hit here if there is a system application already created and registered to this instance, - // but we've changed the context root and so need to reconfigure the system app - reconfigureSystemApplication(); - } - } else { - // If the app simply doesn't exist, create one and register it for this instance - createAndRegisterApplication(); - } - } - - loadApplication(); - } catch (Exception ex) { - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); - LOGGER.log(Level.WARNING, "Problem while attempting to register or load Payara Fang!", ex); - } - } - - /** - * Create the system application entry and register the application - * @throws Exception - */ - private void createAndRegisterApplication() throws Exception { - // Update the adapter state - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.REGISTERING); - LOGGER.log(Level.FINE, "Registering the Payara Fang Application..."); - - // Create the system application entry and application-ref in the config - ConfigCode code = new ConfigCode() { - @Override - public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, TransactionFailure { - // Create the system application - SystemApplications systemApplications = (SystemApplications) proxies[0]; - Application application = systemApplications.createChild(Application.class); - - // Check if the application name is valid, generating a new one if it isn't - checkAndResolveApplicationName(systemApplications); - - systemApplications.getModules().add(application); - application.setName(applicationName); - application.setEnabled(Boolean.TRUE.toString()); - application.setObjectType("system-admin"); - application.setDirectoryDeployed("true"); - application.setContextRoot(contextRoot); - - try { - application.setLocation("${com.sun.aas.installRootURI}/lib/install/applications/" - + PayaraFangService.DEFAULT_FANG_APP_NAME); - } catch (Exception me) { - throw new RuntimeException(me); - } - - // Set the engine types - Module singleModule = application.createChild(Module.class); - application.getModule().add(singleModule); - singleModule.setName(applicationName); - Engine webEngine = singleModule.createChild(Engine.class); - webEngine.setSniffer("web"); - Engine weldEngine = singleModule.createChild(Engine.class); - weldEngine.setSniffer("weld"); - Engine securityEngine = singleModule.createChild(Engine.class); - securityEngine.setSniffer("security"); - singleModule.getEngines().add(webEngine); - singleModule.getEngines().add(weldEngine); - singleModule.getEngines().add(securityEngine); - - // Create the application-ref - Server s = (Server) proxies[1]; - List arefs = s.getApplicationRef(); - ApplicationRef aref = s.createChild(ApplicationRef.class); - aref.setRef(application.getName()); - aref.setEnabled(Boolean.TRUE.toString()); - aref.setVirtualServers(getVirtualServerListAsString()); - arefs.add(aref); - - return true; - } - }; - - Server server = domain.getServerNamed(serverEnv.getInstanceName()); - ConfigSupport.apply(code, domain.getSystemApplications(), server); - - // Update the adapter state - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); - LOGGER.log(Level.FINE, "Payara Fang Registered."); - } - - private void registerApplication() throws Exception { - // Update the adapter state - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.REGISTERING); - LOGGER.log(Level.FINE, "Registering the Payara Fang Application..."); - - // Create the application-ref entry in the domain.xml - ConfigCode code = new ConfigCode() { - @Override - public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, TransactionFailure { - // Get the system application config - SystemApplications systemApplications = (SystemApplications) proxies[0]; - Application application = null; - for (Application systemApplication : systemApplications.getApplications()) { - if (systemApplication.getName().equals(applicationName)) { - application = systemApplication; - break; - } - } - - if (application == null) { - throw new IllegalStateException("Payara Fang has no system app entry!"); - } - - // Create the application-ref - Server s = (Server) proxies[1]; - List arefs = s.getApplicationRef(); - ApplicationRef aref = s.createChild(ApplicationRef.class); - aref.setRef(application.getName()); - aref.setEnabled(Boolean.TRUE.toString()); - aref.setVirtualServers(getVirtualServerListAsString()); - arefs.add(aref); - return true; - } - }; - - Server server = domain.getServerNamed(serverEnv.getInstanceName()); - ConfigSupport.apply(code, domain.getSystemApplications(), server); - - // Update the adapter state - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); - LOGGER.log(Level.FINE, "Payara Fang Registered."); - } - - private String getVirtualServerListAsString() { - if (vss == null) { - return ""; - } - - String virtualServers = Arrays.toString(vss.toArray(new String[vss.size()])); - - // Standard JDK implemetation always returns this enclosed in [], which we don't want - virtualServers = virtualServers.substring(1, virtualServers.length() - 1); - - return virtualServers; - } - - /** - * Loads the application - */ - private void loadApplication() { - ApplicationRegistry appRegistry = habitat.getService(ApplicationRegistry.class); - ApplicationInfo appInfo = appRegistry.get(applicationName); - if (appInfo != null && appInfo.isLoaded()) { - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADED); - return; - } - - Application config = null; - if (dynamicStart) { - config = payaraFangAdapter.getSystemApplicationConfig(contextRoot); - } else { - config = payaraFangAdapter.getSystemApplicationConfig(); - } - - - if (config == null) { - throw new IllegalStateException("Payara Fang has no system app entry!"); - } - - // Update adapter state - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADING); - - // Load the Payara Fang Application - String instanceName = serverEnv.getInstanceName(); - ApplicationRef ref = domain.getApplicationRefInServer(instanceName, applicationName); - habitat.getService(ApplicationLoaderService.class).processApplication(config, ref); - - // Update adapter state and mark as registered - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADED); - payaraFangAdapter.setAppRegistered(true); - } - - private void checkAndResolveApplicationName(SystemApplications systemApplications) { - // Check if the application name is not empty - if (applicationName == null || applicationName.equals("")) { - LOGGER.log(Level.INFO, "No or incorrect application name detected for Payara Fang: reverting to default"); - applicationName = PayaraFangService.DEFAULT_FANG_APP_NAME; - } - - // Loop through the system applications - boolean validApplicationNameFound = false; - int applicationNameSuffix = 1; - while (!validApplicationNameFound) { - // Check if the current application name is in use - validApplicationNameFound = isApplicationNameValid(systemApplications); - - if (!validApplicationNameFound) { - // If the name isn't valid, append a number to it and try again - applicationName = applicationName + "-" + applicationNameSuffix; - applicationNameSuffix++; - } - } - - } - - private boolean isApplicationNameValid(SystemApplications systemApplications) { - boolean validApplicationNameFound = true; - - // Search through the system application names to check if there are any apps with the same name - for (Application systemApplication : systemApplications.getApplications()) { - if (systemApplication.getName().equals(applicationName)) { - // We've found an application with the same name, that means we can't use this one - validApplicationNameFound = false; - break; - } - } - - return validApplicationNameFound; - } - - private void reconfigureSystemApplication() throws Exception { - Application systemApplication = payaraFangAdapter.getSystemApplicationConfig(); - - // Update the adapter state - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.RECONFIGURING); - LOGGER.log(Level.FINE, "Reconfiguring the Payara Fang Application..."); - - // Reconfigure the system-application entry in the domain.xml - ConfigCode code = new ConfigCode() { - @Override - public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, TransactionFailure { - Application systemApplication = (Application) proxies[0]; - systemApplication.setContextRoot(contextRoot); - - return true; - } - }; - - ConfigSupport.apply(code, systemApplication); - - // Update the adapter state - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); - LOGGER.log(Level.FINE, "Payara Fang Reconfigured."); - } -} diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java deleted file mode 100644 index d47bd3cdc61..00000000000 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://github.com/payara/Payara/blob/master/LICENSE.txt - * See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at glassfish/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * The Payara Foundation designates this particular file as subject to the "Classpath" - * exception as provided by the Payara Foundation in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package fish.payara.appserver.fang.service; - -import com.sun.enterprise.config.serverbeans.Config; -import com.sun.enterprise.config.serverbeans.Domain; -import fish.payara.appserver.fang.service.adapter.PayaraFangAdapter; -import fish.payara.appserver.fang.service.adapter.PayaraFangEndpointDecider; -import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; -import java.beans.PropertyChangeEvent; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import javax.inject.Named; -import org.glassfish.api.admin.ServerEnvironment; -import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.hk2.runlevel.RunLevel; -import org.glassfish.internal.api.PostStartupRunLevel; -import org.glassfish.server.ServerEnvironmentImpl; -import org.jvnet.hk2.annotations.Optional; -import org.jvnet.hk2.annotations.Service; -import org.jvnet.hk2.config.ConfigBeanProxy; -import org.jvnet.hk2.config.ConfigListener; -import org.jvnet.hk2.config.UnprocessedChangeEvent; -import org.jvnet.hk2.config.UnprocessedChangeEvents; - -/** - * The core service for the Payara Fang application. Handles starting and reconfiguration of the application. - * @author Andrew Pielage - */ -@Service(name = "payara-fang") -@RunLevel(PostStartupRunLevel.VAL) -public class PayaraFangService implements ConfigListener { - - public static final String DEFAULT_FANG_APP_NAME = "__fang"; - private boolean startAttempted = false; - private String contextRoot; - - @Inject - @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) - @Optional - private PayaraFangConfiguration payaraFangConfiguration; - - @Inject - private PayaraFangAdapter payaraFangAdapter; - - @Inject - Domain domain; - - @Inject - ServerEnvironmentImpl serverEnv; - - @Inject - ServiceLocator habitat; - - @PostConstruct - private void postConstruct() { - contextRoot = payaraFangAdapter.getContextRoot(); - payaraFangConfiguration = habitat.getService(PayaraFangConfiguration.class); - - if (payaraFangConfiguration.getEnabled().equals("true")) { - loadApplication(); - } - } - - private void loadApplication() { - startAttempted = true; - try { - new PayaraFangLoader(payaraFangAdapter, habitat, domain, serverEnv, - contextRoot, payaraFangConfiguration.getApplicationName(), - payaraFangAdapter.getVirtualServers()).start(); - } catch (Exception ex) { - throw new RuntimeException("Unable to load Payara Fang!", ex); - } - } - - private void loadApplication(boolean dynamicStart) { - startAttempted = true; - try { - new PayaraFangLoader(payaraFangAdapter, habitat, domain, serverEnv, - contextRoot, payaraFangConfiguration.getApplicationName(), - payaraFangAdapter.getVirtualServers(), dynamicStart).start(); - } catch (Exception ex) { - throw new RuntimeException("Unable to load Payara Fang!", ex); - } - } - - @Override - public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvents) { - List unprocessedChanges = new ArrayList<>(); - boolean dynamicStart = false; - - for (PropertyChangeEvent propertyChangeEvent : propertyChangeEvents) { - // Check that the property change event is for us. - if (propertyChangeEvent.getSource().toString().equals("GlassFishConfigBean." - + PayaraFangConfiguration.class.getName()) && isCurrentInstanceMatchTarget(propertyChangeEvent)) { - // Check if the property has actually changed - if (!propertyChangeEvent.getOldValue().equals(propertyChangeEvent.getNewValue())) { - // If the application hasn't attempted to start yet - if (!startAttempted) { - // We can only get here if enabled was false at server start, so in the case of the enabled - // property, we don't need to compare it to the current value - it can only be true - if (propertyChangeEvent.getPropertyName().equals("enabled")) { - // Flag that we want to dynamically start Payara Fang - dynamicStart = true; - } else if (propertyChangeEvent.getPropertyName().equals("context-root")) { - // If we haven't attempted to start the app yet, grab the new context root - Config serverConfig = domain.getServerNamed(serverEnv.getInstanceName()).getConfig(); - PayaraFangEndpointDecider endpointDecider = new PayaraFangEndpointDecider(serverConfig, - payaraFangConfiguration); - contextRoot = endpointDecider.getContextRoot(); - } - } else { - // If a startup has been attempted, just throw an unprocessed change event as we need to restart - unprocessedChanges.add(new UnprocessedChangeEvent(propertyChangeEvent, - "Payara Fang redeploy required")); - } - } - } - } - - // This should only be true if Payara Fang was not enabled at startup, and we've just enabled the service - if (dynamicStart) { - loadApplication(true); - } - - // If we need to restart, throw an unprocessed change event - if (unprocessedChanges.isEmpty()) { - return null; - } else { - return new UnprocessedChangeEvents(unprocessedChanges); - } - } - - private boolean isCurrentInstanceMatchTarget(PropertyChangeEvent propertyChangeEvent) { - // If we are an instance then the change will apply to us as it has been - // replicated directly to us by the DAS - if (serverEnv.isInstance()) { - return true; - } - - ConfigBeanProxy proxy = (ConfigBeanProxy) propertyChangeEvent.getSource(); - - // Find the config parent - while (proxy != null && !(proxy instanceof Config)) { - proxy = proxy.getParent(); - } - - if (proxy != null) { - // We have found a config node at the root - // If the root config is the das config return true - return ((Config)proxy).isDas(); - } - - return false; - } -} diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java deleted file mode 100644 index ea31cba8708..00000000000 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java +++ /dev/null @@ -1,446 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://github.com/payara/Payara/blob/master/LICENSE.txt - * See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at glassfish/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * The Payara Foundation designates this particular file as subject to the "Classpath" - * exception as provided by the Payara Foundation in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package fish.payara.appserver.fang.service.adapter; - -import com.sun.appserv.server.util.Version; -import com.sun.enterprise.config.serverbeans.Application; -import com.sun.enterprise.config.serverbeans.Config; -import com.sun.enterprise.config.serverbeans.Domain; -import com.sun.enterprise.config.serverbeans.SystemApplications; -import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.MissingResourceException; -import java.util.ResourceBundle; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import javax.inject.Named; -import org.glassfish.api.admin.ServerEnvironment; -import org.glassfish.api.container.Adapter; -import org.glassfish.api.event.Events; -import org.glassfish.grizzly.http.Method; -import org.glassfish.grizzly.http.io.OutputBuffer; -import org.glassfish.grizzly.http.server.HttpHandler; -import org.glassfish.grizzly.http.server.Request; -import org.glassfish.grizzly.http.server.Response; -import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.internal.data.ApplicationRegistry; -import org.glassfish.server.ServerEnvironmentImpl; -import org.jvnet.hk2.annotations.Optional; -import org.jvnet.hk2.annotations.Service; - -/** - * The adapter class for the Payara Fang application. - * @author Andrew Pielage - */ -@Service -public final class PayaraFangAdapter extends HttpHandler implements Adapter { - private PayaraFangAdapterState stateMsg = PayaraFangAdapterState.UNINITIALISED; - private boolean isRegistered = false; - private boolean appRegistered = false; - private ResourceBundle bundle; - private final Method[] allowedHttpMethods = {Method.GET, Method.POST, Method.HEAD, Method.DELETE, Method.PUT}; - - private static PayaraFangEndpointDecider endpointDecider; - - @Inject - ServerEnvironmentImpl env; - - @Inject - ApplicationRegistry appRegistry; - - @Inject - Domain domain; - - @Inject - ServiceLocator habitat; - - @Inject - Events events; - - @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) - Config serverConfig; - - @Inject - @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) - @Optional - PayaraFangConfiguration fangServiceConfiguration; - - private final static Logger logger = Logger.getLogger(PayaraFangAdapter.class.getName()); - private final static String RESOURCE_PACKAGE = "fish/payara/appserver/fang/adapter"; - private final CountDownLatch latch = new CountDownLatch(1); - - @PostConstruct - public void postConstruct() { - fangServiceConfiguration = habitat.getService(PayaraFangConfiguration.class); - init(); - } - - private void init() { - try { - endpointDecider = new PayaraFangEndpointDecider(serverConfig, fangServiceConfiguration); - } catch (Exception ex) { - logger.log(Level.INFO, "Payara Fang Console cannot initialise", ex); - } - - // If the app exists in the domain.xml AND it's registered to this instance - if (appExistsInConfig() && (domain.getSystemApplicationReferencedFrom(env.getInstanceName(), - fangServiceConfiguration.getApplicationName()) != null)) { - setStateMsg(PayaraFangAdapterState.NOT_LOADED); - setAppRegistered(true); - } else { - setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); - } - } - - public boolean appExistsInConfig() { - return (getSystemApplicationConfig() != null); - } - - public boolean appExistsInConfig(String contextRoot) { - return (getSystemApplicationConfig(contextRoot) != null); - } - - /** - * Gets the application config for the system application with the matching name or context root (in that order). - * @return The application config, or null if there is no matching application - */ - public Application getSystemApplicationConfig() { - // First, check if there is an app registered for this server with the given application name - Application application = domain.getSystemApplicationReferencedFrom(env.getInstanceName(), - fangServiceConfiguration.getApplicationName()); - - // If the app hasn't been registered to the instance yet, the previous check will return null, so check for one - // with a matching context root instead (as these are also unique and saves us creating an extra app entry) - if (application == null) { - application = getApplicationWithMatchingContextRoot(getContextRoot()); - } - - return application; - } - - /** - * Gets the application config for the system application with the matching context root. This method is used over the - * overloaded method if you want to skip trying to get the application config based on the application name, such as - * if you've reconfigured the application. - * @param contextRoot The context root of the application - * @return The application config, or null if there is no matching application. - */ - public Application getSystemApplicationConfig(String contextRoot) { - Application application = getApplicationWithMatchingContextRoot(contextRoot); - - return application; - } - - /** - * Helper method that searches through all system applications for one with a matching context root. - * @param contextRoot The context root fo the application. - * @return The application config, or null if there are no applications with a matching context root. - */ - private Application getApplicationWithMatchingContextRoot(String contextRoot) { - Application application = null; - - SystemApplications systemApplications = domain.getSystemApplications(); - for (Application systemApplication : systemApplications.getApplications()) { - if (systemApplication.getContextRoot().equals(contextRoot)) { - application = systemApplication; - break; - } - } - - return application; - } - - public PayaraFangAdapterState getStateMsg() { - return stateMsg; - } - - public void setStateMsg(PayaraFangAdapterState msg) { - stateMsg = msg; - logger.log(Level.FINE, msg.toString()); - } - - @Override - public void service(Request request, Response response) throws Exception { - bundle = getResourceBundle(request.getLocale()); - Method method = request.getMethod(); - - if (!checkHttpMethodAllowed(method)) { - response.setStatus(java.net.HttpURLConnection.HTTP_BAD_METHOD, - method.getMethodString() + " " + bundle.getString("http.bad.method")); - response.setHeader("Allow", getAllowedHttpMethodsAsString()); - return; - } - - try { - if (!latch.await(100L, TimeUnit.SECONDS)) { - logger.log(Level.SEVERE, "Timed out processing a Payara Fang request"); - return; - } - } catch (InterruptedException ex) { - logger.log(Level.SEVERE, "Cannot process Payara Fang request"); - return; - } - - logRequest(request); - - if (isResourceRequest(request)) { - try { - handleResourceRequest(request, response); - } catch (IOException ioe) { - if (logger.isLoggable(Level.SEVERE)) { - logger.log(Level.SEVERE, "Unable to serve resource: {0}. Cause: {1}", - new Object[]{request.getRequestURI(), ioe.toString()}); - } - - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, ioe.toString(), ioe); - } - } - - return; - } - - response.setContentType("text/html; charset=UTF-8"); - - String serverVersion = Version.getFullVersion(); - - if ("/testifbackendisready.html".equals(request.getRequestURI())) { - // Replace state token - String status = getStateMsg().getI18NKey(); - try { - // Try to get a localized version of this key - status = bundle.getString(status); - } catch (MissingResourceException ex) { - // Use the non-localized String version of the status - status = getStateMsg().toString(); - } - - String wkey = PayaraFangAdapterState.WELCOME_TO.getI18NKey(); - - try { - // Try to get a localized version of this key - serverVersion = bundle.getString(wkey) + " " + serverVersion + "."; - } catch (MissingResourceException ex) { - // Use the non-localized String version of the status - serverVersion = PayaraFangAdapterState.WELCOME_TO.toString() + " " + serverVersion + "."; - } - - status += "\n" + serverVersion; - - try { - OutputBuffer ob = getOutputBuffer(response); - byte[] bytes = (":::" + status).getBytes("UTF-8"); - response.setContentLength(bytes.length); - ob.write(bytes, 0, bytes.length); - ob.flush(); - } catch (IOException ex) { - logger.log(Level.SEVERE, "Unable to serve resource: {0}. Cause: {1}", ex); - } - } - // TODO: Handle application not being there - } - - private ResourceBundle getResourceBundle(Locale locale) { - return ResourceBundle.getBundle("com.sun.enterprise.v3.admin.adapter.LocalStrings", locale); - } - - private boolean checkHttpMethodAllowed(Method method) { - for (Method allowedMethod : allowedHttpMethods) { - if (allowedMethod.equals(method)) { - return true; - } - } - return false; - } - - private String getAllowedHttpMethodsAsString() { - StringBuilder sb = new StringBuilder(allowedHttpMethods[0].getMethodString()); - for (int i = 1; i < allowedHttpMethods.length; i++) { - sb.append(", ").append(allowedHttpMethods[i].getMethodString()); - } - - return sb.toString(); - } - - private void logRequest(Request request) { - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, "PayaraFangAdapter's STATE IS: {0}", getStateMsg()); - logger.log(Level.FINE, "Current Thread: {0}", Thread.currentThread().getName()); - - for (final String name : request.getParameterNames()) { - final String values = Arrays.toString(request.getParameterValues(name)); - logger.log(Level.FINE, "Parameter name: {0} values: {1}", new Object[]{name, values}); - } - } - } - - private boolean isResourceRequest(Request request) { - return (getContentType(request.getRequestURI()) != null); - } - - private String getContentType(String resource) { - if (resource == null || resource.length() == 0) { - return null; - } - - if (resource.endsWith(".gif")) { - return "image/gif"; - } else if (resource.endsWith(".jpg")) { - return "image/jpeg"; - } else { - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, "Unhandled content-type: {0}", resource); - } - - return null; - } - } - - private void handleResourceRequest(Request request, Response response) throws IOException { - String resourcePath = RESOURCE_PACKAGE + request.getRequestURI(); - - ClassLoader loader = PayaraFangAdapter.class.getClassLoader(); - - try (InputStream inputStream = loader.getResourceAsStream(resourcePath)) { - if (inputStream == null) { - logger.log(Level.WARNING, "Resource not found: {0}", resourcePath); - return; - } - - byte[] buffer = new byte[512]; - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(512); - - for (int i = inputStream.read(buffer); i != -1; i = inputStream.read(buffer)) { - byteArrayOutputStream.write(buffer, 0, i); - } - - String contentType = getContentType(resourcePath); - - if (contentType != null) { - response.setContentType(contentType); - } - - response.setContentLength(byteArrayOutputStream.size()); - OutputStream outputStream = response.getOutputStream(); - byteArrayOutputStream.writeTo(outputStream); - outputStream.flush(); - } - } - - private OutputBuffer getOutputBuffer(Response response) { - response.setStatus(202); - response.setContentType("text/html"); - response.setCharacterEncoding("UTF-8"); - return response.getOutputBuffer(); - } - - @Override - public HttpHandler getHttpService() { - return this; - } - - @Override - public String getContextRoot() { - return endpointDecider.getContextRoot(); - } - - @Override - public int getListenPort() { - return endpointDecider.getListenPort(); - } - - @Override - public InetAddress getListenAddress() { - return endpointDecider.getListenAddress(); - } - - @Override - public List getVirtualServers() { - return endpointDecider.getHosts(); - } - - @Override - public boolean isRegistered() { - return isRegistered; - } - - @Override - public void setRegistered(boolean isRegistered) { - this.isRegistered = isRegistered; - } - - public boolean isAppRegistered() { - return appRegistered; - } - - public void setAppRegistered(boolean appRegistered) { - this.appRegistered = true; - } - - /** - * Overloaded method that checks if an application with the provided context root has been registered to this instance. - * @param contextRoot The context root to match. - * @return True if an application has been registered to this instance. - */ - public boolean isAppRegistered(String contextRoot) { - boolean registered = false; - Application application = getSystemApplicationConfig(contextRoot); - - // Check if we've found an application with a matching context root, and that it's registered to this instance - if (application != null && (domain.getSystemApplicationReferencedFrom(env.getInstanceName(), - application.getName()) != null)) { - registered = true; - } - - return registered; - } -} diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java deleted file mode 100644 index eb5660ae5d8..00000000000 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://github.com/payara/Payara/blob/master/LICENSE.txt - * See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at glassfish/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * The Payara Foundation designates this particular file as subject to the "Classpath" - * exception as provided by the Payara Foundation in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package fish.payara.appserver.fang.service.adapter; - -/** - * - * @author Andrew Pielage - */ -public enum PayaraFangAdapterState { - NOT_LOADED("state.notLoaded", "Payara Fang is registered in the config but not loaded yet"), - LOADING("state.loading", "Payara Fang is loading"), - LOADED("state.loaded", "Payara Fang is loaded"), - UNINITIALISED("state.uninitialised", "Payara Fang has not been initialised yet"), - REGISTERING("state.registering", "Payara Fang is being registered as a system application"), - NOT_REGISTERED("state.notRegistered", "Payara Fang is not registered in the config"), - RECONFIGURING("state.reconfiguring", "Payara Fang system-application entry is being reconfigured"), - WELCOME_TO("status.welcometo", "Welcome to "); - - private final String desc; - private final String i18nKey; - - private PayaraFangAdapterState(String i18nKey, String desc) { - this.i18nKey = i18nKey; - this.desc = desc; - } - - /** - * This is the key that should be used to retrieve the localised message from a properties file. - */ - public String getI18NKey() { - return i18nKey; - } - - @Override - public String toString() { - return (desc); - } -} diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java deleted file mode 100644 index e1f7a7b87ff..00000000000 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangEndpointDecider.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://github.com/payara/Payara/blob/master/LICENSE.txt - * See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at glassfish/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * The Payara Foundation designates this particular file as subject to the "Classpath" - * exception as provided by the Payara Foundation in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package fish.payara.appserver.fang.service.adapter; - -import com.sun.enterprise.config.serverbeans.Config; -import com.sun.enterprise.config.serverbeans.ServerTags; -import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.logging.Logger; -import javax.inject.Inject; -import org.glassfish.grizzly.config.dom.NetworkListener; -import org.glassfish.grizzly.config.dom.ThreadPool; -import org.glassfish.hk2.api.ServiceLocator; - -/** - * This class encapsulates the process of resolving the actual endpoint of the Payara Fang application. - * @author Andrew Pielage - */ -public class PayaraFangEndpointDecider { - private String contextRoot; - - private int port; - private InetAddress address; - private int maxThreadPoolSize = 5; - private Config config; - private static final Logger logger = Logger.getLogger(PayaraFangEndpointDecider.class.getName()); - private List hosts; - private PayaraFangConfiguration fangServiceConfiguration; - - private final static String DEFAULT_CONTEXT_ROOT = "/fang"; - - public static final int DEFAULT_ADMIN_PORT = 4848; - - @Inject - ServiceLocator habitat; - - public PayaraFangEndpointDecider(Config config, PayaraFangConfiguration fangServiceConfiguration) { - if (config == null || logger == null) - throw new IllegalArgumentException("config or logger can't be null"); - this.config = config; - this.fangServiceConfiguration = fangServiceConfiguration; - setValues(); - } - - public int getListenPort() { - return port; - } - - public InetAddress getListenAddress() { - return address; - } - - public int getMaxThreadPoolSize() { - return maxThreadPoolSize; - } - - public String getContextRoot() { - return contextRoot; - } - - private void setValues() { - NetworkListener networkListener = config.getAdminListener(); - ThreadPool threadPool = networkListener.findThreadPool(); - - // Set Thread pool size - if (threadPool != null) { - try { - maxThreadPoolSize = Integer.parseInt(threadPool.getMaxThreadPoolSize()); - } catch (NumberFormatException ex) { - - } - } - - String defaultVirtualServer = networkListener.findHttpProtocol().getHttp().getDefaultVirtualServer(); - hosts = Collections.unmodifiableList(Arrays.asList(defaultVirtualServer)); - - // Set network address - try { - address = InetAddress.getByName(networkListener.getAddress()); - } catch (UnknownHostException e) { - throw new IllegalStateException(e); - } - - // Set the context root and port number - if (ServerTags.ADMIN_LISTENER_ID.equals(networkListener.getName())) { - // Get the context root from the Payara Fang service - if (fangServiceConfiguration == null) { - contextRoot = DEFAULT_CONTEXT_ROOT; - } else { - contextRoot = fangServiceConfiguration.getContextRoot(); - } - - try { - port = Integer.parseInt(networkListener.getPort()); - } catch(NumberFormatException ne) { - port = DEFAULT_ADMIN_PORT; - } - } - else { - try { - port = Integer.parseInt(networkListener.getPort()); - } catch(NumberFormatException ne) { - port = DEFAULT_ADMIN_PORT; - } - - // Get the context root from the Payara Fang service - if (fangServiceConfiguration == null) { - contextRoot = DEFAULT_CONTEXT_ROOT; - } else { - contextRoot = fangServiceConfiguration.getContextRoot(); - } - } - } - - public List getHosts() { - return hosts; - } -} diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java deleted file mode 100644 index 6c3ad7e3854..00000000000 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://github.com/payara/Payara/blob/master/LICENSE.txt - * See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at glassfish/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * The Payara Foundation designates this particular file as subject to the "Classpath" - * exception as provided by the Payara Foundation in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package fish.payara.appserver.fang.service.admin; - -import com.sun.enterprise.config.serverbeans.Config; -import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; -import java.beans.PropertyVetoException; -import java.util.logging.Logger; -import javax.inject.Inject; -import org.glassfish.api.Param; -import org.glassfish.api.admin.AdminCommand; -import org.glassfish.api.admin.AdminCommandContext; -import org.glassfish.api.admin.ExecuteOn; -import org.glassfish.api.admin.RestEndpoint; -import org.glassfish.api.admin.RestEndpoints; -import org.glassfish.api.admin.RuntimeType; -import org.glassfish.api.admin.ServerEnvironment; -import org.glassfish.hk2.api.PerLookup; -import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.internal.api.Target; -import org.jvnet.hk2.annotations.Service; -import org.jvnet.hk2.config.ConfigSupport; -import org.jvnet.hk2.config.SingleConfigCode; -import org.jvnet.hk2.config.TransactionFailure; - -/** - * - * @author Andrew Pielage - */ -@Service(name = "set-payara-fang-configuration") -@PerLookup -@ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE}) -@RestEndpoints({ - @RestEndpoint(configBean = PayaraFangConfiguration.class, - opType = RestEndpoint.OpType.POST, - path = "set-payara-fang-configuration", - description = "Sets the Payara Fang Configuration") -}) -public class SetPayaraFangConfigurationCommand implements AdminCommand { - - private final static Logger LOGGER = Logger.getLogger(SetPayaraFangConfigurationCommand.class.getName()); - - @Param(optional = true, defaultValue = "server-config") - String target; - - @Param(optional = true) - Boolean enabled; - - @Param(optional = true, alias = "contextroot") - String contextRoot; - - @Param(optional = true) - String name; - - @Param(optional = true, alias = "securityenabled") - Boolean securityEnabled; - - @Inject - private Target targetUtil; - - @Inject - ServiceLocator habitat; - - @Inject - ServerEnvironment serverEnv; - - @Override - public void execute(AdminCommandContext context) { - Config targetConfig = targetUtil.getConfig(target); - PayaraFangConfiguration fangConfiguration = targetConfig.getExtensionByType(PayaraFangConfiguration.class); - - try { - ConfigSupport.apply(new SingleConfigCode(){ - @Override - public Object run(PayaraFangConfiguration configProxy) throws PropertyVetoException { - if (enabled != null) { - configProxy.setEnabled(enabled.toString()); - } - - if (contextRoot != null) { - configProxy.setContextRoot(contextRoot); - } - - if (name != null) { - configProxy.setApplicationName(name); - } - - if (securityEnabled != null) { - configProxy.setSecurityEnabled(securityEnabled.toString()); - } - - return null; - } - }, fangConfiguration); - } catch (TransactionFailure ex) { - context.getActionReport().failure(LOGGER, "Failed to update Payara Fang configuration", ex); - } - } -} diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java deleted file mode 100644 index 5e772c22c01..00000000000 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/configuration/PayaraFangConfiguration.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://github.com/payara/Payara/blob/master/LICENSE.txt - * See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at glassfish/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * The Payara Foundation designates this particular file as subject to the "Classpath" - * exception as provided by the Payara Foundation in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package fish.payara.appserver.fang.service.configuration; - -import java.beans.PropertyVetoException; -import org.glassfish.api.admin.config.ConfigExtension; -import org.jvnet.hk2.config.Attribute; -import org.jvnet.hk2.config.ConfigBeanProxy; -import org.jvnet.hk2.config.Configured; - -/** - * - * @author Andrew Pielage - */ -@Configured -public interface PayaraFangConfiguration extends ConfigBeanProxy, ConfigExtension { - - /** - * Checks if Payara Fang is enabled or not - * @return true if enabled - */ - @Attribute(defaultValue = "false", dataType = Boolean.class) - String getEnabled(); - void setEnabled(String value) throws PropertyVetoException; - - @Attribute(defaultValue = "/fang") - String getContextRoot(); - void setContextRoot(String contextRoot) throws PropertyVetoException; - - @Attribute(defaultValue = "__fang") - String getApplicationName(); - void setApplicationName(String name) throws PropertyVetoException; - - @Attribute(defaultValue = "false", dataType = Boolean.class) - String getSecurityEnabled(); - void setSecurityEnabled(String value) throws PropertyVetoException; - -} diff --git a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java b/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java deleted file mode 100644 index 066e7513124..00000000000 --- a/appserver/payara-appserver-modules/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://github.com/payara/Payara/blob/master/LICENSE.txt - * See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at glassfish/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * The Payara Foundation designates this particular file as subject to the "Classpath" - * exception as provided by the Payara Foundation in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ -package fish.payara.appserver.fang.service.security; - -import com.sun.enterprise.security.SecurityServicesUtil; -import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; -import java.io.IOException; -import java.security.Principal; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.message.AuthException; -import javax.security.auth.message.AuthStatus; -import javax.security.auth.message.MessageInfo; -import javax.security.auth.message.MessagePolicy; -import javax.security.auth.message.callback.CallerPrincipalCallback; -import javax.security.auth.message.callback.PasswordValidationCallback; -import javax.security.auth.message.module.ServerAuthModule; -import javax.servlet.RequestDispatcher; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import org.glassfish.hk2.api.ServiceLocator; - -/** - * - * @author Andrew Pielage - */ -public class FangAuthModule implements ServerAuthModule { - - private String contextRoot = null; - private CallbackHandler handler = null; - private boolean securityEnabled = false; - -// private static final String SAVED_SUBJECT = "Saved_Subject"; - private static final String ORIG_REQUEST_PATH = "origRequestPath"; - private static final String LOGIN_PAGE = "/login.xhtml"; -// private static final String ERROR_PAGE = "/error.xhtml"; -// private static final String RESPONSE_TYPE = "application/json"; -// private static final String USER_NAME = "userName"; - private static final Class[] SUPPORTED_MESSAGE_TYPES = new Class[] {HttpServletRequest.class, - HttpServletResponse.class }; - - @Override - public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) - throws AuthException { - this.handler = handler; - ServiceLocator habitat = SecurityServicesUtil.getInstance().getHabitat(); - PayaraFangConfiguration fangConfiguration = habitat.getService(PayaraFangConfiguration.class); - - contextRoot = fangConfiguration.getContextRoot(); - securityEnabled = Boolean.parseBoolean(fangConfiguration.getSecurityEnabled()); - } - - @Override - public Class[] getSupportedMessageTypes() { - return SUPPORTED_MESSAGE_TYPES; - } - - @Override - public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) - throws AuthException { - if (securityEnabled) { - HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); - HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); - HttpSession session = request.getSession(); - - // Check if our session has already been authenticated - Principal userPrincipal = request.getUserPrincipal(); - if (userPrincipal != null) { - try { - handler.handle(new Callback[] { new CallerPrincipalCallback(clientSubject, userPrincipal) }); - - return AuthStatus.SUCCESS; - } catch (IOException | UnsupportedCallbackException ex) { - AuthException ae = new AuthException(); - ae.initCause(ex); - throw ae; - } - } - - // See if the username / password has been passed in... - String username = request.getParameter("j_username"); - String password = request.getParameter("j_password"); - if ((username == null) || (password == null) || !request.getMethod().equalsIgnoreCase("post")) { - // Not passed in, show the login page... - String origPath = request.getRequestURI(); - String queryString = request.getQueryString(); - - if ((queryString != null) && (!queryString.isEmpty())) { - origPath += "?" + queryString; - } - - session.setAttribute(ORIG_REQUEST_PATH, origPath); - RequestDispatcher rd = request.getRequestDispatcher(LOGIN_PAGE); - - try { - rd.forward(request, response); - } catch (Exception ex) { - AuthException authException = new AuthException(); - authException.initCause(ex); - throw authException; - } - - return AuthStatus.SEND_CONTINUE; - } - - // Authenticate the details - PasswordValidationCallback pvCallback = new PasswordValidationCallback(clientSubject, username, - password.toCharArray()); - - try { - handler.handle(new Callback[]{pvCallback}); - } catch (Exception ex) { - AuthException ae = new AuthException(); - ae.initCause(ex); - throw ae; - } - - // Register the session as authenticated - messageInfo.getMap().put("javax.servlet.http.registerSession", Boolean.TRUE.toString()); - - // Redirect to original path - try { - String origRequest = (String) session.getAttribute(ORIG_REQUEST_PATH); - - if ((origRequest == null)) { - origRequest = contextRoot; - } - - response.sendRedirect(response.encodeRedirectURL(origRequest)); - } catch (Exception ex) { - AuthException ae = new AuthException(); - ae.initCause(ex); - throw ae; - } - - // Continue... - return AuthStatus.SUCCESS; - } else { - Callback[] callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, "wibbles") }; - - try { - handler.handle(callbacks); - } catch (IOException | UnsupportedCallbackException ex) { - Logger.getLogger(FangAuthModule.class.getName()).log(Level.SEVERE, null, ex); - } - - return AuthStatus.SUCCESS; - } - } - - @Override - public AuthStatus secureResponse(MessageInfo messageInfo, Subject serviceSubject) throws AuthException { - return AuthStatus.SUCCESS; - } - - @Override - public void cleanSubject(MessageInfo messageInfo, Subject subject) throws AuthException { - if (subject != null) { - subject.getPrincipals().clear(); - } - } -} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java index 64c43f00fa7..ad612ced7e0 100644 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java @@ -95,7 +95,7 @@ public class PayaraFangService implements ConfigListener { @PostConstruct private void postConstruct() { contextRoot = payaraFangAdapter.getContextRoot(); - payaraFangConfiguration = habitat.getService(PayaraFangConfiguration.class); + payaraFangConfiguration = habitat.getService(PayaraFangConfiguration.class); if (payaraFangConfiguration.getEnabled().equals("true")) { loadApplication(); @@ -194,4 +194,4 @@ private boolean isCurrentInstanceMatchTarget(PropertyChangeEvent propertyChangeE return false; } -} +} \ No newline at end of file diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java index 6c3ad7e3854..8d80ba3ab06 100644 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java @@ -42,13 +42,20 @@ import com.sun.enterprise.config.serverbeans.Config; import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; +import fish.payara.appserver.fang.service.security.FangAuthModule; import java.beans.PropertyVetoException; import java.util.logging.Logger; import javax.inject.Inject; +import javax.security.auth.Subject; +import org.glassfish.api.ActionReport; +import org.glassfish.api.ActionReport.MessagePart; import org.glassfish.api.Param; import org.glassfish.api.admin.AdminCommand; import org.glassfish.api.admin.AdminCommandContext; +import org.glassfish.api.admin.CommandRunner; +import org.glassfish.api.admin.CommandRunner.CommandInvocation; import org.glassfish.api.admin.ExecuteOn; +import org.glassfish.api.admin.ParameterMap; import org.glassfish.api.admin.RestEndpoint; import org.glassfish.api.admin.RestEndpoints; import org.glassfish.api.admin.RuntimeType; @@ -76,7 +83,9 @@ }) public class SetPayaraFangConfigurationCommand implements AdminCommand { - private final static Logger LOGGER = Logger.getLogger(SetPayaraFangConfigurationCommand.class.getName()); + private static final String AUTH_MODULE_NAME = "FangAuthModule"; + private static final String DEFAULT_USER_NAME = "fang"; + private static final Logger LOGGER = Logger.getLogger(SetPayaraFangConfigurationCommand.class.getName()); @Param(optional = true, defaultValue = "server-config") String target; @@ -102,11 +111,30 @@ public class SetPayaraFangConfigurationCommand implements AdminCommand { @Inject ServerEnvironment serverEnv; + @Inject + CommandRunner commandRunner; + @Override public void execute(AdminCommandContext context) { Config targetConfig = targetUtil.getConfig(target); PayaraFangConfiguration fangConfiguration = targetConfig.getExtensionByType(PayaraFangConfiguration.class); + // Get the value of securityEnabled + if (securityEnabled == null) { + securityEnabled = Boolean.parseBoolean(fangConfiguration.getSecurityEnabled()); + } + + // If security is enabled and the required message security provider is not present, create it + if (securityEnabled && !messageSecurityProviderExists(context.getActionReport().addSubActionsReport(), + context.getSubject())) { + createRequiredMessageSecurityProvider(context.getActionReport().addSubActionsReport(), context.getSubject()); + } + + // Create the default user if it doesn't exist + if (!defaultFangUserExists(context.getActionReport().addSubActionsReport(), context.getSubject())) { + createDefaultFangUser(context.getActionReport().addSubActionsReport(), context.getSubject()); + } + try { ConfigSupport.apply(new SingleConfigCode(){ @Override @@ -133,5 +161,76 @@ public Object run(PayaraFangConfiguration configProxy) throws PropertyVetoExcept } catch (TransactionFailure ex) { context.getActionReport().failure(LOGGER, "Failed to update Payara Fang configuration", ex); } - } + } + + private boolean messageSecurityProviderExists(ActionReport subActionReport, Subject subject) { + boolean exists = false; + + CommandInvocation invocation = commandRunner.getCommandInvocation("list-message-security-providers", + subActionReport, subject); + + ParameterMap parameters = new ParameterMap(); + parameters.add("layer", "HttpServlet"); + + invocation.parameters(parameters).execute(); + + for (MessagePart message : subActionReport.getTopMessagePart().getChildren()) { + if (message.getMessage().equals(AUTH_MODULE_NAME)) { + exists = true; + break; + } + } + + return exists; + } + + private void createRequiredMessageSecurityProvider(ActionReport subActionReport, Subject subject) { + CommandInvocation invocation = commandRunner.getCommandInvocation("create-message-security-provider", + subActionReport, subject); + + ParameterMap parameters = new ParameterMap(); + parameters.add("classname", FangAuthModule.class.getName()); + parameters.add("isdefaultprovider", "false"); + parameters.add("layer", "HttpServlet"); + parameters.add("providertype", "server"); + parameters.add("target", target); + parameters.add("requestauthsource", "sender"); + parameters.add("DEFAULT", AUTH_MODULE_NAME); + + + invocation.parameters(parameters).execute(); + } + + private boolean defaultFangUserExists(ActionReport subActionReport, Subject subject) { + boolean exists = false; + + CommandInvocation invocation = commandRunner.getCommandInvocation("list-file-users", subActionReport, subject); + + ParameterMap parameters = new ParameterMap(); + parameters.add("authrealmname", "file"); + + invocation.parameters(parameters).execute(); + + for (MessagePart message : subActionReport.getTopMessagePart().getChildren()) { + if (message.getMessage().equals(DEFAULT_USER_NAME)) { + exists = true; + break; + } + } + + return exists; + } + + private void createDefaultFangUser(ActionReport subActionReport, Subject subject) { + CommandInvocation invocation = commandRunner.getCommandInvocation("create-file-user", subActionReport, subject); + + ParameterMap parameters = new ParameterMap(); + parameters.add("groups", "fang"); + parameters.add("userpassword", "fang"); + parameters.add("target", target); + parameters.add("authrealmname", "file"); + parameters.add("DEFAULT", DEFAULT_USER_NAME); + + invocation.parameters(parameters).execute(); + } } From ddfe0ee03bf17e7b5391bae36134623553f9ff8e Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Wed, 24 May 2017 16:12:11 +0100 Subject: [PATCH 18/22] Remove unnecessary dependencies and fix version --- appserver/packager/payara-fang/pom.xml | 2 +- .../payara-fang/payara-fang-service/pom.xml | 20 +------------------ .../payara-fang/pom.xml | 2 +- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/appserver/packager/payara-fang/pom.xml b/appserver/packager/payara-fang/pom.xml index b08ed2ed76f..c19edf1a016 100644 --- a/appserver/packager/payara-fang/pom.xml +++ b/appserver/packager/payara-fang/pom.xml @@ -44,7 +44,7 @@ org.glassfish.main.packager packages - 4.1.2.172-SNAPSHOT + 4.1.2.173-SNAPSHOT payara-fang Payara Fang Package diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/pom.xml b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/pom.xml index 834fb2193f3..2d19a2aa637 100644 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/pom.xml +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/pom.xml @@ -43,7 +43,7 @@ fish.payara.appserver.payara-fang payara-fang-parent - 4.1.2.172-SNAPSHOT + 4.1.2.173-SNAPSHOT fish.payara.appserver.payara-fang payara-fang-service @@ -72,23 +72,5 @@ 7.0 provided
- - org.glassfish.main.security - security - ${project.version} - provided - - - org.glassfish.main.admin - rest-client - ${project.version} - provided - - - fish.payara.admingui - console-common - ${project.version} - provided -
diff --git a/appserver/payara-appserver-modules/payara-fang/pom.xml b/appserver/payara-appserver-modules/payara-fang/pom.xml index b3cee2cd697..03204cb966c 100644 --- a/appserver/payara-appserver-modules/payara-fang/pom.xml +++ b/appserver/payara-appserver-modules/payara-fang/pom.xml @@ -43,7 +43,7 @@ org.glassfish.main payara-appserver-modules - 4.1.2.172-SNAPSHOT + 4.1.2.173-SNAPSHOT fish.payara.appserver.payara-fang payara-fang-parent From bbac192b77749cc1e96695f1ad2b32acc599b733 Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Thu, 25 May 2017 14:16:23 +0100 Subject: [PATCH 19/22] Finish up --- .../fang/service/PayaraFangLoader.java | 23 +----- .../fang/service/PayaraFangService.java | 2 +- .../service/adapter/PayaraFangAdapter.java | 75 ------------------ .../adapter/PayaraFangAdapterState.java | 76 ------------------- .../SetPayaraFangConfigurationCommand.java | 45 +++++++---- .../fang/service/security/FangAuthModule.java | 7 +- .../payara/monitoring/fang/FangConfig.java | 6 +- .../src/main/webapp/j_security_check | 40 ---------- .../src/main/webapp/login.xhtml | 2 +- 9 files changed, 41 insertions(+), 235 deletions(-) delete mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java delete mode 100644 appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/j_security_check diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java index 4d4ffd232ee..71fbe88fa53 100644 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangLoader.java @@ -49,7 +49,6 @@ import com.sun.enterprise.config.serverbeans.SystemApplications; import com.sun.enterprise.v3.server.ApplicationLoaderService; import fish.payara.appserver.fang.service.adapter.PayaraFangAdapter; -import fish.payara.appserver.fang.service.adapter.PayaraFangAdapterState; import java.beans.PropertyVetoException; import java.util.Arrays; import java.util.List; @@ -141,7 +140,6 @@ public void run() { loadApplication(); } catch (Exception ex) { - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); LOGGER.log(Level.WARNING, "Problem while attempting to register or load Payara Fang!", ex); } } @@ -151,8 +149,6 @@ public void run() { * @throws Exception */ private void createAndRegisterApplication() throws Exception { - // Update the adapter state - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.REGISTERING); LOGGER.log(Level.FINE, "Registering the Payara Fang Application..."); // Create the system application entry and application-ref in the config @@ -210,14 +206,10 @@ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, Tran Server server = domain.getServerNamed(serverEnv.getInstanceName()); ConfigSupport.apply(code, domain.getSystemApplications(), server); - // Update the adapter state - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); LOGGER.log(Level.FINE, "Payara Fang Registered."); } private void registerApplication() throws Exception { - // Update the adapter state - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.REGISTERING); LOGGER.log(Level.FINE, "Registering the Payara Fang Application..."); // Create the application-ref entry in the domain.xml @@ -254,7 +246,6 @@ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, Tran ConfigSupport.apply(code, domain.getSystemApplications(), server); // Update the adapter state - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); LOGGER.log(Level.FINE, "Payara Fang Registered."); } @@ -278,7 +269,7 @@ private void loadApplication() { ApplicationRegistry appRegistry = habitat.getService(ApplicationRegistry.class); ApplicationInfo appInfo = appRegistry.get(applicationName); if (appInfo != null && appInfo.isLoaded()) { - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADED); + LOGGER.log(Level.FINE, "Payara Fang already loaded."); return; } @@ -293,18 +284,16 @@ private void loadApplication() { if (config == null) { throw new IllegalStateException("Payara Fang has no system app entry!"); } - - // Update adapter state - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADING); // Load the Payara Fang Application String instanceName = serverEnv.getInstanceName(); ApplicationRef ref = domain.getApplicationRefInServer(instanceName, applicationName); habitat.getService(ApplicationLoaderService.class).processApplication(config, ref); - // Update adapter state and mark as registered - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.LOADED); + // Mark as registered payaraFangAdapter.setAppRegistered(true); + + LOGGER.log(Level.FINE, "Payara Fang Loaded."); } private void checkAndResolveApplicationName(SystemApplications systemApplications) { @@ -348,8 +337,6 @@ private boolean isApplicationNameValid(SystemApplications systemApplications) { private void reconfigureSystemApplication() throws Exception { Application systemApplication = payaraFangAdapter.getSystemApplicationConfig(); - // Update the adapter state - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.RECONFIGURING); LOGGER.log(Level.FINE, "Reconfiguring the Payara Fang Application..."); // Reconfigure the system-application entry in the domain.xml @@ -365,8 +352,6 @@ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, Tran ConfigSupport.apply(code, systemApplication); - // Update the adapter state - payaraFangAdapter.setStateMsg(PayaraFangAdapterState.NOT_LOADED); LOGGER.log(Level.FINE, "Payara Fang Reconfigured."); } } diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java index ad612ced7e0..262bc4c5ba1 100644 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/PayaraFangService.java @@ -149,7 +149,7 @@ public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvent payaraFangConfiguration); contextRoot = endpointDecider.getContextRoot(); } - } else if (!propertyChangeEvent.getPropertyName().equals("securityEnabled")) { + } else if (!propertyChangeEvent.getPropertyName().equals("security-enabled")) { // If a startup has been attempted and the changed property isn't securityEnabled, throw an // unprocessed change event as we need to restart unprocessedChanges.add(new UnprocessedChangeEvent(propertyChangeEvent, diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java index ea31cba8708..9248981847e 100644 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapter.java @@ -40,7 +40,6 @@ package fish.payara.appserver.fang.service.adapter; -import com.sun.appserv.server.util.Version; import com.sun.enterprise.config.serverbeans.Application; import com.sun.enterprise.config.serverbeans.Config; import com.sun.enterprise.config.serverbeans.Domain; @@ -51,10 +50,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; -import java.util.Arrays; import java.util.List; import java.util.Locale; -import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -67,7 +64,6 @@ import org.glassfish.api.container.Adapter; import org.glassfish.api.event.Events; import org.glassfish.grizzly.http.Method; -import org.glassfish.grizzly.http.io.OutputBuffer; import org.glassfish.grizzly.http.server.HttpHandler; import org.glassfish.grizzly.http.server.Request; import org.glassfish.grizzly.http.server.Response; @@ -83,7 +79,6 @@ */ @Service public final class PayaraFangAdapter extends HttpHandler implements Adapter { - private PayaraFangAdapterState stateMsg = PayaraFangAdapterState.UNINITIALISED; private boolean isRegistered = false; private boolean appRegistered = false; private ResourceBundle bundle; @@ -134,10 +129,7 @@ private void init() { // If the app exists in the domain.xml AND it's registered to this instance if (appExistsInConfig() && (domain.getSystemApplicationReferencedFrom(env.getInstanceName(), fangServiceConfiguration.getApplicationName()) != null)) { - setStateMsg(PayaraFangAdapterState.NOT_LOADED); setAppRegistered(true); - } else { - setStateMsg(PayaraFangAdapterState.NOT_REGISTERED); } } @@ -199,15 +191,6 @@ private Application getApplicationWithMatchingContextRoot(String contextRoot) { return application; } - public PayaraFangAdapterState getStateMsg() { - return stateMsg; - } - - public void setStateMsg(PayaraFangAdapterState msg) { - stateMsg = msg; - logger.log(Level.FINE, msg.toString()); - } - @Override public void service(Request request, Response response) throws Exception { bundle = getResourceBundle(request.getLocale()); @@ -230,8 +213,6 @@ public void service(Request request, Response response) throws Exception { return; } - logRequest(request); - if (isResourceRequest(request)) { try { handleResourceRequest(request, response); @@ -250,43 +231,6 @@ public void service(Request request, Response response) throws Exception { } response.setContentType("text/html; charset=UTF-8"); - - String serverVersion = Version.getFullVersion(); - - if ("/testifbackendisready.html".equals(request.getRequestURI())) { - // Replace state token - String status = getStateMsg().getI18NKey(); - try { - // Try to get a localized version of this key - status = bundle.getString(status); - } catch (MissingResourceException ex) { - // Use the non-localized String version of the status - status = getStateMsg().toString(); - } - - String wkey = PayaraFangAdapterState.WELCOME_TO.getI18NKey(); - - try { - // Try to get a localized version of this key - serverVersion = bundle.getString(wkey) + " " + serverVersion + "."; - } catch (MissingResourceException ex) { - // Use the non-localized String version of the status - serverVersion = PayaraFangAdapterState.WELCOME_TO.toString() + " " + serverVersion + "."; - } - - status += "\n" + serverVersion; - - try { - OutputBuffer ob = getOutputBuffer(response); - byte[] bytes = (":::" + status).getBytes("UTF-8"); - response.setContentLength(bytes.length); - ob.write(bytes, 0, bytes.length); - ob.flush(); - } catch (IOException ex) { - logger.log(Level.SEVERE, "Unable to serve resource: {0}. Cause: {1}", ex); - } - } - // TODO: Handle application not being there } private ResourceBundle getResourceBundle(Locale locale) { @@ -310,18 +254,6 @@ private String getAllowedHttpMethodsAsString() { return sb.toString(); } - - private void logRequest(Request request) { - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, "PayaraFangAdapter's STATE IS: {0}", getStateMsg()); - logger.log(Level.FINE, "Current Thread: {0}", Thread.currentThread().getName()); - - for (final String name : request.getParameterNames()) { - final String values = Arrays.toString(request.getParameterValues(name)); - logger.log(Level.FINE, "Parameter name: {0} values: {1}", new Object[]{name, values}); - } - } - } private boolean isResourceRequest(Request request) { return (getContentType(request.getRequestURI()) != null); @@ -376,13 +308,6 @@ private void handleResourceRequest(Request request, Response response) throws IO } } - private OutputBuffer getOutputBuffer(Response response) { - response.setStatus(202); - response.setContentType("text/html"); - response.setCharacterEncoding("UTF-8"); - return response.getOutputBuffer(); - } - @Override public HttpHandler getHttpService() { return this; diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java deleted file mode 100644 index eb5660ae5d8..00000000000 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/adapter/PayaraFangAdapterState.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) [2016-2017] Payara Foundation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://github.com/payara/Payara/blob/master/LICENSE.txt - * See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at glassfish/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * The Payara Foundation designates this particular file as subject to the "Classpath" - * exception as provided by the Payara Foundation in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package fish.payara.appserver.fang.service.adapter; - -/** - * - * @author Andrew Pielage - */ -public enum PayaraFangAdapterState { - NOT_LOADED("state.notLoaded", "Payara Fang is registered in the config but not loaded yet"), - LOADING("state.loading", "Payara Fang is loading"), - LOADED("state.loaded", "Payara Fang is loaded"), - UNINITIALISED("state.uninitialised", "Payara Fang has not been initialised yet"), - REGISTERING("state.registering", "Payara Fang is being registered as a system application"), - NOT_REGISTERED("state.notRegistered", "Payara Fang is not registered in the config"), - RECONFIGURING("state.reconfiguring", "Payara Fang system-application entry is being reconfigured"), - WELCOME_TO("status.welcometo", "Welcome to "); - - private final String desc; - private final String i18nKey; - - private PayaraFangAdapterState(String i18nKey, String desc) { - this.i18nKey = i18nKey; - this.desc = desc; - } - - /** - * This is the key that should be used to retrieve the localised message from a properties file. - */ - public String getI18NKey() { - return i18nKey; - } - - @Override - public String toString() { - return (desc); - } -} diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java index 8d80ba3ab06..7bcb0e3c0d1 100644 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/admin/SetPayaraFangConfigurationCommand.java @@ -41,6 +41,8 @@ package fish.payara.appserver.fang.service.admin; import com.sun.enterprise.config.serverbeans.Config; +import com.sun.enterprise.config.serverbeans.Domain; +import com.sun.enterprise.config.serverbeans.SecureAdmin; import fish.payara.appserver.fang.service.configuration.PayaraFangConfiguration; import fish.payara.appserver.fang.service.security.FangAuthModule; import java.beans.PropertyVetoException; @@ -114,27 +116,28 @@ public class SetPayaraFangConfigurationCommand implements AdminCommand { @Inject CommandRunner commandRunner; + @Inject + Domain domain; + @Override public void execute(AdminCommandContext context) { Config targetConfig = targetUtil.getConfig(target); PayaraFangConfiguration fangConfiguration = targetConfig.getExtensionByType(PayaraFangConfiguration.class); - // Get the value of securityEnabled - if (securityEnabled == null) { - securityEnabled = Boolean.parseBoolean(fangConfiguration.getSecurityEnabled()); - } + ActionReport actionReport = context.getActionReport(); + Subject subject = context.getSubject(); - // If security is enabled and the required message security provider is not present, create it - if (securityEnabled && !messageSecurityProviderExists(context.getActionReport().addSubActionsReport(), + // If the required message security provider is not present, create it + if (!messageSecurityProviderExists(actionReport.addSubActionsReport(), context.getSubject())) { - createRequiredMessageSecurityProvider(context.getActionReport().addSubActionsReport(), context.getSubject()); + createRequiredMessageSecurityProvider(actionReport.addSubActionsReport(), subject); } // Create the default user if it doesn't exist - if (!defaultFangUserExists(context.getActionReport().addSubActionsReport(), context.getSubject())) { - createDefaultFangUser(context.getActionReport().addSubActionsReport(), context.getSubject()); + if (!defaultFangUserExists(actionReport.addSubActionsReport(), subject)) { + createDefaultFangUser(actionReport.addSubActionsReport(), subject); } - + try { ConfigSupport.apply(new SingleConfigCode(){ @Override @@ -161,13 +164,25 @@ public Object run(PayaraFangConfiguration configProxy) throws PropertyVetoExcept } catch (TransactionFailure ex) { context.getActionReport().failure(LOGGER, "Failed to update Payara Fang configuration", ex); } + + // If security is enabled but secure admin isn't, prompt a warning + if (Boolean.parseBoolean(fangConfiguration.getSecurityEnabled()) + && !SecureAdmin.Util.isEnabled(domain.getSecureAdmin())) { + actionReport.appendMessage("\n---WARNING---\nSecure Admin is not enabled! - it is highly " + + "recommended that you do so to properly secure Payara Fang.\n"); + } + + // If everything has passed, scrap the subaction reports as we don't want to print them out + if (!actionReport.hasFailures() || !actionReport.hasWarnings()) { + actionReport.getSubActionsReport().clear(); + } } private boolean messageSecurityProviderExists(ActionReport subActionReport, Subject subject) { boolean exists = false; CommandInvocation invocation = commandRunner.getCommandInvocation("list-message-security-providers", - subActionReport, subject); + subActionReport, subject, false); ParameterMap parameters = new ParameterMap(); parameters.add("layer", "HttpServlet"); @@ -186,7 +201,7 @@ private boolean messageSecurityProviderExists(ActionReport subActionReport, Subj private void createRequiredMessageSecurityProvider(ActionReport subActionReport, Subject subject) { CommandInvocation invocation = commandRunner.getCommandInvocation("create-message-security-provider", - subActionReport, subject); + subActionReport, subject, false); ParameterMap parameters = new ParameterMap(); parameters.add("classname", FangAuthModule.class.getName()); @@ -204,7 +219,8 @@ private void createRequiredMessageSecurityProvider(ActionReport subActionReport, private boolean defaultFangUserExists(ActionReport subActionReport, Subject subject) { boolean exists = false; - CommandInvocation invocation = commandRunner.getCommandInvocation("list-file-users", subActionReport, subject); + CommandInvocation invocation = commandRunner.getCommandInvocation("list-file-users", subActionReport, subject, + false); ParameterMap parameters = new ParameterMap(); parameters.add("authrealmname", "file"); @@ -222,7 +238,8 @@ private boolean defaultFangUserExists(ActionReport subActionReport, Subject subj } private void createDefaultFangUser(ActionReport subActionReport, Subject subject) { - CommandInvocation invocation = commandRunner.getCommandInvocation("create-file-user", subActionReport, subject); + CommandInvocation invocation = commandRunner.getCommandInvocation("create-file-user", subActionReport, subject, + false); ParameterMap parameters = new ParameterMap(); parameters.add("groups", "fang"); diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java index 066e7513124..6d0868eb644 100644 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-service/src/main/java/fish/payara/appserver/fang/service/security/FangAuthModule.java @@ -73,12 +73,9 @@ public class FangAuthModule implements ServerAuthModule { private CallbackHandler handler = null; private boolean securityEnabled = false; -// private static final String SAVED_SUBJECT = "Saved_Subject"; + private static final String DEFAULT_USER_NAME = "fang"; private static final String ORIG_REQUEST_PATH = "origRequestPath"; private static final String LOGIN_PAGE = "/login.xhtml"; -// private static final String ERROR_PAGE = "/error.xhtml"; -// private static final String RESPONSE_TYPE = "application/json"; -// private static final String USER_NAME = "userName"; private static final Class[] SUPPORTED_MESSAGE_TYPES = new Class[] {HttpServletRequest.class, HttpServletResponse.class }; @@ -179,7 +176,7 @@ public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject // Continue... return AuthStatus.SUCCESS; } else { - Callback[] callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, "wibbles") }; + Callback[] callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, DEFAULT_USER_NAME) }; try { handler.handle(callbacks); diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangConfig.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangConfig.java index 34201442917..3d37a4749ef 100644 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangConfig.java +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangConfig.java @@ -60,9 +60,7 @@ public Set> getClasses() { } private void addRestResourceClasses(Set> resources) { - resources.add(fish.payara.monitoring.fang.resource - .FangStateResource.class); - resources.add(fish.payara.monitoring.fang.resource - .MBeanReadResource.class); + resources.add(fish.payara.monitoring.fang.resource.FangStateResource.class); + resources.add(fish.payara.monitoring.fang.resource.MBeanReadResource.class); } } diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/j_security_check b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/j_security_check deleted file mode 100644 index 4c52f35d7f8..00000000000 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/j_security_check +++ /dev/null @@ -1,40 +0,0 @@ - - diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/login.xhtml b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/login.xhtml index e9636179394..9f5571a7011 100644 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/login.xhtml +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/login.xhtml @@ -46,7 +46,7 @@

Hello, please log in:

-
+

Please type your user name:

Please type your password: From 0f301a809026fa7e40924c8c548742af1a1a2d8d Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Tue, 30 May 2017 10:58:34 +0100 Subject: [PATCH 20/22] Login page edits --- .../payara-fang-war/src/main/webapp/login.xhtml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/login.xhtml b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/login.xhtml index 9f5571a7011..24afbb261dd 100644 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/login.xhtml +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/webapp/login.xhtml @@ -42,19 +42,16 @@ - Login Form + Payara Fang Login -

Hello, please log in:

-

Please type your user name: +

Username:

-

Please type your password: +

Password:

-

- -

-
-
+

+ + From aa550ffa8c532ea5c56ef1eb7e36728173754db3 Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Wed, 7 Jun 2017 09:48:46 +0100 Subject: [PATCH 21/22] Fix version numbers --- .../payara-fang/payara-fang-war/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/pom.xml b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/pom.xml index 63f280d8f7f..6fdb8beddd7 100644 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/pom.xml +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/pom.xml @@ -43,13 +43,13 @@ fish.payara.appserver.payara-fang payara-fang-parent - 4.1.2.172-SNAPSHOT + 4.1.2.173-SNAPSHOT payara-fang-war war Payara Fang War - 0.0.1-ALPHA + 1.0.0-Beta ${project.build.directory}/endorsed From 6f236136b0f3bfbe4064a4096be23a682dc23a79 Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Wed, 28 Jun 2017 16:53:53 +0100 Subject: [PATCH 22/22] PAYARA-812 Update missed version numbers --- .../src/main/java/fish/payara/monitoring/fang/FangState.java | 2 +- appserver/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangState.java b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangState.java index 8dcb646382a..2f9aa22218d 100644 --- a/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangState.java +++ b/appserver/payara-appserver-modules/payara-fang/payara-fang-war/src/main/java/fish/payara/monitoring/fang/FangState.java @@ -53,7 +53,7 @@ public final class FangState { // Values private static final String AGENT_NAME = "Fang"; - private static final String AGENT_VERSION = "0.0.1-Alpha"; + private static final String AGENT_VERSION = "1.0.0-Beta"; private static final String AGENT_TYPE = "war"; public static String getAgentNameKey() { diff --git a/appserver/pom.xml b/appserver/pom.xml index 3b6ba0dc5bb..058b42955e5 100644 --- a/appserver/pom.xml +++ b/appserver/pom.xml @@ -149,7 +149,7 @@ 1.1.1 3.3.0.Final 19.0 - 0.0.1-ALPHA + 1.0.0-Beta